0

I have a JPanel with one JLabel, two JButtons and a GridBagLayout as the layout manager. The problem that I now have is that when I add all the components to the panel (using the GridBagConstraints of course) only the label is fully displayed and all of the buttons are cut off. Half of the text on the buttons is missing and they're way smaller than they're supposed to be. Even when I try to specify the size of the buttons inside my code with

.setSize(new Dimension(width / 2, 100))

it still does not work.

Here's the relevant code of my panel:

public class StartPanel extends JPanel {
 private int width = 32 * 32;
 private int height = 32 * 18;
 // Buttons
 private JButton[] buttons;
 private JButton startButton;
 private JButton exitButton;
 // Label
 private JLabel titel;
 // Andere Objekte
 private PassivThread passivThread;
 private GridBagLayout gbl;
 private GridBagConstraints gbc;
 private Fenster fenster;
 public StartPanel(PassivThread passivThread) {
 this.passivThread = passivThread;
 setPreferredSize(new Dimension(width, height));
 setBackground(Color.black);
 gbl = new GridBagLayout();
 gbc = new GridBagConstraints();
 setLayout(gbl);
 loadObjects();
 buttonEvents();
 setVisible(true);
 }
 // Hier werden die Objekte platziert
 private void loadObjects() {
 startButton = new RoundedBorder("Spiel starten", 75);
 exitButton = new RoundedBorder("Zurück zum Desktop", 75);
 buttons = new JButton[2];
 buttons[0] = startButton;
 buttons[1] = exitButton;
 Font font = new Font("Monospaced", Font.BOLD, 40);
 titel = new JLabel("Jump 'n' Run");
 titel.setFont(font);
 titel.setForeground(Color.red);
 titel.setVisible(true);
 gbc.gridx = 0;
 gbc.gridy = 0;
 gbc.gridheight = 2;
 gbc.insets = new Insets(20, 0, 20, 0);
 add(titel, gbc);
 for (int i = 0; i < buttons.length; i++) {
 buttons[i].setForeground(Color.white);
 buttons[i].setBackground(null);
 buttons[i].setFont(font);
 buttons[i].setBorder(null);
 buttons[i].setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
 buttons[i].setSize(new Dimension(width / 2, 50));
 gbc.gridheight = 1;
 gbc.gridy = 2 + i;
 add(buttons[i], gbc);
 }
 }
}

And an example of what I mean:

Buttons not fully displayed

Abra
21k14 gold badges106 silver badges75 bronze badges
asked May 22, 2024 at 6:47
5
  • I have solved the porblem myself; I used a roundedBorder button, instead of a normal one. I switched the buttons and now it's working. Commented May 22, 2024 at 7:11
  • 2
    BTW posted code, with addition of missing parts, is working for me: i.sstatic.net/3KMc7ozl.png -- consider including a minimal reproducible example in future postings like this Commented May 22, 2024 at 7:42
  • As stated in this comment, code in your question is also working for me - after commenting out references to missing classes, including PassivThread, Fenster and RoundedBorder. Specifically, I replaced RoundedBorder with JButton so the problem could be in class RoundedBorder. Commented May 22, 2024 at 9:55
  • I agree with @user85421: this question will need a minimal reproducible example to be potentially a useful question and answer on this site. Commented May 22, 2024 at 12:11
  • I used a roundedBorder button - that should not cause a problem if the Border is implemented correctly. The getBorderInsets() methods needs to be implemented correctly. Commented May 22, 2024 at 13:49

2 Answers 2

2

This happens when you assume a particular size of rendered text.

Your code contains this:

Font font = new Font("Monospaced", Font.BOLD, 40);

What does that 40 mean, exactly? It means you are creating a 40-point font.

And what is a 40-point font? What does "40 points" mean? A point is a typographic measurement. It has a very specific size in print media, but when it comes to screen graphics, it means exactly 1⁄72 inch. A 40 point font is a font where one line of text is 40⁄72 inch high.

How many pixels does it take to display characters of a font that size? How many pixels are in one inch?

The answer depends on the video mode of the desktop where the program is running, and the dot pitch of the monitor where the program’s window is displayed. (And probably the desktop system’s display scaling, as well, at least in Windows.)

That’s a nontrivial bit of math, isn’t it? You could do all that math yourself... but you don’t have to. Swing already does it for you. All of that math is already done, and is made available in the default preferred size of any component which displays text, including JButtons and JLabels.

Furthermore, most layout managers will respect those preferred sizes, and will set a container’s preferred size based on the child components’ preferred sizes.

Assuming an exact pixel size for any of these computations is basically guessing. As you have seen in the comments, it works for some people, but not for others. Your hard-coded dimensions are correct on some monitors and desktops, but incorrect on others.

To take advantage of the correct computed size provided by Swing, all a program has to do is... avoid overriding the default preferred size of each component. Normally, a program does this by never calling setSize or setPreferredSize, and instead calling pack() on the containing window.

Here is a short demo version that creates a panel similar to yours:

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.Color;
import java.awt.Font;
import java.awt.Cursor;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
public class StartPanel {
 private JPanel panel;
 private JButton startButton;
 private JButton exitButton;
 public StartPanel() {
 startButton = new JButton("Spiel starten");
 exitButton = new JButton("Zurück zum Desktop");
 JButton[] buttons = { startButton, exitButton };
 Font font = new Font("Monospaced", Font.BOLD, 40);
 JLabel titel = new JLabel("Jump 'n' Run");
 titel.setFont(font);
 titel.setForeground(Color.red);
 panel = new JPanel(new GridBagLayout());
 panel.setOpaque(true);
 panel.setBackground(Color.BLACK);
 GridBagConstraints gbc = new GridBagConstraints();
 gbc.gridx = 0;
 gbc.gridy = 0;
 gbc.gridheight = 1;
 gbc.insets = new Insets(20, 0, 20, 0);
 panel.add(titel, gbc);
 for (JButton button : buttons) {
 button.setForeground(Color.white);
 button.setBackground(null);
 button.setFont(font);
 button.setBorder(null);
 button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
 gbc.gridy++;
 panel.add(button, gbc);
 }
 }
 public void showInWindow() {
 JFrame frame = new JFrame("Start");
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame.getContentPane().add(panel);
 frame.pack();
 frame.setLocationByPlatform(true);
 frame.setVisible(true);
 }
 public static void main(String[] args) {
 EventQueue.invokeLater(() -> new StartPanel().showInWindow());
 }
}

Notice there are no calls to setSize or setPreferredSize. This allows Swing to accommodate the size of the text, for any and all displays it may run on.

Some other notes:

  • setVisible is not needed. All components are visible when they are created, except for instances of Window and its subclasses.
  • GridBagLayout uses grid-based alignment, but its grid is flexible. It is not a regular grid. The rectangular cells of the grid are not all the same size. So, when you say gbc.gridheight = 2, you are not laying out components so they will be twice as high as components with gridheight=1. GridBagLayout makes each grid cell as wide and as high as necessary to accommodate its child components, nothing more.
  • It is not a good idea to subclass Swing or AWT component classes unless necessary. Usually the only reason to do so is to override the paintComponent method, which obviously is not necessary here. Inheritance should be used only when necessary, not whenever possible.
answered May 22, 2024 at 17:00
Sign up to request clarification or add additional context in comments.

Comments

0

I have solved the porblem myself; I used a roundedBorder button, instead of a normal one. I switched the buttons and now it's working.

answered May 22, 2024 at 7:11

3 Comments

buttons[i].setSize(new Dimension(width / 2, 50)); this isn't great practice. The component should know it's own size so the layout manager can work.
I know and I already deleted it. I still had it left in my code to test something and for an older button design I used.
Not only isn't it a great practice, it does nothing of use, since GridBagLayout, like most standard layouts, ignores a button's size and instead better respects its preferred size. Usually this sort of problem occurs if you artificially constrain the size of things in other ways, perhaps the size of the GUI window, but who is to say?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.