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);
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 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 am using JPanels to simulate a print preview and just printing the content panel, however I have ran into a problem whereby if I try to print multiple panels that are essentially the same document, only the the one currently being displayed on screen will print.
Is there a way I can force the JPanel to repaint even if it is not currently on screen?
I have tried:
Disabling double buffering via:
JComponent.setDoubleBuffered()
RepaintManager.setDoubleBufferingEnabled()
Painting Twice
Painting through paint()
Painting through repaint()
Painting through print()
I couldn't get it to paint off screen and I felt like I was wasting my time battling the Swing API so I just cheated and made the panels display on screen as they are being printed; now I have a new "feature" that shows you the page being printed.
I'll leave the question open incase someone knows how to do this as I would prefer not to shove all the pages in the user's face.
Update
Turns out the problem was with components that had extended java.awt.Container, the Swing components must override certain AWT methods that deal with this sort of rendering.
So I'm making this program with a GUI and I haven't worked with Swing/SWT too much but a little bit to know what's going on.
Anyway, I add an actionlistener for a button so it'll add an image to the contentPane when I click on the button but it doesn't work unless I have it as a JComponent (as seen below) and add my other things (button, JLabel, etc) to it afterwards...AND set this JComponent to the content view (which doesn't make sense).... I've also tried making it extend JPanel and just clearing out original contents and re-adding them to the new JPanel. The thing is, when I do this it recreates the text for my JLabel in a weird way, and I just know there's gotta be a simpler, more efficient, way.
class ShowImage extends JComponent{
public ShowImage(){
super();
monkey = Toolkit.getDefaultToolkit().getImage(("D:/monkey.png"));
}
public void paintComponent(Graphics g){
g.drawImage(monkey, 20, 100, null);
repaint();
}
}
Do not invoke repaint inside paintComponent
Invoke super.paintComponent and then draw the image
Also, depending on the layout manager, this component will have a preferred size of (0, 0), and therefore will not be visible.
For more information, see 2D Graphics.
Edit -
Note that dynamically adding a component will force you to revalidate the container and issue a repaint request so the layout manager will layout its components again and remove any visual artifacts. Also, for more information regarding images, see Working with Images.
Anyway, the simplest approach would probably be to set the image as the icon of a JLabel instance and add that to the container. There's really no need to reinvent the wheel here.
g.drawImage(monkey, 20, 100, this);
..would most likely have fixed the problem in the original code. It was a combined problem of:
Loading the image in an asynchronous way. (Toolkit.getImage() as opposed to ImageIO.read().)
Painting it to a 'blinkered' ImageObserver. The JComponent implements ImageObserver. As soon as the image is totally loaded (as well as a few points before that), the observer will be informed, triggering a repaint().
I've implemented a custom JPanel, whose paint method I've extended to do a lot of manual rendering in full screen mode. Now I would like to integrate another JComponent to this (in my case a JPanel that contains a JScrollpane with a JTextPane as its viewport) that should appear on top of my first panel, but because my custom rendering pipeline is complex, adding the JComponent to my panel and having it painted the traditional way through the AWT system is not an option (I tried and it's quirky at best, not functional at worst), so my question is: is it possible to manually order the JComponent to be painted at one point in my program by calling its regular paint method without tying it to a JContainer and if yes, how do I do this?
Thanks in advance for your answers.
See the LabelRenderTest.java source on this thread. The label is eventually drawn to screen, but it is painted to BufferedImage before ever being displayed.
The important line of the source is..
textLabel.setSize(textLabel.getPreferredSize());
You can take a look at CellRendererPane and see how for example BasicTableUI paints component images with it.
Yes, just call the normal paint method on the object and pass the Graphics you want it to paint on. However, this is just going to paint it and it sounds like you want it to possibly scroll which means you will need to add it to your custom JPanel. In that case just add the panel and you a layout manager that will place the component where you need it.
You should set size for the component. Then to position it use your Graphics' translate(x,y) to position the component in desired Point.
if there is any container higher level in the hierarchy you can use
validate(); repaint();
pair to do that.
if not you can change it's size or bounds ( like +1 , -1 ) at the end to make it repaint itself.