I'm currently making a java swing GUI with the Netbeans GUI builder. I have a bunch of panels that are being replaced on my main JFrame as the user navigates the GUI and a controller class is taking care of this. At one step, however, there is a panel (FilterDefinitionPanel) that contains a combo box as well as a blank inner panel (QueryHelperPanel).
What I'd like to do is to swap out this inner panel with another I've created (StringQueryDefinitionPanel) depending on what the user selects in the combo box. So right now under my combo box's ComboBoxItemStateChanged event handler I have my controller class run this method:
public void selectFilterAttribute(Object item) {
/**
* Determine panel to create based on item selection. Currently always returns the same
* StringQueryDefinitionPanel.
*/
JPanel panel = this.getRequiredQueryHelperPanel(item);
/**
* Swap the placeholder QueryHelperPanel with the required one.
*/
((FilterDefinitionPanel) this.mainFrame.getMainPanel()).setQueryHelperPanel(panel);
/**
* Not sure if all of these are needed :\
*/
mainFrame.validate();
mainFrame.repaint();
mainFrame.pack();
}
This is what's happening in the FilterDefinitionPanel's setQueryHelper method:
public void setQueryHelperPanel(JPanel panel){
this.remove(queryHelperPanel);
this.queryHelperPanel=panel;
this.queryHelperPanel.repaint();
/**
* Again, not sure which refresh methods are needed...
*/
this.validate();
this.repaint();
}
Currently I think this is replacing my inner placeholder panel with ...something... , but the replacement seems to contain nothing. I don't know if it matters but both the placeholder and the replacement panel are the same size. I'm kind of a swing nub so any tips would be really appreciated.
The setQueryHelperPanel() method does not work because it removes the existing panel from the collection of children of this via the remove() method, but then does not use add() to add the new panel - assigning it to the instance variable does not cause it to become a child.
However, a much cleaner solution for your problem would be to use a CardLayout.
Thanks for the reply.
I looked into CardLayout previously but I'm trying to avoid it as from what I understand it loads all the panels in memory and then allows you to swap them out. I'd like to keep full control over when I dynamically display the panels.
Forgetting the remove was a dumb mistake on my part. I actually had that earlier but it still wasn't working. This is the current swap method:
public void setQueryHelperPanel(JPanel panel){
this.remove(queryHelperPanel);
this.queryHelperPanel=panel;
this.add(queryHelperPanel);
this.queryHelperPanel.repaint();
this.validate();
this.repaint();
}
I understand that setting the instance variable doesn't actually add it as a child, but my idea was that the variable would be used to remember what panel to remove or add.
Related
I have three JPanel, fatherPanel, childPanel1, childrenPanel2.
When I click a button, I remove the current children panel from the father panel, and add another children in the father panel.
Everytime I should call revalidate() and repaint() to update the UI.
Then, I know the SwingUtilities.updateComponentTreeUI() has the same effect.
I want to know are there any difference between the twos?
Swing supports pluggable Look-n-Feel's. When you change the L&F at runtime you need to inform all your components, about this change using the method updateComponentTreeUI. Because due to new L&F the component sizes can be changed, Swing must call revalidate to recalculate the layout. Here is the code of the method updateComponentTreeUI
/**
* A simple minded look and feel change: ask each node in the tree
* to <code>updateUI()</code> -- that is, to initialize its UI property
* with the current look and feel.
*/
public static void updateComponentTreeUI(Component c) {
updateComponentTreeUI0(c);
c.invalidate();
c.validate();
c.repaint();
}
So yes, you can invoke SwingUtilities.updateComponentTreeUI to inform your GUI about layout change but it's huge overhead (and can theoretically have some side-effects). Combination of revalidate and repaint is better in your case.
So I have a program that at the start only contains an 'add movie' button at the bottom of the frame.
Above it I inserted a scrollpane.
I also made a seperate JPanel form which contains labels and textfields where you have to input the data of the movie.
Every time I click the 'add'-button I want a form to appear inside the scrollpane (next to previously made forms).
So I figured I just needed to do this:
private void AddMovieButtonActionPerformed(java.awt.event.ActionEvent evt) {
MovieForm movie = new MovieForm();
MovieScrollPane.add(movie);
}
But nothing new appears.
I tried validate() and repaint(), but so far these don't seem to work.
I made the interface in Eclipse btw.
Anyone who can help me?
Thanks anyway!
MovieScrollPane.add(movie);
Don't add components directly to the scrollpane. Normally a JPanel is added the the viewport of the scrollpane.
Then, whenever you add a component to a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
This makes sure the layout manager is invoked to the preferred size can be recalculated.
Also, follow Java naming conventions. Variable names should NOT start with an upper case characters.
I'm trying to be creative with a class project in Java.
I have a JFrame which takes in some input from the user, and I want to create a sort of pop up frame that will show a graph from the input.
The second frame is only going to be showing a graph. I'm having trouble realizing this.
I'm using the GUI builder(Netbeans) for the main JFrame and at first I tried to just create an empty JPanel and set it visible from the button, but that didn't work and I soon found out I couldn't.
I had to use a JFrame or some other container apparently(am I wrong?).
So now I'm thinking, how will I pass the information to the second pane for the graphing information?
Anyways, I'm just looking for some input or good practices in order to accomplish this. I'm reading up on CardLayout now but that's not the solution I want since it would require me to create a pane to hold the graph component. I just want the graph button to open up a graph pane(or frame) and close when the user wants to. The main frame is only used to take the input for the graph. Thank you for any input.
There will be a question soon on how I can actually graph something in Java, but ill tackle one problem at a time
You could create another class for the pop-up JFrame which would probably be the best idea. You could do something like:
public class PopupFrame extends JFrame{
//Declare variable you wish to use for your graph here.
public PopupFrame(/* Pass in variable(s) that you will need to display the information. */)
{
super("Graph");
//Set the graph variable equal to the variable to passed into the constructor.
add(/* Put in the variable that you just initialized above and that you declared outside of the constructor. */);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,500);// Change to the dimension that you want.
setLocation(50,50);// You could also have the constructor give it these values if you want to center it on your parent window.
setVisible(true);
}
}
and in your main class, have something like:
PopupFrame f = new PopupFrame(/* Graph variable(s) passed in here. */);
f.show();
Hopefully this was of some use to you. Good luck!
Is it possible to use a single JPanel for multiple tab items in JTabbedPane?
EG:
JTabbedPanel tabs=new JTabbePanel();
JPanel panel=new JPanel();
JButton but=new JButton("TEXT");
but.addActionlistener(this);
panel.add(but)
tabs.add("First",panel);
tabs.add("Second",panel);
An ActionListener is added to the JTabbedPane to notify the program of tab changes (change cur_tab to tab number)
public void actionPerformed(..)
{ System.out.println("Now in "+cur_tab); }
The same component cannot be used for several tabs
taken from here
Sounds like you need a subclass of JPanel. Just create an abstract class that handles the complex layout and have the subclasses create the necessary GUI elements that are required.
If you are just inserting a single text box, button, etc, you may not even need subclasses per tab. Just create multiple instances of the base class and add the component you need.
New panels and other GUI items are relatively cheap. Performance issues in a Swing GUI are more likely to come from event handling or firing too many events rather than how complex or how many components it has. Make things easier to maintain and understand, then worry about performance.
if you'll create class that returns JPanel then yes that's possible
but Notice:
there are long time Bug that two Tabs can't contains same component schemas, with schemas I means for example one Tab contains JPanel + JTextField + JButton, but then second JPanel must contains another Numbers or Type of JComponents
unfortunatelly (nothing special) BugsDatabase isn't accesible in this moment
I had a panel with memory-intensive components on it which I only wanted to create one instance of, but change the behaviour of it using the attractive JTabbedPane.
I did it by creating empty panels for each tab, and a third panel that contains my (single) complicated components. On the StateChange event for the JTabbedPane, I remove the third panel from whichever of the first two it was in, and add it to whichever one is newly selected.
Bit hacky, but it works fine.
You are wrong.
Just set a panel on the first tab in function initComponents() like that:
p.add("1", MainPanel);
Then use:
p.add("2", p.getTabComponentAt(0));
Using this metode you will have the same component on 2 tabs.
You can use StateChanged Event to change actions in this tabs.
For example:
JTabbedPane p = (JTabbedPane)Tabbar;
int idx = p.getSelectedIndex();
if(idx==0){
Do something...
}
if(idx==1){
Do something different...
}
The following will allow you to add the same component with different titles to a JTabbedPane:
JTabbedPane tabbedPane = new JTabbedPane()
{
boolean adding = false;
#Override
public void removeTabAt(int index)
{
if(!adding)
{
super.removeTabAt(index);
}
}
#Override
public void insertTab(String title, Icon icon, Component component, String tip, int index)
{
adding = true;
super.insertTab(title, icon, component, tip, index);
adding = false;
}
};
class Deal implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
dl.setDeck();
dl.shuffle();
dl.firstDraw(pl);
for(Card c:pl.showHand())
panelplay.add(new JLabel(c.getImageIcon()));
panelplay.validate();
}
}
This is an event handler for a Jbutton. The method pl.showHand() returns a ArrayList of a user defined class 'Card'. Inserting a println() inside the loop shows the print, so the code is being executed but the Panel panelplay isnt showing card Images.
What about the existing labels on the panel? You don't remove them. I'm guessing you are using a FlowLayout and the labels just get added to the end of the panel so you don't see them.
So one solution is to use panel.removeAll() before adding the labels back to the panel. I then use:
panel.revalidate();
panel.repaint();
Or the better option as suggested earlier is to not replace the labels but just replace the Icons using the setIcon() method.
Do as Gilbert says, look at the Swing Tutorial part that concerns Labels.
JLabel has the following methods...
void setIcon(Icon)
Icon getIcon()
Also look at the SplitPaneDemo It does exactly what you want, you can even run it with JNLP to see.
You don't want to add the JLabel in the ActionListener.
You want to use an already added JLabel setText() method in the ActionListener.
You define all the Swing components once, when you create the GUI.