Size miscalculated when dynamically adding JPanels - java

I am writing an application that is a virtual notebook. The idea is to have panels with various content (which is based on an external file) added to a panel that acts as a page. Once that page is full, its specialized add method should return false.
The problem is that I can't figure out how to accurately determine the size of the panels when I'm adding them, so I end up adding too many. The preferredSize of the panels is generally too short, and the size has 0 height. Is there a way to determine the exact size that a component is taking up in a layout?
I've tried using doLayout(), but it doesn't seem to change the size or preferredSize of my components. Maybe I'm not using it right? Here is the add method: (The contentPanel has BoxLayout, and the content panel doesn't have a set size, but is added to a panel (this) that does. The class this method is in extends JPanel)
public boolean addSpecializedgPanel(SpecializedPanel sp) {
this.contentPanel.add(sp);
this.doLayout();
if (this.contentPanel.getSize().height > this.getHeight()) {
this.contentPanel.remove(sp);
return false;
}
return true;
}
Thanks for any help (even if it criticizes my whole design :) )! This has been a huge headache!

I don't think you should deal with the size like that, you should use a layout manager for that. Maybe you should have a look at How to use CardLayout

You want to use Container.validate() on the panel (possibly calling invalidate() first):
public void validate()
Validates this container and all of its subcomponents.
The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the container has been displayed.
This should cause layout to occur, and, consequently, resizing of the components. You will then need to invalidate() after removing your failing panel, before returning false.

Related

Why doesn't AWT/Swing repaint automatically when adding a component to a container?

We have some code implemented as follows:
#Override
public void showPanel(CardPanel panel)
{
cardPanel.removeAll();
cardPanel.add((Component) panel);
// Even though you'd think adding a component should automatically repaint,
// it turns out that it doesn't.
cardPanel.repaint();
}
cardPanel is just a JPanel and CardPanel is just one of our own interfaces, but all card panels are just using normal Swing components.
This comment was baffling because, as far as I knew, Container#add was supposed to automatically repaint itself if a child was added. Yet, if I delete the line, indeed I do see that it doesn't repaint its contents when the child is added.
Is there some particular reason why Container behaves this way? To me, it seems to violate the "principle of least surprise"...
Is there some particular reason why Container behaves this way?
By default all Swing components have a default size of (0, 0) so there is nothing to paint.
Components are given a size (and location) when the layout manager is invoked. Since you could be adding multiple components to the panel it doesn't make sense for the layout manager to continually be invoked as each component is added.
So when you finish adding components to the panel you do:
panel.revalidate(); // to invoke the layout manager
panel.repaint(); // not always needed, but will ensure the panel is repainted.

Auto scaling components with Java JFrame [duplicate]

Not sure if what I need is possible.
I have a container (JPanel) that contains some internal elements.
I was wondering if it is possible to force internal elements to fit into the container's size.
I need them to be fully visible i.e., resize to fit inside the Panel's size and not cut some parts of the internal elements.
Scrolling is not an option.
Is this possible by using a Layout or something?
EDIT: Important clarification:
The thing is that I do not have access to the internal elements neither to their properties so I would say that a Layoutmanager capable of resizing child elements to fit to its size is needed. I tested BorderLayout and GridBagLayout but the result is always the same, the internal elements are cut out.
It's for exactly that reason that LayoutManagers exist. All the LayoutManagers work for simple containers directly, excluding GridBagLayout which is to able to handle most complete GUIs directly.
For most complete GUI's you have some choices as follows:
Look for a 3rd party layout such as MigLayout or here
Use GridBagLayout
Very easy way is use nested layout, where there is more than one JPanel and each has child JPanels with the same or different LayoutManager
Or custom layout, should be hard..., but same as using GridBagLayout
You could set the JPanel layout to border layout, then add the single child to the center. If there are multiple children, this approach becomes less useful since components added to the the NORTH, SOUTH, EAST, and WEST will remain statically sized while the centre resizes to fill the remainder.
In short, this isn't an ideal solution. All layouting in Swing is made all the more complex by the fact that different components behave in different ways, so you really need to provide further details of the child components you wish to add to your panel, and any behaviour that has been overridden on those components.
The best way is to try a couple of simple examples to see what mileage you get and whether subtle redesign of your child component nesting could help.
you can use a layout, like GridBagLayout, or BorderLayout depending on the situation. With proper weights it is possible.
this sounds to me like you should just peek an appropriate layout manager and use it. For example, look at BorderLayout - put your component in the CENTER and it will occupy all the area. Its up to each concrete layout manager to decide what will be the size of the components.
Mark
I was using a JInternalFrame inside JDesktopPane. I wanted the internal_frame to auto resize as desktop pane is resized, so I had to implement the AncestorResized event for the internal frame where I placed the following code:
this.setPreferredSize(this.getParent().getPreferredSize());
this.pack();

Change preferredSize of a JLabel after setVisible the JFrame

I have a problem when I try to resize a JLabel. In my application appears the next strucutre. Understand every list item like something inside the previous list item.
JFrame (Layout null, fixed size, not resizeable, used by different people).
JPanel (Layout null, with a size of all the window, the place were I put my work).
various JPanel with different Layouts (the areas of content inside the main panel, you can think about it like html divs...).
Inside one of this "divs" with Layout null there are extended Classes of JPanel with Flow Layout.
Inside every one of this extedend Classes are labels with preferredSizes.
The thing is that when after create all of this i call theFrame.setVisible(true); and all works propertly.
But in a moment of the flow of my application I have to change the size of one of the labels. Then, I simply call label.setPreferredSize(d) and the change doesn't change. The function works propertly if I call it before set visible the frame, but not after.
I have the feeling that the problem is that I don't use nothing like pack(), validate(), repaint(), etc. Because I don't know what it works. I try call repaint and validate to the jlabel, and repaint the main panel, but doesn't works.
I'm relative new with awt and swing, and this is for homework. Sorry for my bad use of English language, and thank you for your help.
After you change the size of your JLabel, call revalidate(). This will cause the JLabel to be resized without waiting for an event that triggers a re-layout (such as resizing the parent Frame, etc...).
JLabel lbl_test;
lbl_test.setPreferredSize(new Dimension(100, 100) );
lbl_test.revalidate();
One other thing to keep in mind, as I'm not certain which class you're having problems with. Null layouts (absolute positioning) mixed with layout managers are going to cause some strange things to happen.

The contents of my JComponent only refresh after a manual resize

I am trying to figure out why my JComponent refreshes when I manually drag my window, but it doesn't refresh when I call repaint or revalidate. The data is ready to be displayed, but it just won't show until I manually resize. Can anybody give some suggestions about what I can do or does this sound like it isn't a Swing problem since I tried repaint and revalidate?
One weird things I've noticed is that if I have this code:
sp.setSize(sp.getSize().width, sp.getSize().height+1);
sp.setSize(sp.getSize().width, sp.getSize().height-1);
If the first line is used, then the JComponent will refresh itself. If I use none or both of these lines it will not, which seems bizarre to me.
I am basically just putting a JPanel in a JInternalFrame in a JDesktopPane. There are two main functions for what I am trying to do. One adds the new JPanel and the other tries to refresh it so the new data will show:
public void addNewSP()
{
sp = new JInternalFrame("SP");
sp.setClosable(true);
sp.setLocation(700, 400); //this should be changed to something based on screen size
sp.setResizable(true);
sp.add(popUp);
this.parentContainer.add(sp, JLayeredPane.DRAG_LAYER);
sp.pack();
sp.show();
sp.setSize(500, 500);
sp.setPreferredSize(new Dimension(500, 500));
}
public void refreshSP()
{
sp.repaint();
sp.validate();
sp.repaint();
sp.validate();
parentContainer.validate();
parentContainer.repaint();
sp.setSize(sp.getSize().width, sp.getSize().height+1);
sp.setSize(sp.getSize().width, sp.getSize().height-1);
}
}
BTW parentContainer is the JDesktopPane
When changing the container's content, you have to call both:
revalidate() to make it recompute the layout for its content
repaint() to request a repaint for this container
but it just won't show until I manually resize.
We don't know the context of your question, which is why a SSCCE should always be posted as suggested earlier.
In general a JComponent, does not have a preferred size, so I'm guessing Swing doesn't think it needs to paint the component. When you resize the frame, chances are the component was added to the center of a BorderLayout so it automatically gets sized to fill the entire space of the frame.
The solution is to give your component a "preferred size" so that any layout manager can use this information to display the component properly.
if your are modifying container's subcomponents you should call jcomponent.validate();
I assume parentContainer is the JDesktopPane?
What kind of changes are you making to sp that are not showing up?
Changing the size of sp will cause Swing to repaint from scratch. That's why the setSize() is fixing the display.
Most likely, the changes you are making are either not happening on the EDT, or are not invalidating the right container. For example, if you change the visibility of a component in sp, you'll need to call sp.invalidate() to rerun the layout manager.
Have you checked that you're only changing components (or their models) on the EDT?
A quick test for that is to run with the Substance LAF as it will complain if you change things on another thread.

Java: Difference between the setPreferredSize() and setSize() methods in components

What is the main difference between setSize() and setPreferredSize(). Sometimes I used setSize(), sometimes setPreferredSize(), sometimes one does what I want, sometimes the other.
What call should I use for JFrames and JPanels?
Usage depends on whether the component's parent has a layout manager or not.
setSize() -- use when a parent layout manager does not exist;
setPreferredSize() (also its related setMinimumSize and setMaximumSize) -- use when a parent layout manager exists.
The setSize() method probably won't do anything if the component's parent is using a layout manager; the places this will typically have an effect would be on top-level components (JFrames and JWindows) and things that are inside of scrolled panes. You also must call setSize() if you've got components inside a parent without a layout manager.
Generally, setPreferredSize() will lay out the components as expected if a layout manager is present; most layout managers work by getting the preferred (as well as minimum and maximum) sizes of their components, then using setSize() and setLocation() to position those components according to the layout's rules.
For example, a BorderLayout tries to make the bounds of its "north" region equal to the preferred size of its north component---they may end up larger or smaller than that, depending on the size of the JFrame, the size of the other components in the layout, and so on.
setSize() or setBounds() can be used when no layout manager is being used.
However, if you are using a layout manager you can provide hints to the layout manager using the setXXXSize() methods like setPreferredSize() and setMinimumSize() etc.
And be sure that the component's container uses a layout manager that respects the requested size. The FlowLayout, GridBagLayout, and SpringLayout managers use the component's preferred size (the latter two depending on the constraints you set), but BorderLayout and GridLayout usually don't.If you specify new size hints for a component that's already visible, you need to invoke the revalidate method on it to make sure that its containment hierarchy is laid out again. Then invoke the repaint method.
setSize will resize the component to the specified size.
setPreferredSize sets the preferred size. The component may not actually be this size depending on the size of the container it's in, or if the user re-sized the component manually.
IIRC ...
setSize sets the size of the component.
setPreferredSize sets the preferred size.
The Layoutmanager will try to arrange that much space for your component.
It depends on whether you're using a layout manager or not ...
In addition to the fact that setSize() should be used in the absence of a layout manager, and setPreferredSize() - when there is no layout manager, there is another difference. 1 takes two numbers in the parameters, and setPreferredSize() takes an object of class java.awt.Dimension:
JFrame frame = new JFrame("Test");
frame.setSize(200,300); //numbers
frame.setPreferredSize(new java.awt.Dimension(200,300)); //an object of java.awt.Dimension

Categories

Resources