I have a JFrame, which is the toplevel container for a window, and a single JComponent (that I have implemented) which is contained in the JFrame.
In part of my JComponent's logic, I need to resize the window to a specific size, but now matter what I try, it has not worked. I have tried calling setPreferredSize and setSize on the JFrame, the JComponent, and on the Container returned from calling getParent() on the component.
I have a feeling this has something to do with not calling pack after changing the size, but I cannot figure out how to access the JFrame from the JComponent to call pack on it (I am no swing expert).
Thank you
You can always get the top level window by calling the SwingUtilities#getWindowAncestor method:
Window topLevelWindow = SwingUtilities.getWindowAncestor(myComponent);
topLevelWindow.pack();
passing in your component. Just make sure that you only call this after the GUI has been rendered, else you'll get a nasty NullPointerException.
Related
I have an LWJGL OpenGL Display showing up inside an AWT Canvas, which in turn is inside a Swing JPanel that is used as content pane for a Swing JFrame. At some point in the program, I want to switch the AWT Canvas containing the Display for a JComponent, so that instead of having something like that:
JFrame > JPanel > Canvas > Display
I have something like so:
JFrame > JPanel > JComponent
However, even though I remove the Canvas from the JPanel and add the JComponent, then revalidate the JPanel and repaint it, the Display still shows until I CTRL-ALT-SUPPR to task manager (my JFrame is set Undecorated and ExtendedState is JFrame.EXTENDED_BOTH, so it is full screen). At which point, the JComponent shows up like nothing ever happened..
I'll share the part of my code that does the transition so you can maybe help me point out what I have done wrong:
public static void switchTo(Container container){
pan.removeAll();
container.setBounds(0, 0, Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
pan.add(container);
frame.getContentPane().validate();
pan.revalidate();
pan.repaint();
}
where pan is my JPanel and frame is my JFrame.
I have also tried directly setting my JComponent as my JFrame's content pane, but that gives the exact same result.
The only way I managed to make it function correctly was by calling destroy() on the Display beforehand; however, I need to keep the OpenGL context running so that I don't have to re-initialize the Display and reload every texture when switching back to the Display, which would be quite a long process given the number of textures I have.
Thank you very much for any answer, I hope I made myself clear!
I've added my JPanel derived class to the JFrame. Now when I want to draw an oval (using fillOval in my JPanel's paintComponent method) I see two ovals being painted. The problem disappears when I invoke super.paintComponent or when I invoke setContentPane in the JFrame class with my JPanel as parameter. The question is, why does it happen? Of course when the upper left corner of both JPanel and JFrame are in the same place, it doesn't happen. But somehow the JPanel isn't opaque unless I invoke super.paintComponent. The main question is why does it paint BOTH on the default content pane AND my JPanel. Thanks for help.
" The main question is why does it paint BOTH on the default content pane AND my JPanel."
It just appears that way, but actually you are seeing both being drawn on the panel. Always call super.paintComponent in the paintComponent method (no if ands or buts) or you will see paint artifacts as the one you're experiencing. The paintComponent method can be called for any number of reasons, and each time it's called, is another opportunity for paint artifacts to appear. Calling super.paintComponent wipes those out. When you set the content pane to the panel, it appears the paintComponent method is not being called more than once, so you don't get those artifacts. But to reiterate, always call super.paintComponent. Setting the content pane has nothing to do with the problem or the solution.
I have an application where I want that the user is able to choose between normal and advanced settings. Now if the user checks a JCheckBox and the advanced settings should disapper the problem starts.
My idea was to set all unnessecary swing components (JScrollPane, JLabel...) invisible and then find a method of JFrame which fits the window to the VISIBLE components.
My question is if there is such a method?
... and then find a method of JFrame which fits the window to the VISIBLE components. My question is if there is such a method?
Yes, there is such a method, and it is called pack().
This will cascade through the layout managers of all the containers held by the top-level window, asking them to re-lay out their visible components, resizing components to their preferred sizes as based on the components and the layout manager requirements, and eventually resizes the top-level window to fit the containers and their components.
1. You can use setVisible(boolean b), to make the component visible and invisible.
2. You can check that if the component is visible or not using isVisible()
3. You can then use the pack() method, pack() method gives sets the frame size as per need
I think you can wrap the advanced content in a panel (if possible) and remove that panel from frame using this.remove(component) then use this.pack()
and you can do the opposite on showing them, this.add(...) then this.pack() again
I found three ways to fill my JFrame frame = new JFrame("...")
createContentPanel returns a JPanel and createToolBar returns a ToolBar.
frame.add(this.createToolBar(), BorderLayout.PAGE_START); //this works and puts the ToolBar above and the ContentPanel under it<br>
frame.add(this.createContentPanel(), BorderLayout.CENTER);
frame.setContentPane(this.createContentPanel()); //this lets the JToolBar hover over the ContentPanel
frame.getContentPane().add(this.createToolBar());
frame.getContentPane().add(this.createContentPanel()); //this only puts the last one into the JFrame
frame.getContentPane().add(this.createToolBar());
And now I am wondering why should i use the getContentPane()/setContentPane() method if i could just use a simple frame.add(...) to fill my frame.
You are right that it doesn't matter which you use (JFrame#add(...) vs. JFrame#getContentPane().add(...)) since they both essentially call the same code, however there will be times in the future when you'll need access to the contentPane itself, such as if you want to change its border, set its background color or determine its dimensions, and so you'll likely use getContentPane() at some point, and thus getting to know it and be familiar with it would be helpful.
//this only puts the last one into the JFrame
You need to understand how layout managers work. The default content pane is a JPanel that uses a BorderLayout. When you add a component and don't specify a constraint, then it defaults to the CENTER. However you can only has a single component in the center so the layout manager only knows about the last one added. When the layout manager is invoked it sets the size() and location() of that component. The other component has a size of 0, so it is never painted.
In Java 1.6, you can just use the add method of JFrame:
http://download.oracle.com/javase/6/docs/api/javax/swing/JFrame.html
(It will be delegated to the contentPane.)
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JFrame.html
Which says:
The JFrame class is slightly
incompatible with Frame. Like all
other JFC/Swing top-level containers,
a JFrame contains a JRootPane as its
only child. The content pane provided
by the root pane should, as a rule,
contain all the non-menu components
displayed by the JFrame. This is
different from the AWT Frame case. For
example, to add a child to an AWT
frame you'd write:
frame.add(child);
However using JFrame you need to add the child
to the JFrame's content pane instead:
frame.getContentPane().add(child);
The same is true for setting layout
managers, removing components, listing
children, and so on. All these methods
should normally be sent to the content
pane instead of the JFrame itself. The
content pane will always be non-null.
Attempting to set it to null will
cause the JFrame to throw an
exception. The default content pane
will have a BorderLayout manager set
on it.
I'm using a JFrame in which the CENTER portion of the BorderLayout is occupied by a JScrollPane that wraps around a JPanel. What I'm finding is that when I initiate the action that actually causes the JPanel to be displayed, the display doesn't change. But when I resize the JFrame, the new JScrollPane has now magically appeared.
So what methods are called when you resize a JFrame? If I know, then I can call it in the code and avoid having to resize the frame just to see the results of the operation.
Its been a little bit since I've done swing, but from memory, calling validate() on the panel should do the trick. This will cause it and its children to have their layout calculated which is when the scrollbars decision is made. If that doesn't work, try calling validate on the frame's content pane. This is a little more costly, but may be needed if other components are being considered.