在 Swing GUI 中提供空白

没有空白的 GUI 显示为“拥挤”。如何在不显式设置组件的位置或大小的情况下提供空白?­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

58970 次浏览

在 Swing GUI 中,有许多方法可以提供组件之间的分离以及组件周围的空白:

但是更普遍的是:

  • 布局构造函数中可以定义的间距。
  • 边界。

下面是一个使用布局分隔符 hGap & vGap值 & 边框(特别是 EmptyBorder)来提供“白色”(实际上显示为 红色以使其非常明显)空间的例子。调整旋转器以查看结果。

With no GUI white space

With GUI white space

import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;


public class WhiteSpace {


private JPanel gui = null;
private BorderLayout mainLayout =
new BorderLayout(0, 0);
private final FlowLayout buttonLayout =
new FlowLayout(FlowLayout.CENTER, 0, 0);
private final JPanel buttonPanel = new JPanel(buttonLayout);
private final SpinnerNumberModel hModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel vModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel hBorderModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel vBorderModel =
new SpinnerNumberModel(0, 0, 15, 1);
private ChangeListener changeListener;


public Container getGui() {
if (gui == null) {
gui = new JPanel(mainLayout);
gui.setBackground(Color.RED);


JTree tree = new JTree();
tree.setVisibleRowCount(10);
for (int ii = tree.getRowCount(); ii > -1; ii--) {
tree.expandRow(ii);
}
gui.add(new JScrollPane(
tree,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
BorderLayout.LINE_START);
gui.add(new JScrollPane(new JTextArea(10, 30)));


gui.add(buttonPanel, BorderLayout.PAGE_START);


changeListener = (ChangeEvent e) -> {
int hGap = hModel.getNumber().intValue();
int vGap = vModel.getNumber().intValue();
int hBorder = hBorderModel.getNumber().intValue();
int vBorder = vBorderModel.getNumber().intValue();
adjustWhiteSpace(hGap, vGap, hBorder, vBorder);
};


addModel("H Gap", hModel);
addModel("V Gap", vModel);
addModel("H Border", hBorderModel);
addModel("V Border", vBorderModel);
}


return gui;
}


private void addModel(String label, SpinnerNumberModel model) {
buttonPanel.add(new JLabel(label));
final JSpinner spinner = new JSpinner(model);
spinner.addChangeListener(changeListener);
buttonPanel.add(spinner);
}


private void adjustWhiteSpace(
int hGap, int vGap, int hBorder, int vBorder) {
mainLayout.setHgap(hGap);
mainLayout.setVgap(vGap);
buttonLayout.setHgap(hGap);
gui.setBorder(new EmptyBorder
(vBorder, hBorder, vBorder, hBorder));
Container c = gui.getTopLevelAncestor();
if (c instanceof Window) {
Window w = (Window) c;
w.pack();
}
}


public static void main(String[] args) {
Runnable r = () -> {
WhiteSpace ws = new WhiteSpace();
Container gui1 = ws.getGui();
JFrame f = new JFrame("White (OK Red) Space");
f.add(gui1);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setResizable(false);
f.pack();
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}

使用各种 LayoutManagers可以提供不同组件之间的间距。

1)边框布局:

  • 重载构造函数: BorderLayout
  • Getter 和 setter 方法

    水平间距 : GetHgap ()SetHgap (int hgap)

    对于垂直间隔 : GetVgap ()和 BorderLayout.html # setVgap% 28int% 29”> BorderLayout.setVgap ()

2)流程设计:

  • 重载构造函数: FlowLayout (整数对齐,整数 hgap,整数 vgap)
  • Getter 和 setter 方法

    水平间距 : GetHgap ()SetHgap (int hgap)

    对于垂直间隔 : GetVgap ()和 FlowLayout.setVgap ()

3)网格布局:

  • GridLayout% 28int,% 20int,% 20int,% 20int% 29”> GridLayout (int rows,int column,int hgap,int vgap)
  • Getter 和 setter 方法

    水平间距 : GetHgap ()SetHgap (int hgap)

    对于垂直间隔 : GetVgap ()和 GridLayout.setVgap ()

4)网格布局:

GridBagConstraints.insets

5.)卡片版式(例子) :

CardLayout (int hGap,int vGap)

显示所有正在运行的构造函数的示例:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class LayoutExample {


private final int hGap = 5;
private final int vGap = 5;


private String[] borderConstraints = {
BorderLayout.PAGE_START,
BorderLayout.LINE_START,
BorderLayout.CENTER,
BorderLayout.LINE_END,
BorderLayout.PAGE_END
};


private JButton[] buttons;


private GridBagConstraints gbc;


private JPanel borderPanel;
private JPanel flowPanel;
private JPanel gridPanel;
private JPanel gridBagPanel;
private JPanel cardPanel;


public LayoutExample() {
buttons = new JButton[16];
gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.insets = new Insets(hGap, vGap, hGap, vGap);
}


private void displayGUI() {
JFrame frame = new JFrame("Layout Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);


JPanel contentPane = new JPanel(
new GridLayout(0, 1, hGap, vGap));
contentPane.setBorder(
BorderFactory.createEmptyBorder(hGap, vGap, hGap, vGap));
borderPanel = new JPanel(new BorderLayout(hGap, vGap));
borderPanel.setBorder(
BorderFactory.createTitledBorder("BorderLayout"));
borderPanel.setOpaque(true);
borderPanel.setBackground(Color.WHITE);
for (int i = 0; i < 5; i++) {
buttons[i] = new JButton(borderConstraints[i]);
borderPanel.add(buttons[i], borderConstraints[i]);
}
contentPane.add(borderPanel);


flowPanel = new JPanel(new FlowLayout(
FlowLayout.CENTER, hGap, vGap));
flowPanel.setBorder(
BorderFactory.createTitledBorder("FlowLayout"));
flowPanel.setOpaque(true);
flowPanel.setBackground(Color.WHITE);
for (int i = 5; i < 8; i++) {
buttons[i] = new JButton(Integer.toString(i));
flowPanel.add(buttons[i]);
}
contentPane.add(flowPanel);


gridPanel = new JPanel(new GridLayout(2, 2, hGap, vGap));
gridPanel.setBorder(
BorderFactory.createTitledBorder("GridLayout"));
gridPanel.setOpaque(true);
gridPanel.setBackground(Color.WHITE);
for (int i = 8; i < 12; i++) {
buttons[i] = new JButton(Integer.toString(i));
gridPanel.add(buttons[i]);
}
contentPane.add(gridPanel);


gridBagPanel = new JPanel(new GridBagLayout());
gridBagPanel.setBorder(
BorderFactory.createTitledBorder("GridBagLayout"));
gridBagPanel.setOpaque(true);
gridBagPanel.setBackground(Color.WHITE);
buttons[12] = new JButton(Integer.toString(12));
addComp(gridBagPanel, buttons[12], 0, 0, 1, 1
, GridBagConstraints.BOTH, 0.33, 0.5);
buttons[13] = new JButton(Integer.toString(13));
addComp(gridBagPanel, buttons[13], 1, 0, 1, 1
, GridBagConstraints.BOTH, 0.33, 0.5);
buttons[14] = new JButton(Integer.toString(14));
addComp(gridBagPanel, buttons[14], 0, 1, 2, 1
, GridBagConstraints.BOTH, 0.66, 0.5);
buttons[15] = new JButton(Integer.toString(15));
addComp(gridBagPanel, buttons[15], 2, 0, 1, 2
, GridBagConstraints.BOTH, 0.33, 1.0);
contentPane.add(gridBagPanel);


cardPanel = new JPanel(new CardLayout(hGap, vGap));
cardPanel.setBorder(
BorderFactory.createTitledBorder("CardLayout"));
cardPanel.setOpaque(true);
cardPanel.setBackground(Color.WHITE);
cardPanel.add(getPanel(Color.BLUE));
cardPanel.add(getPanel(Color.GREEN));
contentPane.add(cardPanel);


frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}


private JPanel getPanel(Color bColor) {
JPanel panel = new JPanel(new FlowLayout(
FlowLayout.CENTER, hGap, vGap));
panel.setOpaque(true);
panel.setBackground(bColor.darker().darker());
JButton swapperButton = new JButton("Next");
swapperButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
CardLayout cardLayout = (CardLayout) cardPanel.getLayout();
cardLayout.next(cardPanel);
}
});


panel.add(swapperButton);


return panel;
}


private void addComp(JPanel panel, JComponent comp
, int x, int y, int gWidth
, int gHeight, int fill
, double weightx, double weighty) {
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = gWidth;
gbc.gridheight = gHeight;
gbc.fill = fill;
gbc.weightx = weightx;
gbc.weighty = weighty;


panel.add(comp, gbc);
}


public static void main(String[] args) {
Runnable runnable = new Runnable(){
@Override
public void run() {
new LayoutExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}

产出:

LAYOUTIMAGE

在使用 BoxLayout时,Box.createVerticalGlue()方法可以帮助您创建一些空白。

另一种方法是 BorderFactory.createEmptyBorder(int top, int left, int bottom, int right),它可以帮助你在组件周围留出一些空白。

感谢 Andrew Thompson 的提醒。我最近修改了 BoxLayout,我发现 Box.createVerticalGlue()可以根据面板的大小增加一些空白,而且你不能设置空白长度的明确像素值。但是 Box.createVerticalStrut()可以做到这一点。这里是一个 MCTaRE,并显示了这两种方法的效果。

enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;


public class WhiteSpace extends JFrame{
static WhiteSpace whiteSpace;
DemoPanel demoPanel;
boolean withGlue;
JSpinner spinner;


public WhiteSpace(){
initialWindow();
demoPanel = new DemoPanel();
ActionPanel actionPanel = new ActionPanel();


setLayout(new BorderLayout());


getContentPane().add(actionPanel,BorderLayout.NORTH);
getContentPane().add(demoPanel,BorderLayout.CENTER);
setVisible(true);
}


public void initialWindow(){
setSize(220, 300);
setTitle("White Space");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//Show the window in the middle of the screen
}


/**
* @param args
*/
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
whiteSpace = new WhiteSpace();
}
};
SwingUtilities.invokeLater(runnable);
}


class DemoPanel extends JPanel{
//Show the vertical white space between label1 and label2
JLabel label1;
JLabel label2;
public void initialDemoPanel(){
setBorder(BorderFactory.createTitledBorder(getBorder(), "DemoPanel", TitledBorder.LEADING, TitledBorder.TOP, new Font("Default",Font.PLAIN,10), Color.gray));
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));


label1 = new JLabel("This is first line");
label2 = new JLabel("This is second line");
}


public DemoPanel(){
initialDemoPanel();
add(label1);
if(withGlue){
add(Box.createVerticalGlue());
}
add(label2);
}


public DemoPanel(int strutValue){
initialDemoPanel();
add(label1);
add(Box.createVerticalStrut(strutValue));
add(label2);
}
}


class ActionPanel extends JPanel{
public ActionPanel(){
setBorder(BorderFactory.createTitledBorder(getBorder(), "ActionPanel", TitledBorder.LEADING, TitledBorder.TOP, new Font("Default",Font.PLAIN,10), Color.gray));


setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
JRadioButton glueButton = new JRadioButton("With Glue");
glueButton.addActionListener(new glueButtonListener());
add(glueButton);


add(Box.createHorizontalStrut(10));
//To create horizontal white space
JLabel strutLabel = new JLabel("Strut Value");
add(strutLabel);
spinner = new JSpinner(new SpinnerNumberModel(0,0,50,1));
spinner.addChangeListener(new spinnerListener());
add(spinner);
//public SpinnerNumberModel(Number value,Comparable minimum,Comparable maximum,Number stepSize)
}
}


class glueButtonListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
spinner.setValue(new Integer(0));
withGlue = (withGlue == true ? false:true);
whiteSpace.getContentPane().remove(demoPanel);
demoPanel = new DemoPanel();
whiteSpace.getContentPane().add(demoPanel,BorderLayout.CENTER);
whiteSpace.getContentPane().validate();
}
}


class spinnerListener implements ChangeListener{


@Override
public void stateChanged(ChangeEvent e) {
int strutValue = (Integer) spinner.getValue();
whiteSpace.getContentPane().remove(demoPanel);
demoPanel = new DemoPanel(strutValue);
whiteSpace.getContentPane().add(demoPanel,BorderLayout.CENTER);
whiteSpace.getContentPane().validate();
}
}
}

Box.createHorizontalGlue()Box.createHorizontalStrut(int height)也可以使用,而且 Box.createRigidArea(Dimension d)也有制造空白的能力。

好东西

作者 Karsten Lentzsch 收集了关于 UI 设计的 陈述。特别是 本 PDF谈到了审美空白的需要。增加有意义的空间,同时也要注意杂乱无章,这样才能区分小麦和谷壳。

MigLayout有多种创造空间的方法。(在这种布局中,空间称为间隙。) 间隙可以创建在最高级别的布局约束,这是可能的 在行和列之间创建间隔,还可以在单个 组件的约束。边框周围也有特定的缺口 一个称为 insets 的容器,它有自己的特定关键字需要设置。

下面的例子创建了所有这些类型的差距:

package com.zetcode;


import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;




public class MigLayoutGaps2 extends JFrame {


public MigLayoutGaps2() {


initUI();


setTitle("Gaps");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}


private void initUI() {


JPanel base = new JPanel(new MigLayout("flowy, ins 30, gap 15"));
setContentPane(base);


JPanel pnl1 = new JPanel();
pnl1.setBorder(
BorderFactory.createTitledBorder("Grid gaps")
);


pnl1.setLayout(new MigLayout("gap 5 5, ins 10, wrap 3"));


pnl1.add(new JButton("1"));
pnl1.add(new JButton("2"));
pnl1.add(new JButton("3"));
pnl1.add(new JButton("4"));
pnl1.add(new JButton("5"));
pnl1.add(new JButton("6"));


JPanel pnl2 = new JPanel();
pnl2.setBorder(
BorderFactory.createTitledBorder("Column gaps")
);


pnl2.setLayout(new MigLayout("wrap 3", "[]10[]"));


JLabel lbl1 = new JLabel();
lbl1.setBorder(
BorderFactory.createEtchedBorder()
);


JLabel lbl2 = new JLabel();
lbl2.setBorder(
BorderFactory.createEtchedBorder()
);


JLabel lbl3 = new JLabel();
lbl3.setBorder(
BorderFactory.createEtchedBorder()
);


pnl2.add(lbl1, "w 40, h 110");
pnl2.add(lbl2, "w 40, h 110");
pnl2.add(lbl3, "w 40, h 110");


JPanel pnl3 = new JPanel();
pnl3.setBorder(
BorderFactory.createTitledBorder("Row gaps")
);


pnl3.setLayout(new MigLayout("wrap", "", "[]15[]"));


JLabel lbl4 = new JLabel();
lbl4.setBorder(
BorderFactory.createEtchedBorder()
);


JLabel lbl5 = new JLabel();
lbl5.setBorder(
BorderFactory.createEtchedBorder()
);


JLabel lbl6 = new JLabel();
lbl6.setBorder(
BorderFactory.createEtchedBorder()
);


pnl3.add(lbl4, "w 150, h 20");
pnl3.add(lbl5, "w 150, h 20");
pnl3.add(lbl6, "w 150, h 20");


JPanel pnl4 = new JPanel();
pnl4.setBorder(
BorderFactory.createTitledBorder("Component gaps")
);


pnl4.setLayout(new MigLayout());


pnl4.add(new JLabel("Name:"), "gapright 5");
pnl4.add(new JTextField(10), "gapbottom 20, gaptop 20");


base.add(pnl1);
base.add(pnl2);
base.add(pnl3);
base.add(pnl4);


pack();
}


public static void main(String[] args) {


EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
MigLayoutGaps2 ex = new MigLayoutGaps2();
ex.setVisible(true);
}
});
}
}

我们在布局中有四个面板。每个面板都有一个 MigLayout管理器。

JPanel base = new JPanel(new MigLayout("flowy, ins 30, gap 15"));

此行创建容器插入和面板之间的垂直间隔。

pnl1.setLayout(new MigLayout("gap 5 5, ins 10, wrap 3"));

在这里,我们为整个网格结构应用间隙,并设置容器间隙。

pnl2.setLayout(new MigLayout("wrap 3", "[]10[]"));

此行在列之间创建间隔。

pnl3.setLayout(new MigLayout("wrap", "", "[]15[]"));

行间隔使用此代码定义。

pnl4.add(new JLabel("Name:"), "gapright 5");
pnl4.add(new JTextField(10), "gapbottom 20, gaptop 20");

最后,可以在各个组件之间创建间隔。

Gaps

每当我遇到这个问题,我就使用 JPanels:

JFrame frame = new JFrame;
frame.setLayout(new GridLayout(2, 0));


//We want the bottom left to be blank
frame.add(new JLabel("Top Left"));
frame.add(new JLabel("Top Right"));


//This is the position we want empty
frame.add(new JPanel());


//Now we can continue with the rest of the script