Java JPanel subclass ignores bounds on adding components - java

I have a subclass of JPanel that I'm trying to add labels to
for(int i = 0; i < 10; i++)
{
JLabel lblPID = new JLabel("" + i);
lblPID.setBounds(55, i * 50, 15, 15);
this.add(lblPID);
}
But when this runs, the labels line up horizontally next to each other at the same y point, ignoring the bounds I'm setting. How do I have the panel lay them out vertically the way they're supposed to appear?

The likely problem is, the container you are adding your label to is using a layout manager, which is making it's own decisions about how your label should be laid out.
You should avoid using setBounds as you can not guarantee that the label will be rendered the same on different computers, even if they are running the same OS. Instead you should make use of appropriate layout managers, which make these decisions for you.
Take a look at Laying out Components within a Container for more details

Related

Java JPanel Layout

Im new in Java Swing, and want to make my layout, but can't do this
Look Now :
Look I want :
Code Now :
JPanel MainPanel = new JPanel(new GridBagLayout());
JLabel MoneyLabel = new JLabel(MoneyIcon);
MoneyLabel.setHorizontalTextPosition(JLabel.CENTER);
MoneyLabel.setVerticalTextPosition(JLabel.BOTTOM);
MoneyLabel.setText("Money:" + CarMain.Money);
JLabel MoneyClicksLabel = new JLabel();
MoneyClicksLabel.setHorizontalTextPosition(JLabel.CENTER);
MoneyClicksLabel.setVerticalTextPosition(JLabel.BOTTOM);
MoneyClicksLabel.setText("Money Clicks: " + CarMain.MoneyClicks);
JLabel BoxesLabel = new JLabel(BoxLv9_10Icon);
BoxesLabel.setHorizontalTextPosition(JLabel.CENTER);
BoxesLabel.setVerticalTextPosition(JLabel.BOTTOM);
BoxesLabel.setText("Boxes: " + CarMain.Boxes);
JLabel BoxesClicksLabel = new JLabel();
BoxesClicksLabel.setHorizontalTextPosition(JLabel.CENTER);
BoxesClicksLabel.setVerticalTextPosition(JLabel.BOTTOM);
BoxesClicksLabel.setText("Boxes Clicks: " + CarMain.BoxesClicks);
MainPanel.add(MoneyLabel);
MainPanel.add(MoneyClicksLabel);
MainPanel.add(jbtnMoney);
MainPanel.add(BoxesLabel);
MainPanel.add(BoxesClicksLabel);
MainPanel.add(jbtnBoxes);
This is simple example of, what i want, becouse i'm building ingame shop, with 13 labels like these, in each tabbedpane window. How can i make it look, like in second picture, what I want?
Im new in Java Swing, and want to make my layout, but can't do this
Probably no single layout can suit everyone's needs. But combining several layouts can usually handle most scenarios.
From the image you showed in the question. There is no need to write your own layout. You can always use sub panels to hold your components and set a specific layout for each sub panel to handle what you need for those individual areas.
The reason for the alignment in your first attached image is because:
JPanel uses FlowLayout as its default layout. Hence all the components added will appear in a linear fashion and tries to fill up the row as much as possible the panel's width can hold. Once exceeded the panel's width, the components will be pushed to the next row.
If you want to achieve the alignment in the second attached image:
You may create a main panel to contain several sub-panels (see image below).
The red box is your main panel and you may continue to use the default FlowLayout.
Then add your components into sub-panels (orange boxes) before adding it to the main. You may then use BoxLayout, FlowLayout or even GridBagLayout for the sub panels (orange boxes).
Artis Uljanovs, at night after work i will give a look at this to help you.
I recommend you already to read the following: https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
You need some foundations on Java Layouts.

Java - Draw a circle ON JButton and JTextArea

So I'm trying to draw a sort of oval on a button and textarea. Yes, there is a reason why I can't just use a Panel or Frame.
So the button and textarea already has text on it and needs to stay as a button and textarea for the reason of the program.
So far, I only got one button to have this circle, but none of the other buttons show up with the circles. And the textareas aren't showing any circles at all.
My Code so Far for the buttons:
for (int i = 0; i < (label.length) / 2; i++) {
butt = new JButton(label[i]); // label contains the text on button
butt.setPreferredSize(new Dimension(83, 100));
butt.add(smallPit); //smallpit is the circle graphics
game.add(butt); // game is a panel
// butt.setLayout(null);
}
for (int i = 6; i < label.length; i++) {
butt = new JButton(label[i]);
butt.setPreferredSize(new Dimension(83, 100));
butt.add(smallPit);
game.add(butt);
}
Code for textarea
score2.setBounds(0, 50, 100, 210);
score1.setBounds(700, 50, 100, 210);
score2.add(scorePit);
score1.add(scorePit);
The outcome so far:
My guess is that this butt.add(smallPit); is causing your issues.
My guess is that smallPit extends from something like JComponent (something that extends from JComponent), the problem is a component can only reside within a single container, so each time you call butt.add(smallPit);, smallPit is removed from it's previous container before been added to the new one.
Instead, create an instance of smallPit (or what ever it is) and add it to each button which needs it.
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
You should also have a look at Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

JPanel above JLabel using Layered Panes

I have a JPanel that contains a bunch of small icons, and a JLabel containing a bigger icon.
First of all, I need clarification on something. By not setting panel.isOpaque, the said panel would have a transparent background and would properly overlap the icons of my JPanel and JLabel. Is this true?
Now to my problem. I've been following the LayeredPanes tutorial on the Oracle website, and I can't seem to make it right on my case.
JFrame window = new JFrame();
ImageIcon underIcon;
URL urlUnder = myClass.class.getResource("images/underImage.gif");
underIcon = new ImageIcon(urlUnder);
JLabel labelUnder = new JLabel(underIcon);
ImageIcon panelIcon;
URL urlAbove = myClass.class.getResource("images/aboveImage.gif");
panelIcon = new ImageIcon(urlAbove);
JLabel aboveIcon1 = new JLabel(panelIcon);
JLabel aboveIcon2 = new JLabel(panelIcon);
JPanel panelAbove = new JPanel(new BorderLayout());
panelAbove.setOpaque(false);
panelAbove.add(aboveIcon1, BorderLayout.WEST);
panelAbove.add(aboveIcon2, BorderLayout.EAST);
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setLayout(new BorderLayout());
layeredPane.add(labelUnder, BorderLayout.CENTER, 1);
layeredPane.add(panelAbove, BorderLayout.CENTER, 2);
layeredPane.setOpaque(true);
window.setContentPane(layeredPane);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();
window.setVisible(true);
I only see the contents of the panel. And I'm 100% sure the images are there on getResource, so that's not the issue. Please advice on how to properly use Layered Panes.
The problem is you are setting a layout manager to the JLayeredPane
layeredPane.setLayout(new BorderLayout());
In of it self, this is not a problem, but your choice of layout manager is.
BorderLayout will only a single componet to occupy any of it's 5 predefined positions. This means when you add your second component, it, effectively, replaces the first.
Try using someone like GridBagLayout instead. Providing a single GridBagConstaint set so that the weightx/y values ara equal to 1, the fill property is set to BOTH and it's gridx/y properties are set to 0
Unlike BorderLayout, GridBagLayout will allow you to layout components to the same position
From the Java Tutorial:
layeredPane.add(dukeLabel, new Integer(2), 0);
This code uses the three-argument version of the add method. The third argument specifies the Duke label position within its depth, which determines the component's relationship with other components at the same depth.
Positions are specified with an int between -1 and (n - 1), where n is the number of components at the depth. Unlike layer numbers, the smaller the position number, the higher the component within its depth. Using -1 is the same as using n - 1; it indicates the bottom-most position. Using 0 specifies that the component should be in the top-most position within its depth. As the following figure shows, with the exception of -1, a lower position number indicates a higher position within a depth.
So your depth orders are the wrong way around, also start from 0.
I also found this in the Solving Common Component Problems Section
Problem: The components in my layered pane are not layered correctly. In fact, the layers seem to be inversed — the lower the depth the higher the component.
This can happen if you use an int instead of an Integer when adding components to a layered pane. To see what happens, in the LayeredPaneDemo class, change
layeredPane.add(label, new Integer(i));
to
layeredPane.add(label, i);.

Nested JPanel with GridBagLayout

I have a JFrame with GridBagLayout. weightx and weighty values are assigned different no-zero values and GridBagConstraints.fill = GridBagConstraints.BOTH. I nested a JPanel in one of the cells and gave it a GridBagLayout too. When adding components to the nested JPanel, the cell size where the nested JPanel resides grows on all sides missing up the parent's layout. Insets and padding are not used. How can I fix this problem?Thanks.
This is an example of the GridBagConstraints values:
GridBagConstraints treePanCon = new GridBagConstraints();
treePan.setLayout(treePanGridbag);
treePanCon.fill = GridBagConstraints.BOTH;
treePanCon.weightx = 0.5;
treePanCon.weighty = 1;
treePanCon.gridx = 0;
treePanCon.gridy = 0;
treePanCon.gridwidth = 1;
treePanCon.gridheight = 1;
This is a screenshot before adding components to the nested JPanel:
This a screenshot after adding components to the nested JPanel:
That's exactly what is supposed to happen. Please explain the behavior you're looking for. As an aside the layout managers available with J2SE are less than ideal. Having done a large amount of Swing work in a past life I would highly recommend checking out JGoodies forms: http://www.jgoodies.com/freeware/forms/. Check out the whitepaper, it's easy to use and much more intuitive than GridBag.
This is probably of absolutely no use to you at this late date, but...
It looks like you probably used BOTH when laying out the two new buttons.
If the preferredSize.width on the tree is the width you want for the inner panel,
and you wanted the two new buttons to each be half the width of the tree,
set their preferredSize.width to half the preferredSize.width of the tree, and use NONE on the two buttons.
Use VERTICAL on the tree in the inner panel.
Use VERTICAL on the inner panel in the outer panel.

Why will BoxLayout not allow me to change the width of a JButton but let me change the height?

I'm trying to get the Layout of a JDialog of mine to fit a particular look that a program in which I'm porting to Java has, I've used several LayoutManagers before with great success yet for some reason I cannot seem to get this working at all. My goal is to have the Right (East) side of the JDialog contain a "Find Next" and "Cancel" button in a top-down order and then any extra space below so that the two buttons are always at the top of the JDialog, yet for some reason BoxLayout is continously ignoring any attempts at changing (this is where I'm lost) the width of a JButton. Code follows.
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
cancel.setPreferredSize(new Dimension((int)findNext.getPreferredSize().getWidth(),
(int)cancel.getPreferredSize().getHeight()));
JPanel example = new JPanel();
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
example.add(cancel);
example.add(Box.createGlue());
No matter what I try, cancel always retains it's normal size. I've tried setMinimumSize() and setMaximumSize() with the same parameters as setPreferredSize with no luck. I've even tried cancel.setPreferredSize(new Dimension(500, 500)); and the buttons height was the only thing adjusted, it STILL retained the default width it was given.
To clear up any questions, here is what it looks like (now that I've finished it) and you'll see that the "Find Next" and "Cancel" buttons are not the same size.
I know this is an old question but I don't really see a good explanation. So for the sake of searchers that stumble upon this I will add my two cents.
There are three methods associated with sizing components in Swing: setPreferredSize(), setMinimumSize(), and setMaximumSize(). However, the important point is that it is up to the particular layout manager being used as to whether or not it honors any of these methods.
For BoxLayout (the layout the original poster is using):
setMinimumSize() -- BoxLayout honors this
setMaximumSize() -- BoxLayout honors this
setPreferredSize() -- if X_AXIS is being used width is honored, if Y_AXIS is being used height is honored
The OP is using a Y_AXIS BoxLayout which is why only his height was being changed.
Update: I put together a page with this same information for all of the layout managers. Hopefully it can help some searchers out: http://thebadprogrammer.com/swing-layout-manager-sizing/
You may not want Box.createGlue(), which "grows as necessary to absorb any extra space in its container." Instead, use Box.createVerticalStrut() between the buttons, as shown below and in the ControlPanel of this simulation.
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
Box.createVerticalStrut(10);
example.add(cancel);
Addendum:
adding in setMaximumSize() made it work.
This is the expected behavior for components having identical maximum widths in a vertical BoxLayout, as described in Box Layout Features. The preferred width of the container becomes that of the (equally wide) children, and the X alignment becomes irrelevant.
example.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
Dimension d = findNext.getMaximumSize();
cancel.setMaximumSize(new Dimension(d));
example.add(findNext);
example.add(cancel);
As mentioned in the comments on the question, you were able to fix it by switching to setMaximumSize(). However, as you noted, setPreferredSize() doesn't work. So, what's up with that?
With many things Swing, the properties used to determine the actual component size when using the BoxLayout are somewhat random (in my opinion). When determining how to render the components, Swing calls layoutComponent() on the layout manager, which is figures out where to position everything.
BoxLayout's implementation of layoutComponent() involves a call to a method that creates SizeRequirements objects for the width and height of each of the components you add to the JPanel, based on their getMinimum/Preferred/MaximumSize() methods.
Later, it calls SizeRequirements.calculateAlignedPositions() for determining the correct width values for each component, because your orientation is BoxLayout.Y_AXIS (The heights are calculated using a different method). Taking snippets from the source, the relevant implementation of this method is as follows:
for (int i = 0; i < children.length; i++) {
SizeRequirements req = children[i];
//...
int maxAscent = (int)(req.maximum * alignment);
int maxDescent = req.maximum - maxAscent;
//...
int descent = Math.min(totalDescent, maxDescent);
//...
spans[i] = (int)Math.min((long) ascent + (long)descent, Integer.MAX_VALUE);
}
Note that totalDescent is the available width, so descent is always set to maxDescent, which is based on SizeRequirements.maximum, which was taken from JButton.getMaximumSize(). The value of spans[i] is then used later in a call to JButton.setBounds() as the width. As you'll note, getPreferredSize() was never involved here, which is why setting it has no impact in this case.
Usually if want to ensure a size of the component in Swing you need to call setMinimumSize(), setMaximumSize(), and SetPrefferedSize() with the same value.
button.setMaximumSize(getMaximumSize());
If you put your buttons in a GridLayout panel they will be the same width.

Categories

Resources