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.
Related
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.
got some problems.
Built an applet that has to be used step-by-step. After each step, a button is clicked and the next step should be added into the GUI.
Problem: without zooming, the added content doesn't get visible. in a application you can workaround with scaling the window size, but in an applet I wasn't able to solve that problem.
Thanks
EDIT:
actually, it looks smth like this:
Panel cp = new Panel(new GridLayout(0,2));
Panel Block1 = new Panel(new GridLayout(2,2));
Panel Block1 = new Panel(new GridLayout(2,2));
...
init
public void init()
{
buildBlock1();
buildBlock2();
add(cp);
cp.setVisible(true);
}
adding some empty panels here, those who will get filled afterwards
private void buildBlock1()
{
Block1.add(panel1);
Block1.add(panel2);
Block1.add(panel3);
Block1.add(panel4);
cp.add(Block1);
}
button actionlistener
private void generatePanel1()
{
//adding some Components to the subpanel of Block1, which is a subpanel of cp.
Panel1.add(...);
cp.repaint();
cp.validate();
}
Now I don't have any code that I can check but adding (and removing) components to a container normally often needs to be "validated". So try
panel.add(...);
panel.revalidate();
API docs for JComponent.revalidate():
Validates this container and all of its subcomponents.
Supports deferred automatic layout.
Calls invalidate and then adds this component's validateRoot to a list of components that need to be validated. Validation will occur after all currently pending events have been dispatched. In other words after this method is called, the first validateRoot (if any) found when walking up the containment hierarchy of this component will be validated. By default, JRootPane, JScrollPane, and JTextField return true from isValidateRoot.
This method will automatically be called on this component when a property value changes such that size, location, or internal layout of this component has been affected. This automatic updating differs from the AWT because programs generally no longer need to invoke validate to get the contents of the GUI to update. The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the container has been displayed.
I have searched for this problem and haven't found anything close. I will try to be specific and post code however this is a large program so I can't post all the code. The problem in general is this: A JButton on one panel causes components on another panel to shift at first click. This only occurs when there is an action listener added to the button. (clicking the button without an action listener doe noting (obviously)). The problem is that the action listener i add only changes the button background, text, and size (to fit new text).
Here is the action listener as of right now. login is the JButton:
private class LoginListener implements ActionListener{
public void actionPerformed(ActionEvent e){
loggedIn = !loggedIn;
if(loggedIn){
login.setText("Logout");
login.setBackground(Constants.RED);
}
else{
login.setText("Login");
login.setBackground(Constants.UPPER_BOUNDARY);
}
login.setSize(login.getPreferredSize());
}
}
The setup is this. The action listener is a subclass of the loginPanel where the login button is located. That loginPanel is added to the main JFrame at the upper 1/4 of the frame. The lower 3/4 of the main JFrame is mainPanel which has other swing components. The loginPanel and mainPanel do not share components or variables or really know of each other's existence (as far as I have coded). Yet when this actionlistener above is added to the login button components in the mainPanel shift from their positions to other positions. The only happens at first click and then they stay where they are at (not where i want them).
Other factors:
- I use absolute positioning (sorry if you don't like it but I like it better)
- I am using a SynthLookAndFeel but have never had this issue with this look and feel before.
Thanks
Other factors: - I use absolute positioning (sorry if you don't like it but I like it better)
There's nothing to be sorry about, and the solution is simple: Don't use absolute positioning, but instead learn about and use the layout managers to there full abilities. One of the reasons to use them is to avoid pernicious bugs like this one. It's quite possible that your code is in fact using a component's default layout manager even now without you knowing about it. You can find out more about them here. One of the keys to using them well is to nest them by using nested JPanels, each using its own layout manager. Then they can do the heavy layout lifting for you automatically.
I have a JFrame inside of which is a jpanel that im using as the content pane.
So basically im using the jpanel to load content into on click. New content is returned as a Jpanel also so its ends up being jpanel -> inside jpanel -> inside Jframe. When i need to load in new content i clear the panel, load the new content and validate() the jframe & jpanel and the new content displays.
My problem is that when the new content displays its clear that the validate method is working because i can see the new interface but i can also see the old interface as if its become the background; i can resize the window and it just disappears and looks as it should.
Is this just the way validate works or can i fix it?
Edit: this worked. The problem was i wasn't calling repaint manually.
public BaseWindow setContent(JComponent comp){
contentPane.add(comp);
contentPane.revalidate();
contentPane.repaint();
return this;
}
Generally the code for adding/removing one or two components from a panel is:
panel.remove(..);
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes needed
However, if you are replacing all the components on the panel, then the better approach is to use a Card Layout.
You have already stated the revaliate() followed by repaint() doesn't work so the only suggestion I have is to post your SSCCE that demonstrates the problem.
Don't use validate. Use revalidate() instead.
Revalidate first calls invalidate() followed by a validate().
In Swing, you would rarely use validate().
Note: I also feel that maybe the old panel is not cleared/removed.Check again!
Validate() is for causing components to re arrange themselves according to the layoutmanager that you have installed. This is not really what you should be using.
I can't see your code, so I'm not sure exactly what you are doing. I could speculate that calling repaint() on your "inner panel" will solve the problem you are having...but really, if you are doing things properly, you shouldn't need to call repaint() or validate().
Make two JPanels, one with content A (e.g. your buttons), and one with content B (e.g. your "static" field). Use the "add()" and "remove()" methods on the parent container (the JFrame's content pane?) to swap these two JPanels with each other whenever you want to switch the content that is displayed in that part of the JFrame.
Then you shouldn't need to do anything else; it should just work.
I don't know if validate() makes any promise about fully repainting the container. You might have to call repaint() yourself to make it behave as you want to.
Here's another possible solution:
Put both JPanels in at the same time, side by side, and then make sure only one of them is ever visible at any one time:
JPanel p = new JPanel(new BorderLayout());
p.add( panelA, BorderLayout.EAST );
p.add( panelB, BroderLayout.WEST );
panelA.setVisible(true);
panelB.setVisible(false);
Then when the user clicks the button to switch panels:
panelA.setVisible(false);
panelB.setVisible(true);
The setVisible() method and BorderLayout should take care of validating, layout, and calls to repaint() for you.
I ended up fixing my issue (display not shown, buttons would stay clicked/weren't unclicking) by changing which panels were added/removed.
Problem:
frame.removeAll();
frame.add(getNewPanelDisplay());
frame.revalidate();
frame.repaint();
Solution:
//initializer()
mainPanel = new JPanel();
frame.add(mainPanel());
// ...
//update()
mainPanel.remove(0);
mainPanel.add(getTablePanel(), 0);
frame.revalidate();
frame.repaint();
I have a class that extends javax.swing.JPanel, it contains a single JButton. I've created the class in NetBeans designer. As such, I have a initComponents() function thats called from the class constructor.
What I want to do is when/if a function is called, I want to add a second button, and change the layout of the two buttons. Doing simply:
public void addSecond() {
javax.swing.JButton secondButton = new javax.swing.JButton();
add(secondButton , java.awt.BorderLayout.CENTER);
}
Doesnt work, the new button doesnt show up. I tried a call to invalidate() as well but no luck.
How do I trigger a re-evaluation of the layout?
If said function is called more than once, what parts of the layout/buttons do I need to call dispose() on? Any other cleanup I should worry about?
Would this be easier to handle if I don't use the NetBeans designer?
You need to set the layout of the panel before you add the button with BorderLayout.CENTER. Also, you must remove and add the first button again and invoke the revalidate() method on the panel.
Change your addSecond() method as below and it should work.
private void addSecond() {
JButton secondButton = new JButton("Button - 2");
this.setLayout(new BorderLayout());
remove(firstButton);
add(firstButton, BorderLayout.NORTH);
add(secondButton, BorderLayout.CENTER);
revalidate();
}
when you changed the components in a way that changes the layout, you need to trigger the layout manager again by calling revalidate(). You can call it as often as you want.
For simple layouts just calling repaint() may be sufficient.
And actually unless you're doing dynamically changing panels (i.e. adding/removing components on the fly) you should use the netbeans designer, so all the Swing elements are in one place.
-- EDIT --
And you can only put one component into BorderLayout.CENTER per panel. If you put more than one element into the same position of a panel, what gets painted is not well defined, i.e. it may be either of the elements (or both).