创建 Inspector-like 东西时 JScrollPane 和 GridBagLayout 问题
JScrollPane and GridBagLayout problems while creating Inspector-like thing
我正在为我的程序创建检查面板之类的东西,因此我可以在 运行 时轻松更改一些变量。
当你运行下面的代码时,你应该看到这样的东西:
inspector screenshot
有几件事困扰着我,我仍然无法使它们正常工作。
- 项目与中心垂直对齐...我已经尝试将锚点设置为北方,但它保持不变。在下面的示例代码中,有一行被注释掉可以解决这个问题:
inspector.finish()
但这个解决方案对我来说似乎有点老套。它的工作原理是将空的 JPanel 添加为面板上的最后一项,充当某种垂直胶水以扩展下部区域并将组件向上推。我不喜欢这个,因为有了这个解决方案,我以后无法再在 运行 时间向检查器添加更多项目。
- 如果您向检查器添加更多项目(您可以通过更改 n 变量来为检查器填充一些测试数据),滚动条将不会显示,并且所有较低的项目都在屏幕外,即使它都被包裹在 JScrollPane 中......我已经尝试了几个 hack 来解决这个问题,但是 none 它们可以正常工作。其中之一是将 JPanel 的 preferredSize 设置为一些 hard-coded 尺寸,但我不喜欢这样,因为我不知道面板的确切尺寸。
- 当您按下一些微调按钮然后单击组合框(标题为 "choose me")时,选项将隐藏在下面的按钮后面。这看起来像是某种 z-ordering 问题。也许这是 swing 中的错误,不知道。
- 当您将 window 垂直调整为更小尺寸时,顶部的项目将开始缩小,而不是保持相同尺寸。是否有任何选项可以始终将它们设置为恒定高度?
也许我使用了错误的布局管理器,但我不知道该选择哪个。我在考虑简单的网格布局,但这不允许我做一些事情,比如让一些行包含一个项目,而另一些行包含多个项目,这样它们将始终使用行的整个宽度 "capacity"。
示例代码:
import java.awt.*;
import javax.swing.*;
public class Test {
// Setup test scenario
public Test() {
// Create window
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setSize(800, 600);
f.setTitle("Inspector");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// Create panel which will be used for the inspector
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(200, 0));
// Encapsulate it to the scroll panel so it can grow vertically
JScrollPane sp = new JScrollPane();
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sp.setViewportView(p);
// Create the inspector inside panel p
Inspector inspector = new Inspector(p);
// Fill the inspector with some test data
int n = 3;
for (int i = 0; i < n; ++i) {
inspector.addTitle("Title");
inspector.addButton("push me");
inspector.addCheckBox("check me");
inspector.addSpinner("Spin me");
inspector.addTextField("Edit me", "here");
inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
inspector.addSeparator();
}
//inspector.finish();
// The inspector will be on the right side of the window
f.getContentPane().add(sp, BorderLayout.LINE_END);
// Show the window
f.setVisible(true);
}
// Main method
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
// Inspector class itself
private class Inspector {
private final JPanel panel;
private final GridBagConstraints constraints;
private int itemsCount = 0;
public Inspector(JPanel p) {
panel = p;
panel.setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 0.5;
}
// Adds component which will span across whole row
private void addComponent(Component component) {
constraints.gridx = 0;
constraints.gridwidth = 2;
constraints.gridy = itemsCount;
panel.add(component, constraints);
itemsCount++;
}
// Adds descriptive label on the left and component on the right side of the row
private void addNamedComponent(String description, Component component) {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(new JLabel(description), constraints);
constraints.gridx = 1;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(component, constraints);
itemsCount++;
}
public void addSeparator() {
// (little hacky)
addComponent(new JPanel());
}
public void addTitle(String title) {
addComponent(new JLabel(title));
}
public void addButton(String actionName) {
addComponent(new Button(actionName));
}
public void addCheckBox(String description) {
addNamedComponent(description, new JCheckBox());
}
public void addSpinner(String description) {
addNamedComponent(description, new JSpinner());
}
public void addTextField(String description, String text) {
addNamedComponent(description, new JTextField(text));
}
public void addComboBox(String description, String[] options) {
JComboBox<String> comboBox = new JComboBox<>();
ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
comboBox.setModel(model);
addNamedComponent(description, comboBox);
}
public void finish() {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 2;
constraints.weighty = 1.0;
panel.add(new JPanel(), constraints);
}
}
}
您无法向上或向下滚动的原因是您将 sp
的首选大小设置为 200x0。您需要删除此行。
p.setPreferredSize(new Dimension(200, 0));
至于一切都居中而不是顶部的问题。我更愿意将 p
保留为默认值 FlowLayout
,并为每个 "section" 提供自己的面板,并使该面板成为 GridBagLayout
。通过这样做,您可能不再需要 addSeparator()
。
public class Test {
// Setup test scenario
public Test() {
// Create window
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setSize(800, 600);
f.setTitle("Inspector");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// Create panel which will be used for the inspector
JPanel p = new JPanel();
// Encapsulate it to the scroll panel so it can grow vertically
JScrollPane sp = new JScrollPane();
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sp.setViewportView(p);
// Create the inspector inside panel p
Inspector inspector = new Inspector(p);
// Fill the inspector with some test data
int n = 2;
for (int i = 0; i < n; ++i) {
inspector.addTitle("Title");
inspector.addButton("push me");
inspector.addCheckBox("check me");
inspector.addSpinner("Spin me");
inspector.addTextField("Edit me", "here");
inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
}
// The inspector will be on the right side of the window
f.getContentPane().add(sp, BorderLayout.LINE_END);
// Show the window
f.setVisible(true);
}
// Main method
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
// Inspector class itself
private class Inspector {
private final JPanel panel;
private final GridBagConstraints constraints;
private int itemsCount = 0;
public Inspector(JPanel p) {
panel = new JPanel();
p.add(panel);
panel.setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
}
// Adds component which will span across whole row
private void addComponent(Component component) {
constraints.gridx = 0;
constraints.gridwidth = 2;
constraints.gridy = itemsCount;
panel.add(component, constraints);
itemsCount++;
}
// Adds descriptive label on the left and component on the right side of the row
private void addNamedComponent(String description, Component component) {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(new JLabel(description), constraints);
constraints.gridx = 1;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(component, constraints);
itemsCount++;
}
public void addSeparator() {
// (little hacky)
addComponent(new JPanel());
}
public void addTitle(String title) {
addComponent(new JLabel(title));
}
public void addButton(String actionName) {
addComponent(new Button(actionName));
}
public void addCheckBox(String description) {
addNamedComponent(description, new JCheckBox());
}
public void addSpinner(String description) {
addNamedComponent(description, new JSpinner());
}
public void addTextField(String description, String text) {
addNamedComponent(description, new JTextField(text));
}
public void addComboBox(String description, String[] options) {
JComboBox<String> comboBox = new JComboBox<>();
ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
comboBox.setModel(model);
addNamedComponent(description, comboBox);
}
public void finish() {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 2;
constraints.weighty = 1.0;
panel.add(new JPanel(), constraints);
}
}
}
我正在为我的程序创建检查面板之类的东西,因此我可以在 运行 时轻松更改一些变量。
当你运行下面的代码时,你应该看到这样的东西: inspector screenshot
有几件事困扰着我,我仍然无法使它们正常工作。
- 项目与中心垂直对齐...我已经尝试将锚点设置为北方,但它保持不变。在下面的示例代码中,有一行被注释掉可以解决这个问题:
inspector.finish()
但这个解决方案对我来说似乎有点老套。它的工作原理是将空的 JPanel 添加为面板上的最后一项,充当某种垂直胶水以扩展下部区域并将组件向上推。我不喜欢这个,因为有了这个解决方案,我以后无法再在 运行 时间向检查器添加更多项目。 - 如果您向检查器添加更多项目(您可以通过更改 n 变量来为检查器填充一些测试数据),滚动条将不会显示,并且所有较低的项目都在屏幕外,即使它都被包裹在 JScrollPane 中......我已经尝试了几个 hack 来解决这个问题,但是 none 它们可以正常工作。其中之一是将 JPanel 的 preferredSize 设置为一些 hard-coded 尺寸,但我不喜欢这样,因为我不知道面板的确切尺寸。
- 当您按下一些微调按钮然后单击组合框(标题为 "choose me")时,选项将隐藏在下面的按钮后面。这看起来像是某种 z-ordering 问题。也许这是 swing 中的错误,不知道。
- 当您将 window 垂直调整为更小尺寸时,顶部的项目将开始缩小,而不是保持相同尺寸。是否有任何选项可以始终将它们设置为恒定高度?
也许我使用了错误的布局管理器,但我不知道该选择哪个。我在考虑简单的网格布局,但这不允许我做一些事情,比如让一些行包含一个项目,而另一些行包含多个项目,这样它们将始终使用行的整个宽度 "capacity"。
示例代码:
import java.awt.*;
import javax.swing.*;
public class Test {
// Setup test scenario
public Test() {
// Create window
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setSize(800, 600);
f.setTitle("Inspector");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// Create panel which will be used for the inspector
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(200, 0));
// Encapsulate it to the scroll panel so it can grow vertically
JScrollPane sp = new JScrollPane();
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sp.setViewportView(p);
// Create the inspector inside panel p
Inspector inspector = new Inspector(p);
// Fill the inspector with some test data
int n = 3;
for (int i = 0; i < n; ++i) {
inspector.addTitle("Title");
inspector.addButton("push me");
inspector.addCheckBox("check me");
inspector.addSpinner("Spin me");
inspector.addTextField("Edit me", "here");
inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
inspector.addSeparator();
}
//inspector.finish();
// The inspector will be on the right side of the window
f.getContentPane().add(sp, BorderLayout.LINE_END);
// Show the window
f.setVisible(true);
}
// Main method
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
// Inspector class itself
private class Inspector {
private final JPanel panel;
private final GridBagConstraints constraints;
private int itemsCount = 0;
public Inspector(JPanel p) {
panel = p;
panel.setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 0.5;
}
// Adds component which will span across whole row
private void addComponent(Component component) {
constraints.gridx = 0;
constraints.gridwidth = 2;
constraints.gridy = itemsCount;
panel.add(component, constraints);
itemsCount++;
}
// Adds descriptive label on the left and component on the right side of the row
private void addNamedComponent(String description, Component component) {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(new JLabel(description), constraints);
constraints.gridx = 1;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(component, constraints);
itemsCount++;
}
public void addSeparator() {
// (little hacky)
addComponent(new JPanel());
}
public void addTitle(String title) {
addComponent(new JLabel(title));
}
public void addButton(String actionName) {
addComponent(new Button(actionName));
}
public void addCheckBox(String description) {
addNamedComponent(description, new JCheckBox());
}
public void addSpinner(String description) {
addNamedComponent(description, new JSpinner());
}
public void addTextField(String description, String text) {
addNamedComponent(description, new JTextField(text));
}
public void addComboBox(String description, String[] options) {
JComboBox<String> comboBox = new JComboBox<>();
ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
comboBox.setModel(model);
addNamedComponent(description, comboBox);
}
public void finish() {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 2;
constraints.weighty = 1.0;
panel.add(new JPanel(), constraints);
}
}
}
您无法向上或向下滚动的原因是您将 sp
的首选大小设置为 200x0。您需要删除此行。
p.setPreferredSize(new Dimension(200, 0));
至于一切都居中而不是顶部的问题。我更愿意将 p
保留为默认值 FlowLayout
,并为每个 "section" 提供自己的面板,并使该面板成为 GridBagLayout
。通过这样做,您可能不再需要 addSeparator()
。
public class Test {
// Setup test scenario
public Test() {
// Create window
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setSize(800, 600);
f.setTitle("Inspector");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// Create panel which will be used for the inspector
JPanel p = new JPanel();
// Encapsulate it to the scroll panel so it can grow vertically
JScrollPane sp = new JScrollPane();
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sp.setViewportView(p);
// Create the inspector inside panel p
Inspector inspector = new Inspector(p);
// Fill the inspector with some test data
int n = 2;
for (int i = 0; i < n; ++i) {
inspector.addTitle("Title");
inspector.addButton("push me");
inspector.addCheckBox("check me");
inspector.addSpinner("Spin me");
inspector.addTextField("Edit me", "here");
inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
}
// The inspector will be on the right side of the window
f.getContentPane().add(sp, BorderLayout.LINE_END);
// Show the window
f.setVisible(true);
}
// Main method
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
// Inspector class itself
private class Inspector {
private final JPanel panel;
private final GridBagConstraints constraints;
private int itemsCount = 0;
public Inspector(JPanel p) {
panel = new JPanel();
p.add(panel);
panel.setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
}
// Adds component which will span across whole row
private void addComponent(Component component) {
constraints.gridx = 0;
constraints.gridwidth = 2;
constraints.gridy = itemsCount;
panel.add(component, constraints);
itemsCount++;
}
// Adds descriptive label on the left and component on the right side of the row
private void addNamedComponent(String description, Component component) {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(new JLabel(description), constraints);
constraints.gridx = 1;
constraints.gridy = itemsCount;
constraints.gridwidth = 1;
panel.add(component, constraints);
itemsCount++;
}
public void addSeparator() {
// (little hacky)
addComponent(new JPanel());
}
public void addTitle(String title) {
addComponent(new JLabel(title));
}
public void addButton(String actionName) {
addComponent(new Button(actionName));
}
public void addCheckBox(String description) {
addNamedComponent(description, new JCheckBox());
}
public void addSpinner(String description) {
addNamedComponent(description, new JSpinner());
}
public void addTextField(String description, String text) {
addNamedComponent(description, new JTextField(text));
}
public void addComboBox(String description, String[] options) {
JComboBox<String> comboBox = new JComboBox<>();
ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
comboBox.setModel(model);
addNamedComponent(description, comboBox);
}
public void finish() {
constraints.gridx = 0;
constraints.gridy = itemsCount;
constraints.gridwidth = 2;
constraints.weighty = 1.0;
panel.add(new JPanel(), constraints);
}
}
}