This is probably a very basic question, but I could't find anything about it online.
I'm working in Java swing and have a JPanel with a null Layout Manager (ie using absolute positioning). The JPanel is filling a space in the JFrame so that its size will change when the JFrame is resized. Within this JPanel, I have a number of other components that I have placed using Component.setBounds(). I would like one of these components to be set relative to the bottom of the JPanel, so that when the containing JPanel resizes, the smaller JComponent stays stuck to the bottom of the container.
I have tried to do this by overriding the getLocation() or getBounds() methods to reference the container height, but neither of these seemed to work the way overriding getPreferredSize() would, even after calling revalidate() and repaint(). Unfortunately, using another layout manager like BorderLayout is not an option here.
Is there a way to do something like this? Am I missing something obvious? If not, is there a way to listen for changes in the container's height and re-call .setBounds()?
Try listening to the resize event of the panel:
panel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
component.setBounds(...);
}
});
You can reference panel.getBounds from withing this method and set your components bounds accordingly.
To do this you can add a component listener to your JFrame.
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
//Do stuff here
}
});
Inside the component listener you can change the sizes and locations of anything you would like to. To stick them to the bottom simply get the size of the JFrame and subtract a specific amount and set that as the y location for what you want stuck to the bottom.
Related
Coded this in netbeans so I did not write all the code for the creation of the rest of the GUI myself.
btn_Next is the button that is already on the panel
private void place_Button() {
btn_Next.setLocation((btn_Next.getX()+30), btn_Next.getY());
btn_Next.revalidate();
btn_Next.repaint();
JButton btn_Back = new JButton("Back");
pnl_Buttons.add(btn_Back);
btn_Back.setPreferredSize(btn_Next.getPreferredSize());
btn_Back.setLocation((btn_Next.getX()- 100), btn_Next.getY());
btn_Back.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
switch_Works_Back();
}
});
btn_Back.setVisible(true);
pnl_Buttons.revalidate();
pnl_Buttons.repaint();
}
What layout manager does pnl_Buttons use? If you don't know, you could easily have Java print it out:
System.out.println(pnl_Buttons.getLayout());
Note that some layout managers allow adding components much better than others, and for your question, the layout is key.
A guess here, but it looks like your pnl_Buttons uses a null layout, and if so, your JButton may not be showing because its size is 0 x 0 since you never set its size; this is because null layouts require that the added components specify completely their own size and location. You specify the location and the preferred size of the button but not its size. If so, a quick solution is to set the JButton's size via setSize(...), but much better is to not use null layouts, and instead use one of the more user friendly layout managers.
As an aside, you shouldn't call revalidate() and repaint() on the component being added and don't need to call setVisible(true) on your JBUtton unless you've called setVisible(false) on it previously. Instead you only need to call revalidate() and repaint() on the container that you're adding your component to, here your pnl_Buttons object.
I am having a hard time to properly set the way my swing components behave on resize.
I have two problems with that interface:
A: The toggle button at the beginning of each row is here to collapse/expand the text. All the elements are contained in a JLayeredPane. On the button click, I edit the pane's height to expand or collapse the content (either 31 or 310). Expand works fine an pushes the elements below. On the other hand, collapse does hide the text but leaves all the elements in position. Here is my code:
private void expandText(java.awt.event.ActionEvent evt) {
JToggleButton button = (JToggleButton) evt.getSource();
Container parent = button.getParent();
Dimension size = parent.getSize();
String icon;
if (button.isSelected()) {
size.height = 310;
icon = "/org/cytoscape/ocsana/resources/images/minus.png";
} else {
size.height = 31;
icon = "/org/cytoscape/ocsana/resources/images/plus.png";
}
parent.setSize(size);
try {
button.setIcon(new ImageIcon(ImageIO.read(getClass().getResource(icon)).getScaledInstance(-1, 15, Image.SCALE_SMOOTH)));
} catch (IOException ex) {
}
backgroundPane.revalidate();
backgroundPane.repaint();
}
B: The screenshot above is the minimum size of the window. When I resize the window horizontally, the inner pane only resize to the value of min + (frame.width - min) / 2 meaning my right scrollbar does not stick to the right side of the frame.
See below a demonstration of the both problems:
Well, you could add a listener to the frame so have an action on event when the frame is being resized. And then pack() the frame.
public final class TestFrame extends JFrame {
(...)
this.getRootPane().addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
this.pack();
this.revalidate();
}
});
}
It you are using the paint graphic method, you should as well repaint() your frame.
In that method you can also manyally set the preferred size of the window by computing it based on e.getWidth()
How does your expand/collapse code work? Do you just make component visible/invisible, or do you add remove components from the panel?
On the other hand, collapse does hide the text but leaves all the elements in position.
If you add/remove components then the basic code is:
panel.remove(...);
panel.add(...);
panel.revalidate();
panel.repaint();
meaning my right scrollbar does not stick to the right side of the frame.
It depends on the layout manager you are using. I would guess the easiest would be to use a GrigBagLayout. It allows you to "fill" the space available. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and examples.
All the elements are contained in a JLayeredPane.
Not sure why you are using a layered pane. By default a layered pane doesn't use a layout manager.
According to camickr answer and comments, see how I solved it:
Point A is due to my free layout used in NetBeans. I did not succeed to fix my code so I changed the structure of my elements. It is probably not optimal and does not use all the swing concepts right, but it works the way I want.
I have a JLayeredPane in the background that uses a GridBagLayout. This background pane contains one column of JPanel of height 30 and 260, one for the summary line, the other one for the details.
The expand/collapse function controlled by the JToggleButton works by hiding the below panel belowPanel.setVisibility(false). No need for repack or anything, just that. Here is how the code looks like without changing the button's icon:
private void inverseVisibility(JToggleButton expand, JPanel target) {
if (expand.isSelected()) {
target.setVisible(true);
} else {
target.setVisible(false);
}
}
As I only wanted the elements to resize horizontally, all my panels have Horizontal as Fill value and Northwest as Anchor. I've set the weightX = 1; weightY = 0. Finally I added a panel in the bottom with a Southwest anchor and fill both along with both weights to 1 (not sure it changes anything but this way I am certain that it will fill all the blank space at the bottom it the window is resized at a bigger size than its content).
Point B has been solved by taking my background panel, that fit in my Frame, and putting it into a JScrollPane. The error I had was due to the Netbeans editor that did not properly stick the scroll pane to the side of the frame, due to incoherences in the sizes defined in both the frame and the scroll pane. My advise to you if you are using this tool is to set the fewest values as possible as a lot of values are heavily interconnected by the gui designer.
Get the full code (95,864 bytes)
I am writing GUI program in Java.
I have a JPanel called jpanel1 that I inserted a JSplitpane (jSplitPane1) on it. I set right and left components of jSplitPane1; jpanel2 & jpanel3. I set a background image on downward panel (jpanel1) and I want to JSplitPane and it's right and left components be transparent such that I can see the background image on them. Is this possible in Java? If this is possible can I use that method to transparent JTree as JSplitpane?
You simply need to call: setOpaque(boolean).
It depends on the L&F. AquaL&F on MacOS will respect setOpaque(false) but e.g. Nimbus does not seem to care about it. To force a transparent divider you need to override it in the UI definition of the JSplitPane
jSplitPane.setUI(new BasicSplitPaneUI(){
#Override
public BasicSplitPaneDivider createDefaultDivider() {
return new BasicSplitPaneDivider(this){
#Override
public void paint(Graphics g) {
}
};
}
});
A potential disadvantage is that this approach overrides the L&F for this component and thus might take away other L&F theming elements.
I want my panel to fit the frame when I show/hide fields. How could I notify to the parent frame to revalidate?
I thought about pass the frame to my panel's constructor, but I think may have a way this is already done. I remember that there was a protected attribute in JPanel, but there isn't.. maybe i remembering the wrong component.
I need show/hide some fields of my
panel, and I want the panel to fit the
frame.
You mean like a summary/details view and you want the frame size to change? Then try:
SwingUtilities.windowForComponent(...).pack();
you could override the addNotify in the panel into something:
public void addNotify() {
getParent().revalidate();
repaint();
super.addNotify();
}
Not sure if that's what you mean though.
SwingUtilities.getRoot(this).invalidate();
How would I force a Frame to repaint() immediately after it is maximized, or resized?
I can't find what method is called when that specific operation takes place. I have a bunch of graphics that are written with Graphic objects in paint and their orientation depends on the real time feedback from getWidth() and getHeight() but paint isn't called when I maximize, only when those pixels change unfortunately.
Register a ComponentListener:
final Component myComponent = makeTheFrameOrWhatever();
myComponent.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{
myComponent.repaint();
}
});
You need to dig further because repaint() and paint() most certainly are called when you resize a frame - it's the only way the frame can cause it's contents to be painted. It is most likely that you're not seeing the repaint reach your specific component in the frame, perhaps because the particular layout you are using is not affected if the window is made larger. Or if you have no layout, then you must subclass Frame and explicitly have it call paint on the subcomponents, since there is no layout manager to do that for you.
Note that whether or not painting is done repeatedly while you are resizing, as opposed to just once after you let go the mouse button may be an operating system option.