Repaint frame when resized? - java

How would I force a Frame to repaint() immediately after it is maximized, or resized?
I can't find what method is called when that specific operation takes place. I have a bunch of graphics that are written with Graphic objects in paint and their orientation depends on the real time feedback from getWidth() and getHeight() but paint isn't called when I maximize, only when those pixels change unfortunately.

Register a ComponentListener:
final Component myComponent = makeTheFrameOrWhatever();
myComponent.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{
myComponent.repaint();
}
});

You need to dig further because repaint() and paint() most certainly are called when you resize a frame - it's the only way the frame can cause it's contents to be painted. It is most likely that you're not seeing the repaint reach your specific component in the frame, perhaps because the particular layout you are using is not affected if the window is made larger. Or if you have no layout, then you must subclass Frame and explicitly have it call paint on the subcomponents, since there is no layout manager to do that for you.
Note that whether or not painting is done repeatedly while you are resizing, as opposed to just once after you let go the mouse button may be an operating system option.

Related

Java Swing component not repainting

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!

In Java Swing Null Layout, set position relative to bottom of container

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.

Override paint() runs twice

Sorry, Im newer on this site, but I have a problem with my code, Im drawing a set of images on a JPanel, so I Override the paint method, but when I run the project, I looks like it is running twice.. because I tried to put a println, and its appears twice on the Output. Please a help :(
public class PanelDibujo extends JPanel {
String cadenaOficial;
public PanelDibujo(String cad){
cadenaOficial=cad;
}
#Override
public void paint(Graphics a){
Toolkit t=Toolkit.getDefaultToolkit();
Image imagen=t.getImage("imagenes/muro.jpg");
g.drawImage(imagen, 20, 20, this);
System.out.println(cadenaOficial);
}
}
I created the Panel from this Frame:
public class VentanaPrincipal extends JFrame{
public VentanaPrincipal() {
PanelDibujo panel= new PanelDibujo(cadenaOficial);
setLocation(300, 10);
setDefaultCloseOperation(3);
setSize(660, 700);
add(panel);
}
}
First rule of Swing, you don't control the paint process. Painting will occur when the system decides it needs to be done, this is known as passive painting. You can make suggestions to the system that a repaint should occur, but it's up to the system to decide what and when that might occur
Don't override paint, override paintComponent and make sure you call super.paintComponent before you do any custom painting. Painting is done through a series of chained method calls, it's far to easy to break this chain and end up with no end of weird paint artifacts. Common convention recommends that you override paintComponent instead, as it's generally a safer place to perform painting
Don't load resources or perform any long running operations within any paint method, this WILL slow down your repaints and painting should run as fast as possible
Painting should paint the current state of the component and should avoid performing any calculations and have little logic within in. Decisions about how the state should be changed should be done externally (like via setters) which then trigger a repaint of the component
See Painting in AWT and Swing and Performing Custom Painting for more details about painting
The paint method is called by the JVM whenever the UI requires to be redrawn. It is the responsibility of the JVM. Like when you minimize a window an then maximize it the paint method will be called.
I would suggest that you first minimize the window and then again maximize it you would again find that the output is getting printed again.

Paint hidden Java swing component

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);

Java add image from an event

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().

Categories