i am learning Java at the moment and have the following question:
i am adding my controls to JFrame and then pack() before displaying.
this runs the application and all is very nice.
i was wondering is there a way to stop the user from resizing the application window?
also is there a way to for the image in JLabel to expand as the user changes the application window?
at the moment i have it as:
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.CENTER;
and it only centers the image, i would like to be able to expand/shrink the image.
thanks.
i was wondering is there a way to stop
the user from resizing the application
window?
If you don't want to allow users to resize your window at all then you can do
frame.setResizable (false);
I'm not sure that this technique can be successfully used at the same time with pack(). You should certainly try, but I remember there was an issue that if you do:
frame.setResizable (false);
pack();
then pack() simply doesn't do what it should and if you do:
pack();
frame.setResizable(false);
then you window becomes a little more narrow then after only pack(). Of course, some workaround can be found (or maybe even it's just my bad experience).
for the first question, you can stop the user from resizing your window using the method setResizable(boolean):
frame.setResizable(false);
I don't use GridBagLayout, so I can't help you with the second question.
To prevent resizing the window, you can simply call setResizable(false) on your Window or (J)Frame.
As to the JLabel and image, there is no easy way to make it scale the image according to it's actual size. If you use the label just for the image (no text), it's probably easier for you to implement your own component, in which you paint the image yourself.
also is there a way to for the image in JLabel to expand as the user changes the application window?
Yes you need to create your own LabelUI class and set it to your label via setUI().
In your custom LabelUI class, you will have to override getPreferredSize and paint the imageIcon as you wish.
It is slightly programmatic, you may want to look at source of BasicLabelUI to understand how things are done.( http://www.java2s.com/Open-Source/Java-Document/Apache-Harmony-Java-SE/javax-package/javax/swing/plaf/basic/BasicLabelUI.java.htm )
or
you could over-ride paintComponent() API of JLabel by creating your own extended JLabel class.
Related
I created a jframe, added a jbutton to it, and set the size of the jframe as 500,500 and size of the jbutton as 40,60. However, when I executed my program, my jbutton was covering the whole of my jframe. I
tried many things and looked into many sources, but I could not find a solution.
Please help me solve this.
You're not using a LayoutManager of any kind. The JButton will try to inherit the size of the parent container, as the default for a JFrame is BorderLayout (specifically, BorderLayout.CENTER). You could try using
button.setPreferredSize(x, y);
However I don't think this would be enough by itself. Call getContentPane on the Jframe, and set a layout on that contentPane container (I use FlowLayout a lot, as it respects setPreferredSize). Put your JButton inside that.
This is always a good starting point:
https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
As the methods that you can call on a UI element vary depending on what LayoutManager you're assigning them to (be the child of). Sometimes it's setMinimumSize, sometimes it's setPreferredSize, and sometimes it's a combination.
I am setting a JLabel for the error messages in my program, so initially the label is empty label.setText(""), but when there is an error it should change to something like label.setText("Error, you have entered invalid data...").
If I use setSize(x,y) on the label, it forces other components to displace when error message takes place. But using setPreferredSize(Dimension(x,y))doesn't impact them.
Q1. Why is that?
Q2. What is the difference between setSize(x,y) and setPreferredSize(Dimension(x,y))
Q3. Does it have to do anything with layout?
Thank you in advance for explanation!
P.S. I am using GridBagLayout for positioning my components on the JPanel.
Don’t use the setSize method.
setSize is called by LayoutManagers, like GridBagLayout, to lay out child components. When you call setSize explicitly, you are fighting with the GridBagLayout. Eventually, GridBagLayout will undo your setSize call, when it calls setSize for its own purposes.
In other words, any call to setSize eventually will be wiped out by the parent layout.
setPreferredSize will not be wiped out. Most LayoutManagers, including GridBagLayout, do their best to respect a component’s preferred size.
However, you should not be calling setPreferredSize. Components already have a preferred size by default, and it is almost certainly better than any numbers you can come up with. For instance, a JLabel’s default preferred size is the size which is just large enough to accommodate its text, icon, and borders.
Computing a preferred size is harder than you might think. How many pixels does text use? How many pixels high is a 12 point font? 12 points is not 12 pixels. 12 points is 12⁄72 inch. How many pixels is that? It depends on the user’s monitor and graphics resolution. All of this is known to the Swing rendering system, and JLabel uses all of that information to determine its default preferred size. You should not try to reinvent all of that work, and you should not try to replace that work with something simpler, as it will be inadequate.
If you just let the JLabel keep its preferred size, GridBagLayout will do its best to accommodate that. If the window itself does not have room to display the JLabel’s new text, you probably should call the window’s pack() method after changing the text.
Update: This appears to be an XY problem—you really want a message that you can show and hide.
You want your layout to be big enough to accommodate your message text as soon as you create it. This is typically done with a CardLayout, which lets you place several components on top of each other, with only one of them visible at any given moment. Since you want to show no text at all, initially, you would add an empty JLabel as the first component in the CardLayout, so it is shown by default:
JLabel label = new JLabel("Error, you have entered invalid data...");
CardLayout messageLayout = new CardLayout();
JPanel messagePane = new JPanel(messageLayout);
messagePane.add(new JLabel(), "blank");
messagePane.add(label, "message");
// Do not add label directly to your user interface.
// Add messagePane instead.
mainWindow.add(messagePane);
// ...
// Show message
messageLayout.show(messagePane, "message");
// ...
// Hide message
messageLayout.show(messagePane, "blank");
"message" and "blank" are never seen by the user. They are just unique identifiers for each component (“card”) in the CardLayout. You can make them anything you want.
The setSize() function sets the size not based on any LayoutManager. Thats why you should always use setPrefferedSize() when working with a LayoutManager. setPrefferedSize() firstly tries to be conform with the LayoutManagers dimensions if then possible Java tries to set the size of the Label according to your setPrefferedSize() input.
So yes, it does have anything to do with layout. If possible, you should only use setPrefferedSize() as you are working with layout managers.
While you resize JFrame manually via mouse, elements on JPanel can go on next line if there is no enough space, same time new element-lines can be removed if JFrame is big enough
Example:
at this moment there are two lines to fit all JButtons
If I change JFrame width via mouse, JButtons will drop on next lines:
the problem is you can't see all JButtons, JFrame needs to be resized in height.
How to make JFrame auto resize in height to fit all elements according to set width?
This is not a very good design. Show me another professional application that works like this? People don't like to see the size of frames jump. The user is usually resizing the frame to fit the app on their desktop and will get frustrated if they fix the width and the height changes. Let the user control the size.
If you want all the buttons to display, then maybe a better solution is to just make the frame non resizable by using:
frame.setResizable( false );
frame.pack();
frame.setVisible();
Anyway, if you really want to do this then you would probably add a ComponentListener to the content pane of the frame. Then in the componentResized() method you would invoke pack().
However, this will cause multiple events to be generated every couple of pixels so you may also want to use:
Toolkit.getDefaultToolkit().setDynamicLayout( false );
So that the pack() is only done once when the mouse is released.
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
frame.setSize(400,200);
Ok I gather that every JComponent can set its location...bet it JPanel, JButton, JLabel..whatever. It can set its location use .setLocation(x,y).
I have come to suspect that actually when I do
JButton btn = new JButton("Click me!") ;
btn.setLocation(10,200);
I am actually changing the location of a button in a panel, and not in the frame. And if I do
JPanel jPanel = new JPanel();
jPanel.setLocation(10,100);
I am changing the location of jPanel not in the JFrame but in the default JPanel provided by default. So JComponents can change their locations, why not just dump everything directly into a bloody jFrame object? :S
I haven't tried but I believe I can arrange stuff just by using the setLocation(x,y) method..and I guess that'd be a big pain the butt.
This leads to my question..if we can set components location by using the method, what is the LayoutManager for?
Can you please provide example to show the difference?
Can you please provide example to show the difference?
Here is an example of using layouts, as well as a challenge.
The challenge is to make a resizable, PLAF changable version of that UI using setLocation()/setBounds().
If you (or anyone) can manage it (in code that is small enough to post to the thread), I'll contribute 500 bounty points to the answer.
I have a JFrame inside of which is a jpanel that im using as the content pane.
So basically im using the jpanel to load content into on click. New content is returned as a Jpanel also so its ends up being jpanel -> inside jpanel -> inside Jframe. When i need to load in new content i clear the panel, load the new content and validate() the jframe & jpanel and the new content displays.
My problem is that when the new content displays its clear that the validate method is working because i can see the new interface but i can also see the old interface as if its become the background; i can resize the window and it just disappears and looks as it should.
Is this just the way validate works or can i fix it?
Edit: this worked. The problem was i wasn't calling repaint manually.
public BaseWindow setContent(JComponent comp){
contentPane.add(comp);
contentPane.revalidate();
contentPane.repaint();
return this;
}
Generally the code for adding/removing one or two components from a panel is:
panel.remove(..);
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes needed
However, if you are replacing all the components on the panel, then the better approach is to use a Card Layout.
You have already stated the revaliate() followed by repaint() doesn't work so the only suggestion I have is to post your SSCCE that demonstrates the problem.
Don't use validate. Use revalidate() instead.
Revalidate first calls invalidate() followed by a validate().
In Swing, you would rarely use validate().
Note: I also feel that maybe the old panel is not cleared/removed.Check again!
Validate() is for causing components to re arrange themselves according to the layoutmanager that you have installed. This is not really what you should be using.
I can't see your code, so I'm not sure exactly what you are doing. I could speculate that calling repaint() on your "inner panel" will solve the problem you are having...but really, if you are doing things properly, you shouldn't need to call repaint() or validate().
Make two JPanels, one with content A (e.g. your buttons), and one with content B (e.g. your "static" field). Use the "add()" and "remove()" methods on the parent container (the JFrame's content pane?) to swap these two JPanels with each other whenever you want to switch the content that is displayed in that part of the JFrame.
Then you shouldn't need to do anything else; it should just work.
I don't know if validate() makes any promise about fully repainting the container. You might have to call repaint() yourself to make it behave as you want to.
Here's another possible solution:
Put both JPanels in at the same time, side by side, and then make sure only one of them is ever visible at any one time:
JPanel p = new JPanel(new BorderLayout());
p.add( panelA, BorderLayout.EAST );
p.add( panelB, BroderLayout.WEST );
panelA.setVisible(true);
panelB.setVisible(false);
Then when the user clicks the button to switch panels:
panelA.setVisible(false);
panelB.setVisible(true);
The setVisible() method and BorderLayout should take care of validating, layout, and calls to repaint() for you.
I ended up fixing my issue (display not shown, buttons would stay clicked/weren't unclicking) by changing which panels were added/removed.
Problem:
frame.removeAll();
frame.add(getNewPanelDisplay());
frame.revalidate();
frame.repaint();
Solution:
//initializer()
mainPanel = new JPanel();
frame.add(mainPanel());
// ...
//update()
mainPanel.remove(0);
mainPanel.add(getTablePanel(), 0);
frame.revalidate();
frame.repaint();