我有一个 Java 8 应用程序,其中有几个
JTextField
和一个用于登录数据库的 JButton
,以及 JTextArea
内的 JScrollPane
用于显示错误。如果没有要显示的错误消息,则文本区域和滚动窗格都必须隐藏 (setVisible(false)
)。
public static ResourceBundle resourceBundle;
private static JTextArea textarea_error;
private JScrollPane scrollPane_error;
private JButton button_login;
private Connection connection = null;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
resourceBundle = ResourceBundle.getBundle("Bundle", Locale.English);
Main frame = new Main();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
//Error handling with the TextArea
}
}
});
}
public Main() {
textarea_error = new JTextArea();
textarea_error.setEditable(false);
textarea_error.setText("Error");
scrollPane_error = new JScrollPane(textarea_error);
scrollPane_error.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
button_login = new JButton(resourceBundle.getString("main.button.login"));
button_login.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
startLogin();
}
});
//Aligning components,... here
textarea_error.setVisible(false);
scrollPane_error.setVisible(false); //this
}
private void startLogin() {
//Read TextField input content here (user, pw, server-url)
SwingWorker<String, String> sw = new SwingWorker<String, String>() {
@Override
protected String doInBackground() throws Exception {
login(user,pw,server);
return null;
}
};
sw.execute();
}
private void login(String user, String pw, String server) {
try {
DriverManager.registerDriver(new SQLServerDriver());
connection = DriverManager.getConnection(server, user, pw);
Statement s = connection.createStatement();
} catch (SQLException e) {
scrollPane_error.setVisible(true); //this
textarea_error.setText(resourceBundle.getString("main.error.userpw"));
textarea_error.setCaretPosition(0);
textarea_error.setVisible(true);
}
}
问题:当出现错误(例如错误的用户名或密码)但文本区域和滚动窗格仍然不可见时,会调用
catch
。如果我只更改文本区域的可见性并始终使滚动窗格保持可见(=删除两个“此”行 - 这也始终显示滚动窗格的边框),那么这工作正常,但一旦我也设置了滚动窗格的可见性,它也不会或者它的孩子回来了。
我不想使用
setEnable
,因为我希望它们仍然占用空间,即使不需要它们。
我已经尝试使用
invalidate
、revalidate
和 repaint
(甚至在滚动窗格上)但这没有帮助。我setVisible(true)
这两个组件的顺序似乎也并不重要。
为什么会发生这种情况以及如何解决?
这是我创建的一个简单示例。
当 GUI 出现时,
JTextArea
和 JScrollPane
设置为不可见。当您单击“登录”JButton
时,JTextArea
和JScrollPane
将变得可见并显示错误消息。
这是完整的可运行代码。全部 102 行。
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class LoginExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new LoginExample());
}
private JFrame frame;
private JScrollPane scrollPane;
private JTextArea errorArea;
@Override
public void run() {
frame = new JFrame("Login Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createLoginPanel(), BorderLayout.CENTER);
frame.add(createMessagePanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public JPanel createLoginPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.gridx = 0;
gbc.gridy = 0;
JLabel label = new JLabel("UserID:");
panel.add(label, gbc);
gbc.gridx++;
JTextField useridField = new JTextField(20);
panel.add(useridField, gbc);
gbc.gridx = 0;
gbc.gridy++;
label = new JLabel("Password:");
panel.add(label, gbc);
gbc.gridx++;
JPasswordField passwordField = new JPasswordField(20);
panel.add(passwordField, gbc);
gbc.gridwidth = 2;
gbc.gridx = 0;
gbc.gridy++;
JButton button = new JButton("Login");
panel.add(button, gbc);
button.addActionListener(e -> {
errorArea.setText("Error message");
errorArea.setVisible(true);
scrollPane.setVisible(true);
frame.pack();
});
return panel;
}
private JPanel createMessagePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
errorArea = new JTextArea(5, 30);
errorArea.setWrapStyleWord(true);
errorArea.setLineWrap(true);
errorArea.setEditable(false);
errorArea.setVisible(false);
scrollPane = new JScrollPane(errorArea);
scrollPane.setVisible(false);
panel.add(scrollPane);
return panel;
}
}
根据您问题中的代码,您正在从
SwingWorker调用方法
login
,这意味着方法 login
确实 not 在 Event Dispatch Thread (EDT)中运行,并且您正在设置 ScrollPane
在该方法中可见。
直接从方法
login
调用方法 startLogin
,即完全取消 SwingWorker
,或者向 SwingWorker
添加 done方法,或者使用
SwingWorker
注册一个 PropertyChangeListener(通过方法添加PropertyChangeListener)。