I am trying to create a JScrollPane that contains a JPanel that will be increasing and decreasing in height. When it becomes larger than the size of the JScrollPane, it should create a vertical scroll bar which will allow me to scroll through the entire JPanel. However, I am having difficulty achieving this. Yes, I know I am not using LayoutManagers. No, I will not be using them, and I need a solution that does not involve their usage.
Here are the two button's AbstractActions that add and subtract from the JPanel:
class AddACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.setSize(420,info.getHeight() + 40);
info.add(new SubPanel); // Adds another JPanel into the main JPanel (for content input)
gui.repaint();
infoS.validate();
}
}
class RemoveACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.remove(subPanel()); // This would remove the last JPanel added to the main JPanel
info.setSize(420,info.getHeight() - 40);
gui.repaint();
infoS.validate();
}
And here is the code for the main JPanel and the JScrollPane:
final JPanel info = new JPanel();
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)
This is the second project I've been trying to learn GUI by doing. I am a complete novice in Swing and am only intermediate in Java. Sorry if I am making a blindingly obvious mistake.
1) Use LayoutManagers (+1 to #kleopatra and #GagandeepBali comments)
The absence of LayoutManagers only guarantees your GUI's will look very trashy (especially when run on other OSes/builds) and being a Novice you should rather learn the correct way than learn the wrong way and get into bad habits like calling setSize() etc.
Have a read on these links to get you started:
A Visual Guide to Layout Managers
Concurrency in Swing
2) See this example for how to use a JScrollPane, it simply adds a JPanel with buttons to a JScrollPane which in-turn is added to the JFrame.
3) Also see this example for how to make the JScrollPane vertically scroll-able only.
4) For more on JScrollPanes have a look here: How to Use Scroll Panes.
5) As for how it interacts with LayoutManager, if you do not explicitly set its size via setPreferredSize(Dimension d) the scroll pane computes it based on the preferred size of its nine components (the viewport, and, if present, the two scroll bars, the row and column headers, and the four corners)
6) On your usage of validate():
validate() is used when new JComponents are added to a visible component
revalidate() is used when JComponent is removed/added from a visible component
revalidate() covers validate() too
Thus always use this:
//add or remove component(s)
revalidate();
repaint();
References:
http://www.daniweb.com/software-development/java/threads/405568/validate-vs-revalidate
LayoutManager is not required to solve the problem. The problem in Thrfoot's example is in these lines:
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
The program appears to recognize there is a need for scroll bars (it would show the scroll bar if your setting was VERTICAL_SCROLLBAR_AS_NEEDED), but the actual scrolling does not work (the scroll bar slider is not there).
To fix this, first set the preferred size of info, then construct the infoS.
Example:
info.setPreferredSize(420,600);
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
The idea is to set the preferred size of the info panel before it is used for the scroll pane. This is the same reason to set the size and location of infoS before adding to the gui:
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)
Related
ive got a JPane within a JScrolledPane. When i add content to JPane , JScrollPane doesnt show scrollbar. I tried repaint() and revalidate() but it didnt help.
static void ladowaniePaneli()
{
int b;
for(b=0;b<o;b++)
{
bgPanel[b] = new JBackgroundPanel();
nowyPanel[b] = new JPanel();
((FlowLayout)bgPanel[b].getLayout()).setVgap(0);
nowyPanel[b].setPreferredSize(new Dimension(790,518));
nowyPanel[b].setOpaque(false);
vertical[b] = new JScrollPane(nowyPanel[b]);
vertical[b].setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
vertical[b].setPreferredSize(new Dimension(789,517));
vertical[b].setOpaque(false);
vertical[b].getViewport().setOpaque(false);
bgPanel[b].add(vertical[b]);
}
}
It makes sense that scrollbars are never seen since you restrict the size of the contained component so that it's always trivially larger than the scrollopane's viewport:
nowyPanel[b].setPreferredSize(new Dimension(790,518));
Solution: don't do that.
if i dont use setPreferredSize method components wont warp to another line
You can try the Wrap Layout.
pairs should be warped to new line if they exceed JScrollPane width
Components are layed out individually. I you want a group of components to wrap then you would need to add the components to a separate panel first. Then add the panel to the panel using the WrapLayout.
I am attempting to create panel, PluginListPanel (extending JPanel), which will show a list of plugin panels which will respect the preferred height of the plugin's panel, but will force the width. I have a solution, but it is slow and has a weird bug. In the screenshot, there are two such panels, one to the left and one to the right:
I don't know different layout manager systems very well, but I know that the TOP field in the BorderLayout does what I want. So, I came up with this 'recursive' solution:
public PluginListPanel(List<PanelContainer> items) {
JPanel body = this;
for (PanelContainer item : items) {
body.setLayout(new BorderLayout(0, 0));
JPanel panel = new PluginOnePanel(item);
body.add(panel, BorderLayout.NORTH);
JPanel newBody = new JPanel();
body.add(newBody, BorderLayout.CENTER);
body = newBody;
}
}
The problem I encounter is when I scroll, the system responds somewhat slowly, and the colour of the SamplePluginPanels is different (see picture below), even if the number of SamplePluginPanels is as low as 8.
The question is, how can I make this more elegant, not slow down the program and not miscolour the panels?
Any insights are highly appreciated.
I think a vertical Box is the answer (actually 2, on both columns):
Box leftBox = Box.createVerticalBox();
Box rightBox = Box.createVerticalBox();
/* put them together */
setLayout(new GridLayout(2,1));
add(leftBox);
add(rightBox);
Also make sure, that the content of the scroll pane implements Scrollable and returns true, to scrollableTracksViewportWidth(). This will force equal widths.
Long time lurker, second time poster (it's got that desperate)
I have a frame that needs to display twelve components next to each other (as if each component is its own column). The first component is a list of attribute names, the second component shows the default attribute, and the next ten are all pulled in from a database. I would like for my Scroll Bar to effectively "freeze" the first two components (i.e. it always shows the first two components) and the scroll bar allows you to look through the rest of the entries. This is similar to Excel where we freeze columns, a la here.
I've looked into using tables, but the problem is that my components are not just text. They've got images and the like too.
Here's some of the code I'm using
JPanel info = new JPanel(); // this is the main component (holds the other 12)
info.setLayout(new GridBagLayout()); // GridBag Layoout
info.add(attNames); // add in the attribute names component
info.add(currentCase); // add in the default values
JPanel rets = new JPanel(); // add in the ten retrieved cases
rets.setLayout(new GridLayout(1,10));
for (int i=0;i<maxCases;i++)
{
rets.add(retCase[i]);
}
info.add(rets); // add the return cases to the info component
JScrollPane scrollBar2=new JScrollPane(rets,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); // surround the return cases with a scroll bar
info.add(scrollBar2); // add the scrollbar
//add the info comp to the content pane along with other necessary components
this.getContentPane().add(casesPanel, BorderLayout.NORTH);
this.getContentPane().add(info, BorderLayout.CENTER);
this.getContentPane().add(buttons, BorderLayout.SOUTH);
//finally, add the overall scrollbars and set the size
this.pack();
JScrollPane scrollBar=new JScrollPane(info,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.setSize(this.getWidth(), 750);
this.setResizable(true);
this.add(scrollBar);
The problem is that the scroll bar for the returned case doesn't think it's needed and I have to use the big scroll bar, meaning I can move away from the first two components.
Any help would be greatly appreciated!!
Here's the problem
Cheers,
K
Place the frozen section into the scroll panes row header. Check how to use scroll panes for more info and examples
I want to add a Jpanel on a jscrollpane; also I want to have only vertical scrolling. I want to set layout of my jPanel "flowLaout" and add several components to my jPanel in my code by jpanel.add(component) method. The result is that all components are placed in just one row that excide width of jpanel and are not shown. I have used this tricks and both failed:
jScrollPane1.setHorizontalScrollBar(null);
jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
Wrap Layout should work for you.
I am unsure of the particulars for your current project, but i would recommend MigLayout. It has never served me wrong.
I am currently writing a touchscreen interface with nested MigLayout panels up to 4 or five layers deep, and have not had a single problem.
Please use the below policy to turn on vertical scrolling and turn off horizontal scrolling(Works with Java SE 7):
Panel graphicPanel = new Panel();
JScrollPane scrollbar = new JScrollPane(graphicPanel);
scrollbar.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollbar.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollbar.setPreferredSize(new Dimension(1300, 600));
scrollbar.setVisible(true);
add(scrollbar, BorderLayout.CENTER);
I have two AWT components in a Frame, Panel A and Panel B. I would like panel A to be sized to the height width of the frame (and maintain that size on frame resize), but I would like panel B to overlap A. B will be at a fixed position (0,0 to make it easier) with a fixed height and width. I'm not sure what kind of layout manager I would need to make this work. If I use a null layout, I think I would have to manage the resizing of panel A myself, but it would make the sizing of panel B relatively easy. Any thoughts on how to accomplish this?
thanks,
Jeff
Take a look at JLayeredPanes. Here is a tutorial.
edit:
If panelA is an AWT component, you will be hard pressed to get panelB to overlap. From Sun's article entitled Mixing Heavy and Light Components:
Do not mix lightweight (Swing) and heavyweight (AWT) components within a container where the lightweight component is expected to overlap the heavyweight one.
However, if you are looking to have panelA fill the Frame completely, why not add panelB as a component of panelA?
Edit2:
If you can make panelB a heavyweight component, then you can use the JLayeredPane.
Here is a quick mockup that shows how:
public static void main(String[] args){
new GUITest();
}
public GUITest() {
frame = new JFrame("test");
frame.setSize(300,300);
addStuffToFrame();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
frame.setVisible(true);
}
});
}
private void addStuffToFrame() {
Panel awtPanel = new Panel();
awtPanel.setBackground(Color.blue);
//here you can fool around with the pane:
//first, you can see how the layered pane works by switching the
//DEFUALT_LAYER and PALLETTE_LAYER back and forth between the two panels
//and re-compiling to see the results
awtPanel.setSize(200,300);
frame.getLayeredPane().add(awtPanel, JLayeredPane.DEFAULT_LAYER);
//next you comment out the above two lines and
//uncomment the following line. this will give you the desired effect of
//awtPanel filling in the entire frame, even on a resize.
//frame.add(awtPanel);
Panel awtPanel2 = new Panel();
awtPanel2.setBackground(Color.red);
awtPanel2.setSize(300,200);
frame.getLayeredPane().add(awtPanel2,JLayeredPane.PALETTE_LAYER);
}
Your best bet is to have your own LayoutManager. The easiest way is probably to extend or proxy BorderLayout, and have a specific case to layout panel B.
Maybe I'm missing something. If B is fixed size and is at (0,0) and A runs the full width what's the use of having B overlap A? You will never see anything that is placed under B.
I can't think of any of the default layout managers, but Orielly has this one you can use:
relative layout manager (see source code link) with documentation. I haven't used it in a long while, but it should beat managing the layout yourself.