# Swing 布局管理
> 原文: [http://zetcode.com/tutorials/javaswingtutorial/swinglayoutmanagement/](http://zetcode.com/tutorials/javaswingtutorial/swinglayoutmanagement/)
Java Swing 具有两种组件:容器和子组件。 容器将子项分组为合适的布局。 要创建布局,我们使用布局管理器。
[Tweet](https://twitter.com/share)
ZetCode 为 Swing 布局管理过程提供了 196 页专门的电子书: [Java Swing 布局管理教程](/ebooks/javaswinglayout/)
## Swing 布局管理器
Swing 有大量可用的布局管理器-内置和第三方。 但是,大多数管理器都不适合现代 UI 的创建。
有三种可以正确完成工作的布局管理器:
* `MigLayout`
* `GroupLayout`
* `FormLayout`
`MigLayout`,`GroupLayout`和`FormLayout`是强大,灵活的布局管理器,可以满足大多数布局要求。 在本教程中,我们使用`GroupLayout`管理器来设计用户界面。
以下布局管理器已过时:
* `FlowLayout`
* `GridLayout`
* `CardLayout`
* `BoxLayout`
* `GridBagLayout`
这些布局管理器无法满足现代 UI 的要求。
## 过时的管理器遇到的问题
过时的管理器要么太简单(`FlowLayout`,`GridLayout`),要么就是不必要的复杂(`GridBagLayout`)。 所有这些管理器都有一个基本的设计错误:他们使用组件之间的固定间隙。 在组件之间使用刚性空间是不可移植的:一旦在不同的屏幕分辨率下运行程序,用户界面就会损坏。
过时的管理器试图通过一种称为嵌套的技术来修复其弱点。 在嵌套中,开发者在多个面板中使用几个不同的布局管理器。 尽管可以使用嵌套创建 UI,但它给代码带来了额外的不必要的复杂性。
## 过时的管理器
在本节中,我们将介绍过时的布局管理器。 不建议使用这些管理器。 如果我们需要维护一些遗留代码,只需花一些时间研究它们。 否则,应拒绝使用它们。
### `FlowLayout`管理器
这是 Java Swing 工具箱中最简单的布局管理器。 它是`JPanel`组件的默认布局管理器。
它是如此简单,以至于不能用于任何实际布局。 许多 Java Swing 教程都介绍了该管理器,因此,初学者尝试在其项目中使用它,而没有意识到它不能用于任何严重的事情。
在计算其子大小时,流程布局使每个组件都假定其自然(首选)大小。 管理器将组件排成一排。 按顺序添加了它们。 如果它们不适合一排,则进入下一排。 可以从右向左添加组件,反之亦然。 管理器允许对齐组件。 隐式地,组件居中,并且组件之间以及组件的边缘与容器的边缘之间有 5px 的空间。
```java
FlowLayout()
FlowLayout(int align)
FlowLayout(int align, int hgap, int vgap)
```
FlowLayout 管理器有三个可用的构造器。 第一个创建具有隐式值的管理器。 以 5px 水平和垂直空间居中。 其他允许指定这些参数。
`FlowLayoutEx.java`
```java
package com.zetcode;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTree;
import java.awt.Dimension;
import java.awt.EventQueue;
public class FlowLayoutEx extends JFrame {
public FlowLayoutEx() {
initUI();
}
private void initUI() {
var panel = new JPanel();
var button = new JButton("button");
panel.add(button);
var tree = new JTree();
panel.add(tree);
var area = new JTextArea("text area");
area.setPreferredSize(new Dimension(100, 100));
panel.add(area);
add(panel);
pack();
setTitle("FlowLayout example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new FlowLayoutEx();
ex.setVisible(true);
});
}
}
```
该示例显示了窗口中的按钮,树组件和文本区域组件。 如果我们创建一个空树组件,则组件内部会有一些默认值。
```java
var panel = new JPanel();
```
`JPanel`组件的隐式布局管理器是`FlowLayout`。 我们不必手动设置。
```java
var area = new JTextArea("text area");
area.setPreferredSize(new Dimension(100, 100));
```
流布局管理器为其组件设置首选大小。 因此,在我们的案例中,区域组件将为`100x100px`。 如果我们未设置首选大小,则组件将具有其文本的大小。 没有文本,该组件将根本不可见。 尝试在区域组件中编写或删除一些文本。 组件将相应地增长和收缩。
```java
panel.add(area);
```
该组件放置在带有`add()`的容器内。
![FlowLayout](https://img.kancloud.cn/fc/c5/fcc589bd4d23ef9d9d4128f86d05082a_287x135.jpg)
图:`FlowLayout`
### `GridLayout`
`GridLayout`布局管理器将组件布置在矩形网格中。 容器分为大小相等的矩形。 每个矩形中放置一个组件。
`GridLayout`非常简单,不能用于任何实际布局。
`GridLayoutEx.java`
```java
package com.zetcode;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.EventQueue;
import java.awt.GridLayout;
public class GridLayoutEx extends JFrame {
public GridLayoutEx() {
initUI();
}
private void initUI() {
var panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.setLayout(new GridLayout(5, 4, 5, 5));
String[] buttons = {
"Cls", "Bck", "", "Close", "7", "8", "9", "/", "4",
"5", "6", "*", "1", "2", "3", "-", "0", ".", "=", "+"
};
for (int i = 0; i < buttons.length; i++) {
if (i == 2) {
panel.add(new JLabel(buttons[i]));
} else {
panel.add(new JButton(buttons[i]));
}
}
add(panel);
setTitle("GridLayout");
setSize(350, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new GridLayoutEx();
ex.setVisible(true);
});
}
}
```
该示例显示了一个简单计算器工具的框架。 我们在管理器中放入了 19 个按钮和一个标签。 请注意,每个按钮的大小均相同。
```java
panel.setLayout(new GridLayout(5, 4, 5, 5));
```
在这里,我们为面板组件设置了网格布局管理器。 布局管理器采用四个参数。 行数,列数以及组件之间的水平和垂直间隙。
![GridLayout](https://img.kancloud.cn/35/99/35997409ceb8f86b816508e0ff17cb3e_350x300.jpg)
图:`GridLayout`
### `BorderLayout`
`BorderLayout`是一个简单的布局管理器,在某些布局中可以派上用场。 它是`JFrame`,`JWindow`,`JDialog`,`JInternalFrame`和`JApplet`的默认布局管理器。 它有一个严重的局限性-它以像素为单位设置子元素之间的间隙,从而创建了刚性的布局。 这导致了不可移植的 UI,因此不建议使用它。
`BorderLayout`将空间分为五个区域:北,西,南,东和中心。 每个区域只能有一个组件。 如果需要在一个区域中放置更多组件,则必须在其中放置一个由我们选择的管理器组成的小组。 N,W,S,E 区域中的组件具有首选大小。 中间的组件占据了剩余的整个空间。
如果子组件彼此之间距离太近,则看起来不太好。 我们必须在它们之间留一些空间。 Swing 工具箱中的每个组件的边缘都可以带有边框。 要创建边框,我们可以创建`EmptyBorder`类的新实例,或者使用`BorderFactory`。
`BorderEx.java`
```java
package com.zetcode;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
public class BorderLayoutEx extends JFrame {
public BorderLayoutEx() {
initUI();
}
private void initUI() {
var bottomPanel = new JPanel(new BorderLayout());
var topPanel = new JPanel();
topPanel.setBackground(Color.gray);
topPanel.setPreferredSize(new Dimension(250, 150));
bottomPanel.add(topPanel);
bottomPanel.setBorder(new EmptyBorder(new Insets(20, 20, 20, 20)));
add(bottomPanel);
pack();
setTitle("BorderLayout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new BorderLayoutEx();
ex.setVisible(true);
});
}
}
```
该示例将显示一个灰色面板及其周围的边框。
```java
var bottomPanel = new JPanel(new BorderLayout());
var topPanel = new JPanel();
```
我们将面板放入面板中。 底部面板具有`BorderLayout`管理器。
```java
bottomPanel.add(topPanel);
```
在这里,我们将顶部面板放入底部面板组件中。 更准确地说,我们将其放置在`BorderLayout`管理器的中心区域。
```java
bottomPanel.setBorder(new EmptyBorder(new Insets(20, 20, 20, 20)));
```
在这里,我们在底部面板周围创建了 20px 的边框。 边框值如下:上,左,下和右。 请注意,创建固定的嵌入(空格)不是可移植的。
![BorderLayout](https://img.kancloud.cn/b5/d5/b5d5078f3dba506d22cc06797f1d3848_292x215.jpg)
图:`BorderLayout`
下一个示例显示`BorderLayout`管理器的典型用法。
`BorderLayoutEx2.java`
```java
package com.zetcode;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Insets;
public class BorderLayoutEx2 extends JFrame {
public BorderLayoutEx2() {
initUI();
}
private void initUI() {
var menubar = new JMenuBar();
var fileMenu = new JMenu("File");
menubar.add(fileMenu);
setJMenuBar(menubar);
var toolbar = new JToolBar();
toolbar.setFloatable(false);
var exitIcon = new ImageIcon("src/resources/exit.png");
var exitBtn = new JButton(exitIcon);
exitBtn.setBorder(new EmptyBorder(0, 0, 0, 0));
toolbar.add(exitBtn);
add(toolbar, BorderLayout.NORTH);
var vertical = new JToolBar(JToolBar.VERTICAL);
vertical.setFloatable(false);
vertical.setMargin(new Insets(10, 5, 5, 5));
var driveIcon = new ImageIcon("src/resources/drive.png");
var compIcon = new ImageIcon("src/resources/computer.png");
var printIcon = new ImageIcon("src/resources/printer.png");
var driveBtn = new JButton(driveIcon);
driveBtn.setBorder(new EmptyBorder(3, 0, 3, 0));
var compBtn = new JButton(compIcon);
compBtn.setBorder(new EmptyBorder(3, 0, 3, 0));
var printBtn = new JButton(printIcon);
printBtn.setBorder(new EmptyBorder(3, 0, 3, 0));
vertical.add(driveBtn);
vertical.add(compBtn);
vertical.add(printBtn);
add(vertical, BorderLayout.WEST);
add(new JTextArea(), BorderLayout.CENTER);
var statusbar = new JLabel(" Statusbar");
add(statusbar, BorderLayout.SOUTH);
setSize(400, 350);
setTitle("BorderLayout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new BorderLayoutEx2();
ex.setVisible(true);
});
}
}
```
该示例显示了典型的应用框架。 我们显示了一个垂直和水平工具栏,一个状态栏和一个中央组件(文本区域)。
`BorderLayout`是`JFrame`容器的默认布局管理器。 因此,我们不必显式设置它。
```java
add(toolbar, BorderLayout.NORTH);
```
我们将工具栏放置在布局的北部。
```java
var driveBtn = new JButton(driveIcon);
driveBtn.setBorder(new EmptyBorder(3, 0, 3, 0));
```
为了在按钮周围留一些空白,我们必须使用`EmptyBorder`。 这会在按钮的顶部和底部增加一些固定的空间。 当我们添加固定空间时,UI 不可移植。 3px 的空间在 1280x720 的屏幕上可能看起来不错,但在`1920x1200px`的屏幕上不合适。
```java
add(vertical, BorderLayout.WEST);
```
我们将垂直太杆放在西边。
```java
add(new JTextArea(), BorderLayout.CENTER);
```
我们将文本区域放置在中间。
```java
add(statusbar, BorderLayout.SOUTH);
```
状态栏转到南部区域。
![BorderLayout 2](https://img.kancloud.cn/00/b7/00b7d556450e19f62cdeb9c2a7a47075_471x367.jpg)
图:`BorderLayout` 2
### `CardLayout`
`CardLayout`是一个简单的布局管理器,将每个组件都视为卡。 容器是这些卡的栈。 一次只能看到一个组件。 其余的隐藏。 最初显示容器时,默认情况下将显示添加到容器的第一个组件。 该管理器的实际用途有限。 它可用于创建向导或选项卡式窗格。
以下示例使用`CardLayout`管理器创建图像库。 我们使用了 Krasna Horka 城堡的四张图片(2012 年大火之前)。
`CardLayoutEx.java`
```java
package com.zetcode;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CardLayoutEx extends JFrame {
private ImageIcon horka1;
private ImageIcon horka2;
private ImageIcon horka3;
private ImageIcon horka4;
private ImageIcon previ;
private ImageIcon nexti;
private JPanel mainPanel;
private CardLayout cardLayout;
public CardLayoutEx() {
initUI();
}
private void initUI() {
mainPanel = new JPanel();
mainPanel.setBackground(new Color(50, 50, 50));
mainPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5)
);
cardLayout = new CardLayout();
mainPanel.setLayout(cardLayout);
horka1 = new ImageIcon("src/resources/horka1.jpg");
horka2 = new ImageIcon("src/resources/horka2.jpg");
horka3 = new ImageIcon("src/resources/horka3.jpg");
horka4 = new ImageIcon("src/resources/horka4.jpg");
previ = new ImageIcon("src/resources/previous.png");
nexti = new ImageIcon("src/resources/next.png");
var label1 = new JLabel(horka1);
var label2 = new JLabel(horka2);
var label3 = new JLabel(horka3);
var label4 = new JLabel(horka4);
mainPanel.add(label1);
mainPanel.add(label2);
mainPanel.add(label3);
mainPanel.add(label4);
add(mainPanel);
var prevButton = new JButton(previ);
prevButton.addActionListener((e) -> cardLayout.previous(mainPanel));
var nextButton = new JButton(nexti);
nextButton.addActionListener((e) -> cardLayout.next(mainPanel));
var btnPanel = new JPanel();
btnPanel.setBackground(new Color(50, 50, 50));
btnPanel.add(prevButton);
btnPanel.add(nextButton);
add(btnPanel, BorderLayout.SOUTH);
pack();
setTitle("Gallery");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new CardLayoutEx();
ex.setVisible(true);
});
}
}
```
我们创建两个按钮来浏览图像。
```java
mainPanel = new JPanel();
mainPanel.setBackground(new Color(50, 50, 50));
mainPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5)
);
```
我们创建主面板组件。 我们将其颜色设置为深灰色。 我们将 5px 放置在面板周围,以使它的子级不太靠近窗口的边界。
```java
cardLayout = new CardLayout();
mainPanel.setLayout(cardLayout);
```
`CardLayout`管理器已创建并设置到主面板。
```java
mainPanel.add(label1);
mainPanel.add(label2);
mainPanel.add(label3);
mainPanel.add(label4);
```
显示图像的标签组件将添加到面板中。
```java
var prevButton = new JButton(previ);
prevButton.addActionListener((e) -> cardLayout.previous(mainPanel));
```
单击上一个按钮,将调用管理器的`previous()`方法。 它会翻转到指定容器的上一张卡片。
```java
add(mainPanel);
```
我们将主面板添加到框架组件边框布局的中心区域。 如果未明确指定放置组件的位置,则会将其添加到中心区域。
```java
var btnPanel = new JPanel();
btnPanel.setBackground(new Color(50, 50, 50));
btnPanel.add(prevButton);
btnPanel.add(nextButton);
```
这些按钮将添加到按钮面板。
```java
add(btnPanel, BorderLayout.SOUTH);
```
最后,将带有按钮的面板放入`BorderLayout`管理器的南部区域。
![CardLayout](https://img.kancloud.cn/76/a0/76a05492c1053fb59c4fb7bc054cc711_402x335.jpg)
图:`CardLayout`
### `BoxLayout`
`BoxLayout`管理器是一个简单的布局管理器,用于组织列或行中的组件。 它可以使用嵌套创建非常复杂的布局。 但是,这增加了布局创建的复杂性,并使用了额外的资源,尤其是许多其他`JPanel`组件。 `BoxLayout`仅能创建固定空间; 因此,其布局不可移植。
`BoxLayout`具有以下构造器:
```java
BoxLayout(Container target, int axis)
```
构造器创建一个布局管理器,该管理器将沿给定轴布置组件。 与其他布局管理器不同,`BoxLayout`将容器实例作为构造器中的第一个参数。 第二个参数确定管理器的方向。 要创建一个水平框,我们可以使用`LINE_AXIS`常量。 要创建一个垂直框,我们可以使用`PAGE_AXIS`常量。
框布局管理器通常与`Box`类一起使用。 此类创建一些不可见的组件,这些组件会影响最终布局。
* 胶水
* 支撑
* 刚性区域
假设我们要在窗口的右下角放置两个按钮。
`BoxLayoutButtonsEx.java`
```java
package com.zetcode;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.EventQueue;
public class BoxLayoutButtonsEx extends JFrame {
public BoxLayoutButtonsEx() {
initUI();
}
private void initUI() {
var basePanel = new JPanel();
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
add(basePanel);
basePanel.add(Box.createVerticalGlue());
var bottomPanel = new JPanel();
bottomPanel.setAlignmentX(1f);
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
var okBtn = new JButton("OK");
var closeBtn = new JButton("Close");
bottomPanel.add(okBtn);
bottomPanel.add(Box.createRigidArea(new Dimension(5, 0)));
bottomPanel.add(closeBtn);
bottomPanel.add(Box.createRigidArea(new Dimension(15, 0)));
basePanel.add(bottomPanel);
basePanel.add(Box.createRigidArea(new Dimension(0, 15)));
setTitle("Two Buttons");
setSize(300, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new BoxLayoutButtonsEx();
ex.setVisible(true);
});
}
}
```
下图说明了该示例。
![Two buttons](https://img.kancloud.cn/04/89/0489b37e73abeeda232bbc266d2003b4_300x211.jpg)
图:两个按钮
我们创建两个面板。 基本面板具有垂直框布局。 底部面板有一个水平面板。 我们将底板插入底板。 底部面板右对齐。 窗口顶部和底部面板之间的空间是可扩展的。 这是通过垂直胶水实现的。
```java
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
```
在这里,我们使用垂直`BoxLayout`创建一个基础面板。
```java
var bottomPanel = new JPanel();
bottomPanel.setAlignmentX(1f);
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
```
底部面板右对齐。 这是通过`setAlignmentX()`方法完成的。 面板具有水平布局。
```java
bottomPanel.add(Box.createRigidArea(new Dimension(5, 0)));
```
我们在按钮之间留出一些刚性空间。
```java
basePanel.add(bottomPanel);
```
在这里,我们将具有水平框布局的底部面板放置到垂直基础面板上。
```java
basePanel.add(Box.createRigidArea(new Dimension(0, 15)));
```
我们还在底部面板和窗口边框之间留出一些空间。
![BoxLayout buttons example](https://img.kancloud.cn/c4/62/c4625c3f17178c53fa1e26f7af9a4d4b_300x150.jpg)
图:`BoxLayout`按钮示例
当使用`BoxLayout`管理器时,可以在组件之间设置一个刚性区域。
`BoxLayoutRigidAreaEx.java`
```java
package com.zetcode;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
public class BoxLayoutRigidAreaEx extends JFrame {
public BoxLayoutRigidAreaEx() {
initUI();
}
private void initUI() {
var basePanel = new JPanel();
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
basePanel.setBorder(new EmptyBorder(new Insets(40, 60, 40, 60)));
basePanel.add(new JButton("Button"));
basePanel.add(Box.createRigidArea(new Dimension(0, 5)));
basePanel.add(new JButton("Button"));
basePanel.add(Box.createRigidArea(new Dimension(0, 5)));
basePanel.add(new JButton("Button"));
basePanel.add(Box.createRigidArea(new Dimension(0, 5)));
basePanel.add(new JButton("Button"));
add(basePanel);
pack();
setTitle("RigidArea");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new BoxLayoutRigidAreaEx();
ex.setVisible(true);
});
}
}
```
在此示例中,我们显示四个按钮。 默认情况下,按钮之间没有空格。 为了在其中留出一些空间,我们增加了一些刚性区域。
```java
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
```
我们为面板使用垂直`BoxLayout`管理器。
```java
basePanel.add(new JButton("Button"));
basePanel.add(Box.createRigidArea(new Dimension(0, 5)));
basePanel.add(new JButton("Button"));
```
我们添加按钮并使用`Box.createRigidArea()`在它们之间创建一个刚性区域。
![Rigid area](https://img.kancloud.cn/5b/9b/5b9bb24f3ba581f9e208eb2cc2a04a15_204x220.jpg)
图:`RigidArea`
### 每日提示
下一个示例创建“每日提示”窗口对话框。 我们结合使用各种布局管理器。
`TipOfDayEx.java`
```java
package com.zetcode;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextPane;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.KeyEvent;
public class TipOfDayEx extends JDialog {
public TipOfDayEx() {
initUI();
}
private void initUI() {
var basePanel = new JPanel();
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
add(basePanel);
var topPanel = new JPanel(new BorderLayout(0, 0));
topPanel.setMaximumSize(new Dimension(450, 0));
var hint = new JLabel("Productivity Hints");
hint.setBorder(BorderFactory.createEmptyBorder(0, 25, 0, 0));
topPanel.add(hint);
var icon = new ImageIcon("src/resources/coffee2.png");
var label = new JLabel(icon);
label.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
topPanel.add(label, BorderLayout.EAST);
var separator = new JSeparator();
separator.setForeground(Color.gray);
topPanel.add(separator, BorderLayout.SOUTH);
basePanel.add(topPanel);
var textPanel = new JPanel(new BorderLayout());
textPanel.setBorder(BorderFactory.createEmptyBorder(15, 25, 15, 25));
var pane = new JTextPane();
pane.setContentType("text/html");
var text = "<p><b>Closing windows using the mouse wheel</b></p>" +
"<p>Clicking with the mouse wheel on an editor tab closes the window. " +
"This method works also with dockable windows or Log window tabs.</p>";
pane.setText(text);
pane.setEditable(false);
textPanel.add(pane);
basePanel.add(textPanel);
var boxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
var box = new JCheckBox("Show Tips at startup");
box.setMnemonic(KeyEvent.VK_S);
boxPanel.add(box);
basePanel.add(boxPanel);
var bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
var tipBtn = new JButton("Next Tip");
tipBtn.setMnemonic(KeyEvent.VK_N);
var closeBtn = new JButton("Close");
closeBtn.setMnemonic(KeyEvent.VK_C);
bottomPanel.add(tipBtn);
bottomPanel.add(closeBtn);
basePanel.add(bottomPanel);
bottomPanel.setMaximumSize(new Dimension(450, 0));
setTitle("Tip of the Day");
setSize(new Dimension(450, 350));
setResizable(false);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new TipOfDayEx();
ex.setVisible(true);
});
}
}
```
该示例混合使用了布局管理器。 只需将四个面板放入垂直组织的基本面板中即可。
```java
var basePanel = new JPanel();
basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS));
add(basePanel);
```
这是最底部的面板。 它具有垂直框布局管理器。 基本面板已添加到默认的`JDialog`组件。 默认情况下,此组件具有边框布局管理器。
```java
var topPanel = new JPanel(new BorderLayout(0, 0));
```
`topPanel`面板具有边框布局管理器。 我们将包含三个组成部分。 两个标签和一个分隔符。
```java
topPanel.setMaximumSize(new Dimension(450, 0));
```
如果我们想要的面板不超过其组件,则必须设置其最大大小。 零值将被忽略。 管理器计算必要的高度。
```java
var textPanel = new JPanel(new BorderLayout());
...
textPanel.add(pane);
```
文本窗格组件将添加到边框布局管理器的中心区域。 它会占用所有剩余空间。 正是我们想要的。
```java
var boxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
```
该复选框显示在`boxPanel`面板中。 它保持对齐。 流布局管理器的水平间隙为 20px。 其他组件的像素为 25px。 这是为什么? 这是因为流布局管理器也在组件和边缘之间放置了一些空间。
```java
var bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
...
bottomPanel.setMaximumSize(new Dimension(450, 0));
```
底部面板显示两个按钮。 它具有右对齐的流布局管理器。 为了在对话框的右边缘显示按钮,面板必须从头到尾水平伸展。
![Tip of the Day](https://img.kancloud.cn/e7/71/e771bda7a05b93978ff7eaab97c4276c_450x350.jpg)
图:当天的提示
## 没有管理器
可以不使用布局管理器。 在少数情况下,我们可能不需要布局管理器。 (也许将一些图像放置在一些不规则的位置。)但是在大多数情况下,要创建真正可移植的复杂应用,我们需要布局管理器。
如果没有布局管理器,我们将使用绝对值来定位组件。
`AbsoluteLayoutEx.java`
```java
package com.zetcode;
import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.EventQueue;
public class AbsoluteLayoutEx extends JFrame {
public AbsoluteLayoutEx() {
initUI();
}
private void initUI() {
setLayout(null);
var okBtn = new JButton("OK");
okBtn.setBounds(50, 50, 80, 25);
var closeBtn = new JButton("Close");
closeBtn.setBounds(150, 50, 80, 25);
add(okBtn);
add(closeBtn);
setTitle("Absolute positioning");
setSize(300, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new AbsoluteLayoutEx();
ex.setVisible(true);
});
}
}
```
这个简单的示例显示了两个按钮。
```java
setLayout(null);
```
我们通过向`setLayout()`方法提供`null`使用绝对定位。 (`JFrame`组件具有默认的布局管理器`BorderLayout`。)
```java
okBtn.setBounds(50, 50, 80, 25);
```
`setBounds()`方法放置“确定”按钮。 参数是 x 和 y 坐标以及组件的宽度和高度。
![Absolute layout](https://img.kancloud.cn/f3/0c/f30cbe31c60e0a515896b240668fbf61_300x250.jpg)
图:绝对布局
在本章中,我们提到了 Swing 中的布局管理。
- ZetCode 数据库教程
- MySQL 教程
- MySQL 简介
- MySQL 安装
- MySQL 的第一步
- MySQL 快速教程
- MySQL 存储引擎
- MySQL 数据类型
- 在 MySQL 中创建,更改和删除表
- MySQL 表达式
- 在 MySQL 中插入,更新和删除数据
- MySQL 中的SELECT语句
- MySQL 子查询
- MySQL 约束
- 在 MySQL 中导出和导入数据
- 在 MySQL 中连接表
- MySQL 函数
- MySQL 中的视图
- MySQL 中的事务
- MySQL 存储过程
- MySQL Python 教程
- MySQL Perl 教程
- MySQL & Perl DBI
- 使用 Perl 连接到 MySQL 数据库
- MySQL 中的 Perl 错误处理
- 使用 Perl 进行 MySQL 查询
- 在 MySQL 中使用 Perl 绑定参数&列
- 在 MySQL 中使用 Perl 处理图像
- 使用 Perl 获取 MySQL 元数据
- Perl 的 MySQL 事务
- MySQL C API 编程教程
- MySQL Visual Basic 教程
- MySQL PHP 教程
- MySQL Java 教程
- MySQL Ruby 教程
- MySQL C# 教程
- SQLite 教程
- SQLite 简介
- sqlite3 命令行工具
- 在 SQLite 中创建,删除和更改表
- SQLite 表达式
- SQLite 插入,更新,删除数据
- SQLite SELECT语句
- SQLite 约束
- SQLite 连接表
- SQLite 函数
- SQLite 视图,触发器,事务
- SQLite C 教程
- SQLite Python 教程
- SQLite Perl 教程
- Perl DBI
- 使用 Perl 连接到 SQLite 数据库
- SQLite Perl 错误处理
- 使用 Perl 的 SQLite 查询
- 使用 Perl 绑定 SQLite 参数&列
- 使用 Perl 在 SQLite 中处理图像
- 使用 Perl 获取 SQLite 元数据
- 使用 Perl 进行 SQLite 事务
- SQLite Ruby 教程
- 连接到 SQLite 数据库
- 在 SQLite 中使用 Ruby 进行 SQL 查询
- 绑定参数
- 处理图像
- 使用 Ruby 获取 SQLite 元数据
- Ruby 的 SQLite 事务
- SQLite C# 教程
- SQLite C# 简介
- 使用SqliteDataReader检索数据
- ADO.NET 数据集
- 使用 C# 在 SQLite 中处理图像
- 使用 C# 获取 SQLite 元数据
- 使用 C# 的 SQLite 事务
- SQLite Visual Basic 教程
- SQLite Visual Basic 简介
- 使用SqliteDataReader检索数据
- ADO.NET 的数据集
- 使用 Visual Basic 在 SQLite 中处理图像
- 使用 Visual Basic 获取 SQLite 元数据
- 使用 Visual Basic 的 SQLite 事务
- PostgreSQL C 教程
- PostgreSQL Ruby 教程
- PostgreSQL PHP 教程
- PostgreSQL PHP 编程简介
- 在 PostgreSQL 中使用 PHP 检索数据
- 在 PostgreSQL 中使用 PHP 处理图像
- 用 PHP 获取 PostgreSQL 元数据
- 在 PostgreSQL 中使用 PHP 进行事务
- PostgreSQL Java 教程
- Apache Derby 教程
- Derby 简介
- Derby 的安装&配置
- Derby 工具
- ij 工具
- Derby 中的 SQL 查询
- 在 Derby 中使用 JDBC 进行编程
- Derby 安全
- 使用 Derby & Apache Tomcat
- NetBeans 和 Derby
- SQLAlchemy 教程
- SQLAlchemy 简介
- 原始 SQL
- 模式定义语言
- SQL 表达式语言
- SQLAlchemy 中的对象关系映射器
- MongoDB PHP 教程
- MongoDB JavaScript 教程
- MongoDB Ruby 教程
- Spring JdbcTemplate 教程
- JDBI 教程
- MyBatis 教程
- Hibernate Derby 教程
- ZetCode .NET 教程
- Visual Basic 教程
- Visual Basic
- Visual Basic 语法结构
- 基本概念
- Visual Basic 数据类型
- Visual Basic 中的字符串
- 运算符
- 控制流
- Visual Basic 数组
- Visual Basic 中的过程&函数
- 在 Visual Basic 中组织代码
- 面向对象编程
- Visual Basic 中的面向对象编程 II
- Visual Basic 中的集合
- 输入和输出
- C# 教程
- C# 语言
- C# 语法结构
- C# 基础
- C# 数据类型
- C# 中的字符串
- C# 运算符
- C# 中的流控制
- C# 数组
- C# 面向对象编程
- C# 中的方法
- C# 面向对象编程 II
- C# 属性
- C# 结构
- C# 委托
- 命名空间
- C# 集合
- C# 输入和输出
- C# 目录教程
- C# 字典教程
- 在 C# 中读取文本文件
- C# 中的日期和时间
- 在 C# 中读取网页
- C# HttpClient教程
- ASP.NET Core 教程
- ZetCode 图形教程
- Java 2D 游戏教程
- Java 游戏基础
- 动画
- 移动精灵
- 碰撞检测
- Java 益智游戏
- Java Snake
- Breakout 游戏
- Java 俄罗斯方块
- Java 吃豆人
- Java 太空侵略者
- Java 扫雷
- Java 推箱子
- Java 2D 教程
- 介绍
- 基本绘图
- 形状和填充
- 透明度
- 合成
- 剪裁
- 变换
- 特效
- 图像
- 文字和字体
- 命中测试,移动物体
- 俄罗斯方块
- Cario 图形教程
- Cario 图形库
- Cario 定义
- Cairo 后端
- Cairo 基本图形
- 形状和填充
- 渐变
- 透明度
- 合成
- 剪裁和遮罩
- 变换
- Cairo 文字
- Cairo 中的图像
- 根窗口
- PyCairo 教程
- PyCairo 简介
- PyCairo 后端
- PyCairo 中的基本绘图
- PyCairo 形状和填充
- PyCairo 渐变
- PyCairo 剪裁&遮罩
- PyCairo 的透明度
- PyCairo 中的变换
- PyCairo 中的文字
- PyCairo 中的图像
- 根窗口
- HTML5 画布教程
- 介绍
- HTML5 画布中的直线
- HTML5 画布形状
- HTML5 画布填充
- HTML5 画布中的透明度
- HTML5 画布合成
- HTML5 canvas 中的变换
- HTML5 画布中的文字
- HTML5 画布中的动画
- HTML5 画布中的 Snake
- ZetCode GUI 教程
- Windows API 教程
- Windows API 简介
- Windows API main函数
- Windows API 中的系统函数
- Windows API 中的字符串
- Windows API 中的日期和时间
- Windows API 中的一个窗口
- UI 的第一步
- Windows API 菜单
- Windows API 对话框
- Windows API 控件 I
- Windows API 控件 II
- Windows API 控件 III
- Windows API 中的高级控件
- Windows API 中的自定义控件
- Windows API 中的 GDI
- PyQt4 教程
- PyQt4 简介
- PyQt4 中的第一个程序
- PyQt4 中的菜单和工具栏
- PyQt4 中的布局管理
- PyQt4 中的事件和信号
- PyQt4 中的对话框
- PyQt4 小部件
- PyQt4 小部件 II
- PyQt4 中的拖放
- PyQt4 中的绘图
- PyQt4 中的自定义小部件
- PyQt4 中的俄罗斯方块游戏
- PyQt5 教程
- PyQt5 简介
- PyQt5 日期和时间
- PyQt5 中的第一个程序
- PyQt5 中的菜单和工具栏
- PyQt5 中的布局管理
- PyQt5 中的事件和信号
- PyQt5 中的对话框
- PyQt5 小部件
- PyQt5 小部件 II
- PyQt5 拖放
- PyQt5 中的绘图
- PyQt5 中的自定义小部件
- PyQt5 中的俄罗斯方块
- Qt4 教程
- Qt4 工具包简介
- Qt4 工具类
- Qt4 中的字符串
- Qt4 中的日期和时间
- 在 Qt4 中使用文件和目录
- Qt4 中的第一个程序
- Qt4 中的菜单和工具栏
- Qt4 中的布局管理
- Qt4 中的事件和信号
- Qt4 小部件
- Qt4 小部件 II
- Qt4 中的绘图
- Qt4 中的自定义小部件
- Qt4 中的打砖块游戏
- Qt5 教程
- Qt5 工具包简介
- Qt5 中的字符串
- Qt5 中的日期和时间
- Qt5 中的容器
- 在 Qt5 中处理文件和目录
- Qt5 中的第一个程序
- Qt5 中的菜单和工具栏
- Qt5 中的布局管理
- Qt5 中的事件和信号
- Qt5 小部件
- Qt5 小部件 II
- Qt5 中的绘图
- Qt5 中的自定义小部件
- Qt5 中的贪食蛇
- Qt5 中的打砖块游戏
- PySide 教程
- PySide 工具包简介
- PySide 中的第一个程序
- PySide 中的菜单和工具栏
- PySide 中的布局管理
- PySide 中的事件和信号
- PySide 中的对话框
- PySide 小部件
- PySide 小部件 II
- 在 PySide 中拖放
- 在 PySide 中绘图
- PySide 中的自定义小部件
- PySide 中的俄罗斯方块游戏
- Tkinter 教程
- Tkinter 简介
- Tkinter 中的布局管理
- Tkinter 标准小部件属性
- Tkinter 小部件
- Tkinter 中的菜单和工具栏
- Tkinter 中的对话框
- Tkinter 中的绘图
- Tkinter 中的贪食蛇
- Tcl/Tk 教程
- Tcl/Tk 简介
- Tcl/Tk 中的布局管理
- Tcl/Tk 小部件
- Tcl/Tk 中的菜单和工具栏
- Tcl/Tk 中的对话框
- Tcl/Tk 绘图
- 贪食蛇
- Qt 快速教程
- Java Swing 教程
- Java Swing 简介
- Java Swing 首个程序
- Java Swing 中的菜单和工具栏
- Swing 布局管理
- GroupLayout管理器
- Java Swing 事件
- 基本的 Swing 组件
- 基本的 Swing 组件 II
- Java Swing 对话框
- Java Swing 模型架构
- Swing 中的拖放
- Swing 中的绘图
- Java Swing 中的可调整大小的组件
- Java Swing 中的益智游戏
- 俄罗斯方块
- JavaFX 教程
- JavaFX 简介
- JavaFX 首个程序
- JavaFX 布局窗格
- 基本的 JavaFX 控件
- 基本 JavaFX 控件 II
- JavaFX 事件
- JavaFX 效果
- JavaFX 动画
- JavaFX 画布
- JavaFX 图表
- Java SWT 教程
- Java SWT 简介
- Java SWT 中的布局管理
- Java SWT 中的菜单和工具栏
- Java SWT 中的小部件
- Table小部件
- Java SWT 中的对话框
- Java SWT 绘图
- Java SWT 中的贪食蛇
- wxWidgets 教程
- wxWidgets 简介
- wxWidgets 助手类
- wxWidgets 中的第一个程序
- wxWidgets 中的菜单和工具栏
- wxWidgets 中的布局管理
- wxWidgets 中的事件
- wxWidgets 中的对话框
- wxWidgets 小部件
- wxWidgets 小部件 II
- wxWidgets 中的拖放
- wxWidgets 中的设备上下文
- wxWidgets 中的自定义小部件
- wxWidgets 中的俄罗斯方块游戏
- wxPython 教程
- wxPython 简介
- 第一步
- 菜单和工具栏
- wxPython 中的布局管理
- wxPython 中的事件
- wxPython 对话框
- 小部件
- wxPython 中的高级小部件
- wxPython 中的拖放
- wxPython 图形
- 创建自定义小部件
- wxPython 中的应用框架
- wxPython 中的俄罗斯方块游戏
- C# Winforms Mono 教程
- Mono Winforms 简介
- Mono Winforms 中的第一步
- Mono Winforms 中的布局管理
- Mono Winforms 中的菜单和工具栏
- Mono Winforms 中的基本控件
- Mono Winforms 中的高级控件
- 对话框
- Mono Winforms 中的拖放
- Mono Winforms 中的绘图
- Mono Winforms 中的贪食蛇
- Java Gnome 教程
- Java Gnome 简介
- Java Gnome 的第一步
- Java Gnome 中的布局管理
- Java Gnome 中的布局管理 II
- Java Gnome 中的菜单
- Java Gnome 中的工具栏
- Java Gnome 中的事件
- Java Gnome 中的小部件
- Java Gnome 中的小部件 II
- Java Gnome 中的高级小部件
- Java Gnome 中的对话框
- Java Gnome 中的 Pango
- 在 Java Gnome 中用 Cairo 绘图
- Cario 绘图 II
- Java Gnome 中的贪食蛇
- QtJambi 教程
- QtJambi 简介
- QtJambi 中的布局管理
- QtJambi 中的小部件
- QtJambi 中的菜单和工具栏
- QtJambi 对话框
- QtJambi 中的绘图
- QtJambi 中的自定义小部件
- 贪食蛇
- GTK+ 教程
- GTK+ 简介
- GTK+ 中的第一个程序
- GTK+ 中的菜单和工具栏
- GTK+ 布局管理
- GTK+ 事件和信号
- GTK+ 对话框
- GTK+ 小部件
- GTK+ 小部件 II
- GtkTreeView小部件
- GtkTextView小部件
- 自定义 GTK+ 小部件
- Ruby GTK 教程
- Ruby GTK 简介
- Ruby GTK 中的布局管理
- Ruby GTK 中的小部件
- Ruby GTK 中的菜单和工具栏
- Ruby GTK 中的对话框
- Ruby GTK Cario 绘图
- Ruby GTK 中的自定义小部件
- Ruby GTK 中的贪食蛇
- GTK# 教程
- GTK# 简介
- GTK 的第一步
- GTK# 中的布局管理
- GTK 中的菜单
- GTK# 中的工具栏
- GTK# 中的事件
- GTK# 中的小部件
- GTK 中的小部件 II
- GTK# 中的高级小部件
- GTK# 中的对话框
- Pango
- GTK# 中的 Cario 绘图
- GTK# 中的 Cario 绘图 II
- GTK# 中的自定义小部件
- Visual Basic GTK# 教程
- Visual Basic GTK# 简介
- 布局管理
- 小部件
- 菜单和工具栏
- 对话框
- Cario 绘图
- 自定义小部件
- 贪食蛇
- PyGTK 教程
- PyGTK 简介
- PyGTK 的第一步
- PyGTK 中的布局管理
- PyGTK 中的菜单
- PyGTK 中的工具栏
- PyGTK 中的事件和信号
- PyGTK 中的小部件
- PyGTK 中的小部件 II
- PyGTK 中的高级小部件
- PyGTK 中的对话框
- Pango
- Pango II
- PyGTK 中的 Cario 绘图
- Cario 绘图 II
- PyGTK 中的贪食蛇游戏
- PyGTK 中的自定义小部件
- PHP GTK 教程
- PHP GTK 简介
- PHP GTK 中的布局管理
- PHP GTK 中的小部件
- PHP GTK 中的菜单和工具栏
- 对话框
- Cario 绘图
- 自定义小部件
- 贪食蛇
- C# Qyoto 教程
- Qyoto 介绍
- 布局管理
- Qyoto 中的小部件
- Qyoto 中的菜单和工具栏
- Qyoto 对话框
- Qyoto 中的绘图
- Qyoto 中的绘图 II
- Qyoto 中的自定义小部件
- 贪食蛇
- Ruby Qt 教程
- Ruby Qt 简介
- Ruby Qt 中的布局管理
- Ruby Qt 中的小部件
- 菜单和工具栏
- Ruby Qt 中的对话框
- 用 Ruby Qt 绘图
- Ruby Qt 中的自定义小部件
- Ruby Qt 中的贪食蛇
- Visual Basic Qyoto 教程
- Qyoto 介绍
- 布局管理
- Qyoto 中的小部件
- Qyoto 中的菜单和工具栏
- Qyoto 对话框
- Qyoto 中的绘图
- Qyoto 中的自定义小部件
- 贪食蛇
- Mono IronPython Winforms 教程
- 介绍
- IronPython Mono Winforms 中的第一步
- 布局管理
- 菜单和工具栏
- Mono Winforms 中的基本控件
- Mono Winforms 中的基本控件 II
- Mono Winforms 中的高级控件
- 对话框
- Mono Winforms 中的拖放
- 绘图
- IronPython Mono Winforms 中的绘图 II
- IronPython Mono Winforms 中的贪食蛇
- IronPython Mono Winforms 中的俄罗斯方块游戏
- FreeBASIC GTK 教程
- Jython Swing 教程
- Jython Swing 简介
- Jython Swing 中的布局管理
- Jython Swing 中的组件
- Jython Swing 中的菜单和工具栏
- Jython Swing 中的对话框
- Jython Swing 中的绘图
- Jython Swing 中的半字节
- JRuby Swing 教程
- JRuby Swing 简介
- JRuby Swing 中的布局管理
- JRuby Swing 中的组件
- 菜单和工具栏
- JRuby Swing 中的对话框
- 在 JRuby Swing 中绘图
- JRuby Swing 中的贪食蛇
- Visual Basic Winforms 教程
- Visual Basic Winforms 简介
- 布局管理
- 基本控制
- 进阶控件
- 菜单和工具栏
- 对话框
- 绘图
- 拖放
- 贪食蛇
- JavaScript GTK 教程
- JavaScript GTK 简介
- 布局管理
- JavaScript GTK 中的小部件
- JavaScript GTK 中的菜单和工具栏
- JavaScript GTK 中的对话框
- JavaScript GTK 中的 Cario 绘图
- ZetCode Java 教程
- Java 教程
- Java 语言
- Java 语法结构
- Java 基础
- Java 数据类型
- Java 数据类型 II
- Java 字符串
- Java 数组
- Java 表达式
- Java 控制流程
- Java 面向对象的编程
- Java 方法
- Java 面向对象编程 II
- Java 包
- Java 中的异常
- Java 集合
- Java 流
- Java Future 教程
- Java Comparable和Comparator
- Java DOM 教程
- Java MVC 教程
- Java SAX 教程
- Java JAXB 教程
- Java JSON 处理教程
- Java H2 教程
- MongoDB Java 教程
- Java 正则表达式教程
- Java PDFBox 教程
- Java 文件教程
- Java Files.list教程
- Java Files.walk教程
- Java DirectoryStream教程
- Java 外部与内部迭代器
- Java 文件大小
- 用 Java 创建目录
- 用 Java 创建文件
- Java Log4j 教程
- Gson 教程
- Java RequestDispatcher
- Java HTTP GET/POST 请求
- Java InputStream教程
- Java FileOutputStream教程
- Java FileInputStream教程
- Java ZipInputStream教程
- Java FileWriter教程
- EJB 简介
- Java forEach教程
- Jetty 教程
- Tomcat Derby 教程
- Stripes 介绍
- 使用 Stripes 的 Java webapp,MyBatis,& Derby
- EclipseLink 简介
- Java 中的数据源
- JSTL 中的 SQL 查询标记
- Java 验证过滤器
- Hibernate 验证器
- 用 Java 显示图像
- Play 框架简介
- Spark Java 简介
- Java ResourceBundle教程
- Jtwig 教程
- Java Servlet 教程
- Java 套接字教程
- FreeMarker 教程
- Android 教程
- Java EE 5 教程
- JSoup 教程
- JFreeChart 教程
- ImageIcon教程
- 用 Java 复制文件
- Java 文件时间教程
- 如何使用 Java 获取当前日期时间
- Java 列出目录内容
- Java 附加到文件
- Java ArrayList教程
- 用 Java 读写 ICO 图像
- Java int到String的转换
- Java HashSet教程
- Java HashMap教程
- Java static关键字
- Java 中的HashMap迭代
- 用 Java 过滤列表
- 在 Java 中读取网页
- Java 控制台应用
- Java 集合的便利工厂方法
- Google Guava 简介
- OpenCSV 教程
- 用 Java8 的StringJoiner连接字符串
- Java 中元素迭代的历史
- Java 谓词
- Java StringBuilder
- Java 分割字串教学
- Java NumberFormat
- Java TemporalAdjusters教程
- Apache FileUtils教程
- Java Stream 过滤器
- Java 流归约
- Java 流映射
- Java InputStreamReader教程
- 在 Java 中读取文本文件
- Java Unix 时间
- Java LocalTime
- Java 斐波那契
- Java ProcessBuilder教程
- Java 11 的新功能
- ZetCode JavaScript 教程
- Ramda 教程
- Lodash 教程
- Collect.js 教程
- Node.js 简介
- Node HTTP 教程
- Node-config 教程
- Dotenv 教程
- Joi 教程
- Liquid.js 教程
- faker.js 教程
- Handsontable 教程
- PouchDB 教程
- Cheerio 教程
- Axios 教程
- Jest 教程
- JavaScript 正则表达式
- 用 JavaScript 创建对象
- Big.js 教程
- Moment.js 教程
- Day.js 教程
- JavaScript Mustache 教程
- Knex.js 教程
- MongoDB JavaScript 教程
- Sequelize 教程
- Bookshelf.js 教程
- Node Postgres 教程
- Node Sass 教程
- Document.querySelector教程
- Document.all教程
- JSON 服务器教程
- JavaScript 贪食蛇教程
- JavaScript 构建器模式教程
- JavaScript 数组
- XMLHttpRequest教程
- 从 JavaScript 中的 URL 读取 JSON
- 在 JavaScript 中循环遍历 JSON 数组
- jQuery 教程
- Google 图表教程
- ZetCode Kotlin 教程
- Kotlin Hello World 教程
- Kotlin 变量
- Kotlin 的运算符
- Kotlin when表达式
- Kotlin 数组
- Kotlin 范围
- Kotlin Snake
- Kotlin Swing 教程
- Kotlin 字符串
- Kotlin 列表
- Kotlin 映射
- Kotlin 集合
- Kotlin 控制流程
- Kotlin 写入文件
- Kotlin 读取文件教程
- Kotlin 正则表达式
- ZetCode 其它教程
- TCL 教程
- Tcl
- Tcl 语法结构
- Tcl 中的基本命令
- Tcl 中的表达式
- Tcl 中的控制流
- Tcl 中的字符串
- Tcl 列表
- Tcl 中的数组
- Tcl 中的过程
- 输入&输出
- AWK 教程
- Vaadin 教程
- Vaadin 框架介绍
- Vaadin Grid教程
- Vaadin TextArea教程
- Vaadin ComboBox教程
- Vaadin Slider教程
- Vaadin CheckBox教程
- Vaadin Button教程
- Vaadin DateField教程
- Vaadin Link教程
- ZetCode PHP 教程
- PHP 教程
- PHP
- PHP 语法结构
- PHP 基础
- PHP 数据类型
- PHP 字符串
- PHP 运算符
- PHP 中的控制流
- PHP 数组
- PHP 数组函数
- PHP 中的函数
- PHP 正则表达式
- PHP 中的面向对象编程
- PHP 中的面向对象编程 II
- PHP Carbon 教程
- PHP Monolog 教程
- PHP 配置教程
- PHP Faker 教程
- Twig 教程
- Valitron 教程
- Doctrine DBAL QueryBuilder 教程
- PHP Respect 验证教程
- PHP Rakit 验证教程
- PHP PDO 教程
- CakePHP 数据库教程
- PHP SQLite3 教程
- PHP 文件系统函数
- ZetCode Python 教程
- Python 教程
- Python 语言
- 交互式 Python
- Python 语法结构
- Python 数据类型
- Python 字符串
- Python 列表
- Python 字典
- Python 运算符
- Python 关键字
- Python 函数
- Python 中的文件
- Python 中的面向对象编程
- Python 模块
- Python 中的包
- Python 异常
- Python 迭代器和生成器
- Python 内省
- Python Faker 教程
- Python f 字符串教程
- Python bcrypt 教程
- Python 套接字教程
- Python smtplib教程
- OpenPyXL 教程
- Python pathlib教程
- Python YAML 教程
- Python 哈希教程
- Python ConfigParser教程
- Python 日志教程
- Python argparse 教程
- Python SQLite 教程
- Python Cerberus 教程
- Python PostgreSQL 教程
- PyMongo 教程
- PyMySQL 教程
- Peewee 教程
- pyDAL 教程
- pytest 教程
- Bottle 教程
- Python Jinja 教程
- PrettyTable 教程
- BeautifulSoup 教程
- pyquery 教程
- Python for循环
- Python 反转
- Python Lambda 函数
- Python 集合
- Python 映射
- Python CSV 教程-读写 CSV
- Python 正则表达式
- Python SimpleJson 教程
- SymPy 教程
- Pandas 教程
- Matplotlib 教程
- Pillow 教程
- Python FTP 教程
- Python Requests 教程
- Python Arrow 教程
- Python 列表推导式
- Python 魔术方法
- PyQt 中的QPropertyAnimation
- PyQt 中的QNetworkAccessManager
- ZetCode Ruby 教程
- Ruby 教程
- Ruby
- Ruby 语法结构
- Ruby 基础
- Ruby 变量
- Ruby 中的对象
- Ruby 数据类型
- Ruby 字符串
- Ruby 表达式
- Ruby 控制流
- Ruby 数组
- Ruby 哈希
- Ruby 中的面向对象编程
- Ruby 中的面向对象编程 II
- Ruby 正则表达式
- Ruby 输入&输出
- Ruby HTTPClient教程
- Ruby Faraday 教程
- Ruby Net::HTTP教程
- ZetCode Servlet 教程
- 从 Java Servlet 提供纯文本
- Java Servlet JSON 教程
- Java Servlet HTTP 标头
- Java Servlet 复选框教程
- Java servlet 发送图像教程
- Java Servlet JQuery 列表教程
- Servlet FreeMarker JdbcTemplate 教程-CRUD 操作
- jQuery 自动补全教程
- Java servlet PDF 教程
- servlet 从 WAR 内读取 CSV 文件
- Java HttpServletMapping
- EasyUI datagrid
- Java Servlet RESTFul 客户端
- Java Servlet Log4j 教程
- Java Servlet 图表教程
- Java ServletConfig教程
- Java Servlet 读取网页
- 嵌入式 Tomcat
- Java Servlet 分页
- Java Servlet Weld 教程
- Java Servlet 上传文件
- Java Servlet 提供 XML
- Java Servlet 教程
- JSTL forEach标签
- 使用 jsGrid 组件
- ZetCode Spring 教程
- Spring @Bean注解教程
- Spring @Autowired教程
- Spring @GetMapping教程
- Spring @PostMapping教程
- Spring @DeleteMapping教程
- Spring @RequestMapping教程
- Spring @PathVariable教程
- Spring @RequestBody教程
- Spring @RequestHeader教程
- Spring Cookies 教程
- Spring 资源教程
- Spring 重定向教程
- Spring 转发教程
- Spring ModelAndView教程
- Spring MessageSource教程
- Spring AnnotationConfigApplicationContext
- Spring BeanFactoryPostProcessor教程
- Spring BeanFactory教程
- Spring context:property-placeholder教程
- Spring @PropertySource注解教程
- Spring @ComponentScan教程
- Spring @Configuration教程
- Spring C 命名空间教程
- Spring P 命名空间教程
- Spring bean 引用教程
- Spring @Qualifier注解教程
- Spring ClassPathResource教程
- Spring 原型作用域 bean
- Spring Inject List XML 教程
- Spring 概要文件 XML 教程
- Spring BeanDefinitionBuilder教程
- Spring 单例作用域 bean
- 独立的 Spring 应用
- 经典 Spring 应用中的JdbcTemplate
- Spring EmbeddedDatabaseBuilder教程
- Spring HikariCP 教程
- Spring Web 应用简介
- Spring BeanPropertyRowMapper教程
- Spring DefaultServlet教程
- Spring WebSocket 教程
- Spring WebJars 教程
- Spring @MatrixVariable教程
- Spring Jetty 教程
- Spring 自定义 404 错误页面教程
- Spring WebApplicationInitializer教程
- Spring BindingResult教程
- Spring FreeMarker 教程
- Spring Thymeleaf 教程
- Spring ResourceHandlerRegistry教程
- SpringRunner 教程
- Spring MockMvc 教程
- ZetCode Spring Boot 教程
- Spring Boot 发送电子邮件教程
- Spring Boot WebFlux 教程
- Spring Boot ViewControllerRegistry教程
- Spring Boot CommandLineRunner教程
- Spring Boot ApplicationReadyEvent 教程
- Spring Boot CORS 教程
- Spring Boot @Order教程
- Spring Boot @Lazy教程
- Spring Boot Flash 属性
- Spring Boot CrudRepository 教程
- Spring Boot JpaRepository 教程
- Spring Boot findById 教程
- Spring Boot Data JPA @NamedQuery教程
- Spring Boot Data JPA @Query教程
- Spring Boot Querydsl 教程
- Spring Boot Data JPA 排序教程
- Spring Boot @DataJpaTest教程
- Spring Boot TestEntityManager 教程
- Spring Boot Data JPA 派生的查询
- Spring Boot Data JPA 查询示例
- Spring Boot Jersey 教程
- Spring Boot CSV 教程
- SpringBootServletInitializer教程
- 在 Spring Boot 中加载资源
- Spring Boot H2 REST 教程
- Spring Boot RestTemplate
- Spring Boot REST XML 教程
- Spring Boot Moustache 教程
- Spring Boot Thymeleaf 配置
- Spring Boot 自动控制器
- Spring Boot FreeMarker 教程
- Spring Boot Environment
- Spring Boot Swing 集成教程
- 在 Spring Boot 中提供图像文件
- 在 Spring Boot 中创建 PDF 报告
- Spring Boot 基本注解
- Spring Boot @ResponseBody教程
- Spring Boot @PathVariable教程
- Spring Boot REST Data JPA 教程
- Spring Boot @RequestParam教程
- Spring Boot 列出 bean
- Spring Boot @Bean
- Spring Boot @Qualifier教程
- 在 Spring Boot 中提供静态内容
- Spring Boot Whitelabel 错误
- Spring Boot DataSourceBuilder 教程
- Spring Boot H2 教程
- Spring Boot Web JasperReports 集成
- Spring Boot iText 教程
- Spring Boot cmd JasperReports 集成
- Spring Boot RESTFul 应用
- Spring Boot 第一个 Web 应用
- Spring Boot Groovy CLI
- Spring Boot 上传文件
- Spring Boot @ExceptionHandler
- Spring Boot @ResponseStatus
- Spring Boot ResponseEntity
- Spring Boot @Controller
- Spring Boot @RestController
- Spring Boot @PostConstruct
- Spring Boot @Component
- Spring Boot @ConfigurationProperties教程
- Spring Boot @Repository
- Spring Boot MongoDB 教程
- Spring Boot MongoDB Reactor 教程
- Spring Boot PostgreSQL 教程
- Spring Boot @ModelAttribute
- Spring Boot 提交表单教程
- Spring Boot Model
- Spring Boot MySQL 教程
- Spring Boot GenericApplicationContext
- SpringApplicationBuilder教程
- Spring Boot Undertow 教程
- Spring Boot 登录页面教程
- Spring Boot RouterFunction 教程
- ZetCode Symfony 教程
- Symfony DBAL 教程
- Symfony 表单教程
- Symfony CSRF 教程
- Symfony Vue 教程
- Symfony 简介
- Symfony 请求教程
- Symfony HttpClient教程
- Symfony Flash 消息
- 在 Symfony 中发送邮件
- Symfony 保留表单值
- Symfony @Route注解教程
- Symfony 创建路由
- Symfony 控制台命令教程
- Symfony 上传文件
- Symfony 服务教程
- Symfony 验证教程
- Symfony 翻译教程