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!
Related
I have a JPanel v. Function below creates a full-screen Jframe, called window, which will feature this JPanel. I have:
protected final void fullScreenMulti(final JPanel v) {
final JFrame window= new JFrame();
window.setUndecorated(true);
window.add(v);
//window.setVisible(true);
.
.
.
window.validate();
window.repaint();
GraphicsDevice gdev = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
gdev.setFullScreenWindow(window);
DisplayMode mode = gdev.getDisplayMode();
window.setSize(mode.getWidth(), mode.getHeight());
}
This works for the default render that is written for the code. However, selecting the GL renderer which uses JOGL, makes the fullscreen frame blank and I get a white screen. You will have to switch-tab in and out, or press Start for the Panel to be painted. I tried changing the background of window using:
Container c = window.getContentPane();
c.setBackground(Color.yellow);
that doesn't do anything though and I still get a white screen. (Although when i debug, I can see that the background property is successfully applied.)
Also clicking on the blank area of a second screen(The window is hosted on the first screen), or even clicking the Start button, SOMETIMES makes the frame go Black and my mouse adaptor fails to work afterwards. (what exactly could be happenning here, how can I investigate it?) Other times, it has the same effect of Alt-tab.
Haven't done much Swing stuff in Java and a I'm bit lost. Seeing that it seems to be working fine on one renderer and not on the other, suggests that it has something to do with the GL renderer, but the renderer works fine when rendering JPanels in my non-full screen mode; Also my understanding is that the role of the renderers is merely to buffer the video that is featured on my JPanel.(I mean that's what renderers do, right?) so it is probably a case of some setting not being specified above, but the original renderer takes care of it. Any suggestions what that might be?
edit: needless to say, taking out window.add(v) will make the frame render fine and the result of changing frame background etc. that was previously not working, will now be visible on the frame.
This is a known problem. -Dsun.java2d.noddraw=true solves it.
I've tried to paint component to PDF. I've got itextpdf 4.2 and everything works perfectly.
But this works only if I make visible the frame that I've tried to render.
The similar question that I've found is How to paint an invisible JFrame elsewhere? that has the same issue, but the solution wasn't provided in answer.
A little of code.
I've created a JFrame and insert main view that I want to render.
JFrame jframe = new ShowingFrame();
jframe.setPreferredSize(new Dimension(PDFHelper.getOriginalWidth().intValue(), PDFHelper.getOriginalHeight().intValue()));
jframe.setMinimumSize(new Dimension(PDFHelper.getOriginalWidth().intValue(), PDFHelper.getOriginalHeight().intValue()));
jframe.add(view);
jframe.setUndecorated(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setState(Frame.ICONIFIED);
jframe.setState(Frame.NORMAL);
//jframe.setVisible(true);
If I uncomment jframe.setVisible(true) than everything works.
But user will see this frame that I want to avoid.
So the question is: How to paint hidden control?
Inside Swing Component.java class all paint methods first check if the component is visible:
public void paint(Graphics g) {
if (isShowing()) {
// rest of the code...
}
}
I've tried to create inherit class ShowingFrame extends JFrame, that override isShowing and always return true. But this not helps to.
Swing (and the Java Graphics API) is optimized to stop rendering as soon as possible.
So the solution is to create a BufferedImage, get the Graphics instance from it and then call component.paint(g); with it.
Now you have a tab component. Try to get the content of the tab instead of rendering the tab itself. If that doesn't work, you can try to clone the tree of children, create a new JPanel, attach the children and render the result. But cloning can become tedious if the models don't behave well.
See this question for some code: Swing: Obtain Image of JFrame
Why do you want to paint something that is not visible? Your computer does not want to waste CPU cycles rendering graphics that can't be seen. In fact, there is a lot of computations done to see what parts of each window are visible and only paint the visible parts (the so called clip window).
If you want to paint something so you can use it later or save it you can always create a BufferedImage of the size you want and paint to that.
If I uncomment jframe.setVisible(true) than everything works. But user will see this frame that I want to avoid.
You can set the frame location so that it is not visible on the screen. Maybe something like:
frame.pack();
Dimension d = frame.getSize();
frame.setLocation(-d.witdh, 0);
I'm programming the game hangman and I have a Label in the center for the word to be guessed, a score panel on the right(east) and a panel of button characters on the bottom(south). As i was moving onto painting the hangman gallows, i tried to paint a simple circle at first and add it to the left(west) of the frame, but only a small portion of the circle appeared, the problem seemed to be fixed temporarily when i maximized the frame and the resized it to its original size, how do i fix this? I created a class that extends JPanel and overrided its pain component method. what should i do so that it fully shows the circle when the program is launched.
I created a class that extends JPanel and overrided its pain component method. what should i do so that it fully shows the circle when the program is launched.
You also need to override the getPreferredSize() method to return the size of the panel so that the layout managers can use this information.
overrided its pain component method
You should be overriding the paintComponent() method, not the paint() method.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
As i wrote in the title, I've this problem with JPanel.
My page is structured as a mainJPanel, another JPanel inside the main (where I paint a background) and some component added to this background panel.
Everytime I interact with something (for example i click a button) the background of the components fade to a lighter version of themselves.
I really can't figure out why.
mainPanel have setOpaque(false) and setLayout(null);
backgroundPanel have setOpaque(false) and setLayout(null) (i painted the background when i create the class backgroundPanel that extends JPanel, with an override of the method paintComponent);
all the components that becomes lighter have setOpaque(true) and setLayout(null);
the background of this components are a custom grey (rgb(232,232,232)).
Thank you all
Using setOpaque(false) should not cause a problem (ie. JLabels are non opaque). It sounds like a painting problem when using transparent colors.
Check out Background With Transparency for an explanation of the problem and a couple of solutions.
In short, my need is to have a background Image in my java app, and upon some event, create some other graphics on top of that image.
I was thinking I would use a JPanel to draw the background image in, add it at to my JFrame the start of program, and then add other JPanels on top of that upon certain events. The problem is Swing gives the JPanels added first the highest Z index, so what should be my background is showing up on top of everything.
Is there any way to control the Z index/order of the JPanels, or am I going about this completely wrong?
You can use the setComponentZOrder() to handle Z-Order in your application.
Resources :
JavaDoc - Container.setComponentZOrder
oracle.com - Mixing heavy and light components
Sounds strange to add mutiple JPanels and use z-order. I would suggest you either simple add ONE JPanel with the paintComponent(Graphics g) method overwritten, where you draw the correct image according to your events.
Or use the CardLayout, and add JLabels (with different images), then when your event triggers, use
CardLayout cl = (CardLayout)getLayout();
cl.show(this, "card3");
to show the correct JLabel.
The JLayeredPane is designed for just this purpose. It allows you to control the Z-order of components.
I was thinking I would use a JPanel to
draw the background image in, add it
at to my JFrame the start of program,
Sounds reasonable.
and then add other JPanels on top of
that upon certain events. The problem
is Swing gives the JPanels added first
the highest Z index, so what should be
my background is showing up on top of
everything.
Adding a panel to a panel is just like adding another component to the panel. The child component will be painted on top of the parent panel. There is no need to play around with Z-Order.
The key is to set a layout manager on the panel with the image. Then each panel you add to the image panel must be made non-opaque so that the background image will be painted.
Maybe the Background Panel can help you out. It automatically makes any component added directly to the panel non-opaque.