I have a Panel which needs to know its size inside the constructor:
class Panneau extends JPanel {
public Panneau() {
super();
new Map(getSize());
}
}
Unfortunately, the size doesn’t seem to have been initialized yet and getSize() returns a Dimension with 0 for height and width. How to get the future Dimension notwithstanding?
If you want to work with the size of a component, you need to do so when the component is actually in use in a well-formed user interface.
One of the ways to do that, is to add a ComponentListener to the code and implement the componentResized method, which will be called whenever the component's size changes. There you can work with the latest accurate value for the component's size by using getSize().
Related
I have a swing component where the ideal size of the component will vary based on the content that is is currently being displayed (which happens in this case to be an image).
I'd like this preferred size to change when the content is changed, and also allow the layout to be changed (for example, if the component is being used inside a JScrollPane then the scroll extents would change to fit the size of the component).
What is the canonical way to do this in Swing ?
Suggestions:
Use a class extends JPanel (or JComponent),
give it a getPreferredSize() method override where you return a Dimension with the parameters that you desire.
For instance if the diameter will be based on a BufferedImage, you could have something like:
getPreferredSize example:
public Dimension getPreferredSize() {
if (myBuffImg != null) {
return new Dimension(myBuffImg.getWidth(), myBuffImg.getHeight());
}
// default return value
return super.getPreferredSize();
}
Edit
Regarding your comment:
how would you handle the case of the component's content image changing though? is it just a a case of triggering a re-layout in the surrounding container?
You'd give this class a setImage(Image image) method of course, and you could repaint() this panel from within this method. The method I suppose could call revalidate() on this JPanel's ancestor causing this component to be re-layed out, but I'm not too crazy about methods in this class having side effects on its ancestor and think that likely it will be better for the code calling the setImage(...) method to suggest that the container revalidate itself.
A lot will come down to your individual needs. When dealing with "image panes", I typically will call setPreferredSize and invalidate, repaint when the image changes.
Changing the layout should automatically trigger a invalidate, reprint request anyway.
But I agree with Hovercraft, you'll want to do this from your own customs panel.
Another approach would be to use something like CardLayout to handle changing between different content layout outs, rather the cleaning up a single panel and re-adding comports to it
I'd also have a look at the Scrollable
I read some posts here and I started why some people do
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
instead of
setPreferredSize(new Dimension(500, 500));
Isn't the second one better because it creates only one Dimension object whereas the first one possibly creates several (even if it's not that much wasted memory)? Or am I wrong? Is there a difference at all?
A big difference is how the value can change over time, and so the one you choose should be dependent on what you're wanting to do with the code.
If you simply call setPreferredSize(new Dimension(500, 500)); in your code, it will do as you expect - it sets the preferred size to 500x500. However, other code in your application can potentially overwrite this value with a new one - anything can call setPreferredSize() and the last call to this method will be the end result.
However, if you override the getPreferredSize() method in your code, it will always return 500x500. It doesn't matter if any of your code calls the setPreferredSize() method, because they are effectively ignored. If you also override getMinimumSize() and getMaximumSize(), you can force a fixed size on a component that shouldn't change regardless of the size of the window and the other components.
However, as mentioned by #Andrew Thompson in the comments, this isn't guaranteed as some layout managers can choose to ignore these, especially if you're writing your own layout manager, and adding a custom component to some parent containers will also ignore these methods, depending on where/how the component is used. Regardless, it's still more rigid than calling setPreferredSize() which can easily be called by other code and be totally overwritten.
I also override the getPreferredSize() method (plus getMinimumSize() and getMaximumSize()) for any of my custom components, such as a color picker that needs to have specific dimensions for the component to be painted properly. Without overriding these methods, the Swing layout managers don't understand how your custom component can be positioned and sized appropriately for the size of the JFrame or JPanel.
I have a class MyPanel that extends JPanel.
MyPanel is a child panel: his size is dinamically calculated by the LayoutManager of his parent.
The problem is that I need MyPanel to be notified as soon as the LayoutManager of his parent calculates his size.
It needs to be notified because I need to initialize some variables according to the panel's size.
If I call getSize() in the MyPanel constructor i get (0,0) because the panel is not "ready".
When should i call getSize()?
I'd like to have something like this:
/** Lays out the panel and sets his size according to his layout */
#Override
public void onReady() {
System.out.println(getSize()); //output is (0,0);
super.onReady();
System.out.println(getSize()); //output is (600,500);
//here i can initialize my variables
}
Is there something similar? Maybe doLayout()?
The only way i could find is calling getSize() in the paintComponent() method... it surely works because the panel is surely displayed when paintComponent() is called but I can't do this because i need to initialize some variables as soon as i know the panel size... but only once! paintComponent() will be called several times...
It's ComponentListener.componentResized().
Best way is to use a ComponentListener.
See ComponentListener.componentResized(ComponentEvent)
I have a subclass of JPanel, and I want it to, as soon as its parent frame is pack()ed, to set its minimum size to its new preferred size. I've tried using a ComponentAdapter, but JPanels are by default visible; if I setVisible(false) at the beginning of the constructor, the JFrame won't make it visible again. If I use SwingUtilities's method to get the window root, it will return null because it's in a constructor.
Is there a way to do this?
I have a subclass of JPanel, and I want it to, as soon as its parent frame is pack()ed, to set its minimum size to its new preferred size.
If you know the preferred/minimum size before the pack, set it then.
to set its minimum size to its new preferred size
Certainly possible, but whether it is useful ... . You can override the getMininumSize() method to return super.getPreferredSize();
I have a simple drawing program, I set my Jframe's size with the following code:
frame.setSize(900, 700);
However, when user change the size of the window, white area to draw, still remain same size therefore, user is not able to draw eventhough he enlarge the window.
http://forum.codecall.net/java-tutorials/31180-java-mini-paint-program.html this is where I start from. I extended class "PadDraw" and wrote most of my code to there, in my other java file, I only create a frame, then I create "PadDraw" object, I crated a container and then added object to the frame's container: content.add(drawPad, BorderLayout.CENTER);
I changed my code:
public class PadDraw extends JComponent implements ActionListener, ItemListener, ComponentListener{
public synchronized void addComponentListener(ComponentListener l) {};
.
.
.
.
And I added unimplemented methods, and the "componentResized" is:
public void componentResized(ComponentEvent arg0) {
System.out.println("Changed ????");
}
But when I changed the window's size, nothing happens.
One thougt: When I added componentlistener to my other file instead of drawPad, componentResized method flags, but because I have created drawPad object before this event occured, I can't change the size =/
Thanks
Hopefully you're not drawing directly on the JFrame but rather in a JPanel or JComponent that's been added to the JFrame's contentPane. If it has been added BorderLayout.CENTER, then it should expand and contract as the JFrame expands and contracts. Things get a little trickier if you're drawing on a BufferedImage as you'll have to use a ComponentListener to see when the component that holds the BufferedImage changes size, and when it does, change the size of the BufferedImage without losing the drawing that's already there.
If this answer is not helpful enough, consider giving us more specific information about your current problem and your current program.
In the program that you link to, you're drawing on an Image object whose size is set the first time paint is called. What you'll want to do is to add a ComponentListener to the PadDraw object in its own constructer, and in the ComponentListener's componentResized method, resize your image using the PadDraw's new height and width. I would only do this however if the new size is larger than the old size. You would also then want to redraw the old image on the new before setting the image variable = to the new image. Then call repaint.