my question is simple but I can not find exact solution for this. I try to write a program with Java GUI, I use absolute layout for my program and I set frame bounds(100, 100, 450, 300) . When I run the program and make it full screen, components stays on their places. I want them to replace automatically according to screen size.
All supports are accepted, thank you!
The solution is quite simple. You state, "I use absolute layout for my program and I set frame bounds(100, 100, 450, 300)." Don't do this. Use the layout managers to help you place your components.
For instance, if you used a BorderLayout for the main JPanel, and added the JButton to a new GridLayout(0, 1, 0, 5) using JPanel (1 column, variable rows, 5 spaces between rows), adding this JPanel to main in the BorderLayout.LINE_END position, your problem is likely solved. As a general rule, you should avoid use of null layout and use of setBounds(...) for component placement as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.
Related
I am trying to create a new JTextField in my Jframe. I want to play around with the positioning of the textfield. I tried using setBounds and setLocation to change the position of the text box but it doesn't change the location of the text box at all.
This is my code:
public class GUI_Tutorial extends JFrame {
public static void main(String[] args) {
GUI_Tutorial frame = new GUI_Tutorial();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(1000, 800);
frame.setVisible(true);
frame.setTitle("Calculator");
frame.setLayout(new FlowLayout());
}
public GUI_Tutorial() {
//frame.setLayout(new FlowLayout());
JTextField num1;
num1 = new JTextField(10);
add(num1);
num1.setVisible(true);
num1.setLocation(5, 5);
}
}
May I know what am I doing wrong?
Your problem is one of layout managers. When you add a component to a container, the layout manager will dictate where the component will go. A JFrame's contentPane (the JFrame sub-container that holds its components) uses a BorderLayout by default, and items added to this container in a default manner will fill the central portion of the container, will fill it completely if nothing else is added to other BorderLayout locations.
Possible solutions for placing items:
The worst suggestion, use a null layout. You would do this by calling getContentPane().setLayout(null);. But when you do this, you the programmer are 100% responsible for the exact position and size of all components added. This leads to hard to maintain GUI's that might not even work on other platforms -- so don't do this.
Use a GUI builder to help build your program: this has definite advantages, one being that it shields you from having to directly understand the layout managers, but this also is a disadvantage, because once you run into edge cases (and you usually will and quickly) that knowledge is essential. My own view is to initially avoid using this so as to better understand the layout managers, and then once you're familiar with the managers, then sure use this as needed.
Better is to learn and experiment with the layout managers, and Borders, playing with placement of components. Remember that you can nest containers (usually JPanels) and each can be given its own layout manager, allowing for complex GUI's that are created easily and maintained easily.
Note that
(again) JFrames (actually their contentPanes), JDialogs, and other top-level windows use BorderLayout by default, that JPanels use FlowLayout by default, that JScrollPanes use their own specialty layout, one that you will likely never want to muck with, and that most other components/containers, such as JComponent, JLabel,... have null layouts by default.
Best resource is the tutorial: Lesson: Laying Out Components Within a Container
Borders can also be useful here, especially the EmptyBorder which can allow you to put a blank buffer zone around your components.
Start playing with the simpler layout managers, FlowLayout, BorderLayout, GridLayout, then BoxLayout, before moving to the more complex
Try removing frame.setLayout(new FlowLayout());. You'll then need to use num1.setBounds(x, y, width, height) rather than setLocation()
But, as other users have pointed out, you should be using a layout manager. Read up on the different layouts and choose the best one for your GUI.
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.
I have a class that extends from JFrame.
In its constructor I generate a JPanel:
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.BLACK);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JOptionPane.showMessageDialog(contentPane, contentPane.getBounds());
I thought with setContentPane, I would fill the whole available space in my JFrame. So it automatically sets the bounds of the JPanel.
I need to get the bounds of the JPanel, but getBounds() returns x = 0, y = 0, width = 0, height = 0.
Other size related methods of the JPanel (like getWidth() etc.) also return 0. If I setBounds() of my JPanel explicit, the methods return my given values.
The curious thing about that is, that the setBackground fills the whole available space in my JFrame. So, the size of my JPanel must be exactly the size of my JFrame. But it doesn´t seem so.
Maybe this problem is caused by the layout manager, like most Container-related problems. But with a layout manager, I also get 0.
I think this is a very dumb question and can be easily solved, but I can´t figure out the problem.
I didn´t find an answer to this in the web, so hopefully didn´t dublicate some post.
The curious thing about that is, that the setBackground fills the whole available space in my JFrame. So, the size of my JPanel must be exactly the size of my JFrame. But it doesn´t seem so.
Actually no, the content pane will be smaller then the frame, because it's contained within the frame decorations. That means the viewable space is the size of the window - the size of the decorations.
Also, a component won't be painted until its sized beyond 0x0
Before the contentPane can know how big it will be, it needs to be laid out by it's parent container. In order for the parent container to lay out the child container(s), it needs to know the size they might like to be.
As you say, this is related to the layout managers, in order for container to know how big it can be, it needs to know how much space it's parent container will give it.
Maybe this problem is caused by the layout manager, like most Container-related problems. But with a layout manager, I also get 0.
A container, even under the management of a layout manager, won't be assigned a size until the parent container is sized appropriately.
While there are several ways to overcome this, the question becomes why? The fact that you're setting the contentPane's layout manager to null is worrisome and would suggest that you're now going to need to reinvent the wheel and replace the job that the layout managers do for you anyway.
I would suggest calling pack before you try and get the component size, but, again, because you've negated the layout manager, this won't result in a value you would be happy with...
Presumably as this is in your main frames constructor you haven't called setVisible(true) on the main frame (the top level window) when you call JOptionPane.showMessageDialog?
If so then the GUI components haven't yet been rendered, so they have bounds of [0, 0]. If you move JOptionPane.showMessageDialog to after setVisible you'll get a dimension.
Alternatively you could call pack to lay things out. As per my comment below you would call contentPane.setPreferredSize(new Dimension(width, height)); before you do this.
I've made a java application in netbeans and am wondering how to have the size of the jframe half the width and height of the computer resolution and also having the components comply with this change. I tried putting code and it did make the frame half the height of the computer resolution but my components, such as buttons and textfields, stopped showing. How can I achieve this? Thanks.
(EDITED)
Set the JFrame's layout manager to GridLayout. In the properties window of the GridLayout itself (select in the navigator window) set columns to 1 and rows to 2. This should give you what you want and you won't have to get into the code.
This is the key code being called within the initComponents() method of your JFrame subclass (created by NetBeans) but it is important to understand where it is:
getContentPane().setLayout(new java.awt.GridLayout(2, 1));
I love Netbeans but you do have to understand the basics.
Good luck with your project. Swing is an awesome toolset that was way ahead of it's time.
As usual in this situation the key is using the right combination of layout managers for your containers. You're probably using NetBeans generated code (something I recommend you avoid until you are very comfortable with Swing coding), and it's probably having you use GroupLayout, a fine layout, but one that might not behave as well as you'd like on resizing components. I suggest that you go through the layout manager tutorial and try to nest JPanel containers and play with different layouts that re-size well such as GridLayout, GridBagLayout and BorderLayout to try to create the best layout that can re-size well.
There are three different kinds of panel each spanning different number of grids. 1*3 , 1*1 , 3*1 .
add(panel1, "span 1 3,push, grow");
add(panel2, "push, grow");
add(panel3, "span 3 1,push, grow");
I want to change first panel's constraint to "span 1 2" when it overlaps with other panel on the screen. But to find out whether it overlaps with another panel I have to know it's bounds.
I did not set any size constraints.
Is there any way , to know 'the bounds before the panel/component is actually displayed'?
And also, how to know the length of the rows and columns set by the MigLayout manager?
Actually I want to cover the full screen with these differently sized panels.
EDIT :
I forgot to enter the main culprit ...add(lastPanel, span, push, grow)
I am trying to cover the full screen with differently sized panels. This code works for even number of rectangles but not for odd. When they are odd in number, then the last grid is always left empty . So I spanned the last panel to cover the full empty available space, but then it overlapped with the 3*1 panel.
I can think of a couple of ways, not really nice or pretty and all suffer from the same issue.
Layouts can occur repetitively in succession (that is you will be clobbered with a number of request to layout the container in quick succession)
The trap is trying to figure out when it's come to stop. The next problem is known when you've caused it.
You "could" override the parent Containers doLayout method, after you've called super.doLayout you will have access to the resulting layout. This is not the best solution as it requires you to implement the Container which you may not want to to.
The other solution I can think of is using a ComponentListener on panel1 on monitor the componentResized event.
I would seriously play around with these and see what trouble you're getting yourself into. A better solution is to try and work out your layout issues ahead of time.
JPanel (by default valid for every Swing JComponents) returns its Size or Bounds in two cases
if is once time visible on the screen
after pack() to the Top-Level Container
there no reason to know any of this value for Standard LayoutManagers, nor for MigLayout,
I got this similar problem again but this time I got the answer, I might be helpful for someone, so I am posting it here.
addAncestorListener(new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
height = getHeight();
width = getWidth();
//Modifications to the components here.
}
I wanted the dimensions set by the LayoutManager at compile time (which was not possibe). The AncestorListener did the trick, as soon as the components were laid out on the screen . It captures the dimensions and modified the components accordingly.