我正在使用Swing设计Java应用程序,而在设计没有布局的GUI时遇到了麻烦。
我的目的是设计一个包含一个JPanel
和四个JButton
的GUI。我已经完成数学运算,将按钮和面板设置在正确的位置,并且编码如下:
import java.awt.*;
import javax.swing.*;
public class MainFrame extends JFrame {
public MainFrame() {
this.setTitle("Example Frame");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
JPanel randomPanel = new JPanel();
randomPanel.setOpaque(true);
randomPanel.setBackground(Color.RED);
randomPanel.setBounds(10, 10, 430, 530);
JButton addButton = new JButton("Add");
addButton.setBounds(10, 550, 100, 40);
addButton.setBackground(Color.GRAY);
JButton deleteButton = new JButton("Delete");
deleteButton.setBounds(120, 550, 100, 40);
deleteButton.setBackground(Color.GRAY);
JButton refreshButton = new JButton("Refresh");
refreshButton.setBounds(230, 550, 100, 40);
refreshButton.setBackground(Color.GRAY);
JButton devButton = new JButton("Developer");
devButton.setBounds(340, 550, 100, 40);
devButton.setBackground(Color.GRAY);
this.add(randomPanel);
this.add(addButton);
this.add(deleteButton);
this.add(refreshButton);
this.add(devButton);
this.setSize(900, 600);
this.setResizable(false);
this.setVisible(true);
}
public static void main(String[] args) {
new MainFrame();
}
}
按照代码,组件应放置如下:
但是,实际的表单显示如下:
组件超出,与预期外观不匹配。
这是什么问题,应该如何正确放置组件?
答案 0 :(得分:1)
主要有两个问题...
setLayout(null)
setSize
您没有考虑的事实是,窗口内容可用的空间量就是窗口的大小减去框架装饰。
像素完美布局是现代UI开发中的一种幻觉,最好避免。
您可以看一下:
了解更多详情。
更好的解决方案是使用一个或多个可用的布局管理器。以下示例仅在BorderLayout
的帮助下使用GridLayout
和EmptyBorder
来提供一些填充
有关更多详细信息,请参见Laying Out Components Within a Container
好处
pack
自动“包装”内容周围的窗口,而无需使代码适应当前运行的OS(或不同外观提供的框架修饰)可运行的示例...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new SizablePane(430, 530));
JPanel buttonPane = new JPanel(new GridLayout(1, 3, 20, 0));
buttonPane.setBorder(new EmptyBorder(10, 0, 0, 0));
buttonPane.add(new JButton("Add"));
buttonPane.add(new JButton("Delete"));
buttonPane.add(new JButton("Refresh"));
buttonPane.add(new JButton("Developer"));
add(buttonPane, BorderLayout.SOUTH);
}
}
public class SizablePane extends JPanel {
private Dimension size;
public SizablePane(int width, int height) {
size = new Dimension(width, height);
setBackground(Color.RED);
}
@Override
public Dimension getPreferredSize() {
return size;
}
}
}
需要添加更多按钮吗?容易...
JPanel buttonPane = new JPanel(new GridLayout(1, 0, 20, 0));
buttonPane.setBorder(new EmptyBorder(10, 0, 0, 0));
buttonPane.add(new JButton("Add"));
buttonPane.add(new JButton("Delete"));
buttonPane.add(new JButton("Refresh"));
buttonPane.add(new JButton("Developer"));
buttonPane.add(new JButton("Some"));
buttonPane.add(new JButton("More"));
buttonPane.add(new JButton("Buttons"));
答案 1 :(得分:0)
我来晚了,我认为这对OP不再有帮助...但是对于处于相同情况的其他人。
就像其他人提到的那样,当您在JFrame上设置size时,它包括标题栏和边框。有一种方法可以获取这些内容的大小值,但是...如果要在内容窗格中手动放置内容,为什么不先准备内容窗格,然后将其添加到JFrame?
class MainPanel extends JPanel {
public MainPanel() {
setLayout(null);
setPreferredSize(new Dimension(900, 600));
// JFrame will have some layouting going on,
// it won't listen to setSize
JPanel randomPanel = new JPanel();
randomPanel.setOpaque(true);
randomPanel.setBackground(Color.RED);
randomPanel.setBounds(10, 10, 430, 530);
JButton addButton = new JButton("Add");
addButton.setBounds(10, 550, 100, 40);
addButton.setBackground(Color.GRAY);
JButton deleteButton = new JButton("Delete");
deleteButton.setBounds(120, 550, 100, 40);
deleteButton.setBackground(Color.GRAY);
JButton refreshButton = new JButton("Refresh");
refreshButton.setBounds(230, 550, 100, 40);
refreshButton.setBackground(Color.GRAY);
JButton devButton = new JButton("Developer");
devButton.setBounds(340, 550, 100, 40);
devButton.setBackground(Color.GRAY);
this.add(randomPanel);
this.add(addButton);
this.add(deleteButton);
this.add(refreshButton);
this.add(devButton);
}
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
mainFrame.setTitle("Example Frame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setContentPane(new MainPanel());
mainFrame.pack();
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
}
如果直接与JFrame混淆,您将绕过组件系统。鉴于此,您正在做组件就好了!现在,您有一个适合单个子面板的JFrame,其中有一些手动布置的东西。
在这种情况下,我通常就是这样做的。
P.S。 “不要手动布置内容,仅使用布局管理器”并不是您可以应用到任何地方的东西。有时候,您可能需要自定义组件,尤其是对于像视频游戏这样的东西,其中您具有自定义渲染的游戏屏幕。在游戏屏幕内,您将进行手动布局。只要您知道哪一个,它们就可以共存。
答案 2 :(得分:-1)
您需要重写基础JFrame的getInsets()方法。
@Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
请查看此question,以了解更多信息。