有 JScrollPane 时如何定位 Java swing 组件
How to position Java swing components when there is a JScrollPane
我是制作 GUI 和 Java Swing 的新手,我正在尝试制作一个显示来自 SQL 数据库的 table 的 GUI。 table 使用 JScrollPane 显示。起初我以为我的其他组件(JLabel 和 JTextField)没有被添加到内容窗格,但实际上它们只是隐藏在 ScrollPane 下面。减小 ScrollPane 的尺寸后,现在这些其他组件出现了,但它们无法使用 setBounds 方法定位,并且始终出现在同一位置,因此最后添加的组件完全覆盖了其他组件。除了代码之外,我还提供了 GUI 外观的屏幕截图。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class LibraryAppGUI extends JFrame {
String sql;
String DB_PATH = LibraryAppGUI.class.getResource("LibraryManagement3.sqlite").getFile();
private JTable table;
private String columns[] = {"PatronFirstName", "PatronLastName"};
private TableModelListener tableModelListener;
public LibraryAppGUI () {
DefaultTableModel model = new DefaultTableModel(columns, 0);
table = new JTable(model);
try{populateSQL(table);} catch(Exception e1) {e1.printStackTrace();}
table.setCellSelectionEnabled(true);
table.setPreferredScrollableViewportSize(new Dimension(600, 300));
table.setFillsViewportHeight(false);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVisible(true);
getContentPane().add(scrollPane, BorderLayout.PAGE_START);
}
public void createSQL() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.jdbc");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement("");
}
public void populateSQL(JTable table) throws ClassNotFoundException, SQLException {
sql = "select PatronFirstName, PatronLastName\r\n" +
"FROM Patron\r\n";
Class.forName("org.sqlite.JDBC");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet res = stmt.executeQuery();
while(res.next()) {
Object[] row = new Object[columns.length];
for (int i = 1; i <= columns.length; i++) {
row[i-1] = res.getObject(i);
}
((DefaultTableModel) table.getModel()).insertRow(res.getRow()-1, row);
}
res.close();
connection.close();
}
public static void main(String[] args) {
LibraryAppGUI window = new LibraryAppGUI();
//label to prompt user
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
为什么要在两个不同的地方创建 Swing 组件?
- 不要在 main() 方法中创建组件。
- 标签、文本字段和 table 都应该在构造函数中创建并添加到框架中,方法与创建和添加 scrollpane/table.
相同
在下面的代码中:
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
不应使用 setBounds(...) 语句。默认情况下,框架的内容窗格使用 BorderLayout。布局管理器将根据布局管理器的规则设置组件的size/location。
如果您在添加组件时未指定约束,则使用 BorderLayout.CENTER
。但是,您只能将一个组件添加到 CENTER,因此只有文本字段被赋予正确的 size/location。标签被忽略。
因此,假设您将 GUI 代码从 main() 方法移至构造函数,正确的设计应该是:
JPanel top = new JPanel();
top.add(welcome);
top.add(user);
add(top, BorderLayot.PAGE_START);
那么您还可以使用:
//getContentPane().add(scrollPane, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
这将在框架顶部显示标签和文本字段,在中心显示滚动窗格。滚动条将随着框架大小的改变而自动调整。
我是制作 GUI 和 Java Swing 的新手,我正在尝试制作一个显示来自 SQL 数据库的 table 的 GUI。 table 使用 JScrollPane 显示。起初我以为我的其他组件(JLabel 和 JTextField)没有被添加到内容窗格,但实际上它们只是隐藏在 ScrollPane 下面。减小 ScrollPane 的尺寸后,现在这些其他组件出现了,但它们无法使用 setBounds 方法定位,并且始终出现在同一位置,因此最后添加的组件完全覆盖了其他组件。除了代码之外,我还提供了 GUI 外观的屏幕截图。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class LibraryAppGUI extends JFrame {
String sql;
String DB_PATH = LibraryAppGUI.class.getResource("LibraryManagement3.sqlite").getFile();
private JTable table;
private String columns[] = {"PatronFirstName", "PatronLastName"};
private TableModelListener tableModelListener;
public LibraryAppGUI () {
DefaultTableModel model = new DefaultTableModel(columns, 0);
table = new JTable(model);
try{populateSQL(table);} catch(Exception e1) {e1.printStackTrace();}
table.setCellSelectionEnabled(true);
table.setPreferredScrollableViewportSize(new Dimension(600, 300));
table.setFillsViewportHeight(false);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVisible(true);
getContentPane().add(scrollPane, BorderLayout.PAGE_START);
}
public void createSQL() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.jdbc");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement("");
}
public void populateSQL(JTable table) throws ClassNotFoundException, SQLException {
sql = "select PatronFirstName, PatronLastName\r\n" +
"FROM Patron\r\n";
Class.forName("org.sqlite.JDBC");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet res = stmt.executeQuery();
while(res.next()) {
Object[] row = new Object[columns.length];
for (int i = 1; i <= columns.length; i++) {
row[i-1] = res.getObject(i);
}
((DefaultTableModel) table.getModel()).insertRow(res.getRow()-1, row);
}
res.close();
connection.close();
}
public static void main(String[] args) {
LibraryAppGUI window = new LibraryAppGUI();
//label to prompt user
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
为什么要在两个不同的地方创建 Swing 组件?
- 不要在 main() 方法中创建组件。
- 标签、文本字段和 table 都应该在构造函数中创建并添加到框架中,方法与创建和添加 scrollpane/table. 相同
在下面的代码中:
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
不应使用 setBounds(...) 语句。默认情况下,框架的内容窗格使用 BorderLayout。布局管理器将根据布局管理器的规则设置组件的size/location。
如果您在添加组件时未指定约束,则使用 BorderLayout.CENTER
。但是,您只能将一个组件添加到 CENTER,因此只有文本字段被赋予正确的 size/location。标签被忽略。
因此,假设您将 GUI 代码从 main() 方法移至构造函数,正确的设计应该是:
JPanel top = new JPanel();
top.add(welcome);
top.add(user);
add(top, BorderLayot.PAGE_START);
那么您还可以使用:
//getContentPane().add(scrollPane, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
这将在框架顶部显示标签和文本字段,在中心显示滚动窗格。滚动条将随着框架大小的改变而自动调整。