I am trying to fetch data from the database and publish the result on a JPanel
.
Here is the simplified code:
public class LedgerView extends JPanel {
public LedgerView() {
super();
this.setLayout(new FlowLayout());
this.add(new JLabel("ITEMS:"));
String JDBC_DRIVER = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost/gnufinance";
String USERNAME = "gnufinance";
String PASSWORD = "gnuisnotunix";
Connection conn = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
String query = "SELECT * FROM transactions";
try {
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String desc = rs.getString(3);
System.out.println(desc);
this.add(new JLabel(desc));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame view = new JFrame();
view.setVisible(true);
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
}
Nothing is displayed except a blank grayed frame, but when I remove the JDBC code, the first JLabel(ITEMS)
is displayed. There is nothing on the screen but the System.out.println
in the while loop prints all the data properly on the console. There are no exceptions.
答案 0 :(得分:2)
You have to create the panel on the Event Dispatch Thread, or EDT.
Swing is not Thread Safe; any changes that you make to swing controls (such as creating new JLabel
s), must occur on the EDT (which is not the thread your main
method starts on. You use EventQueue.invokeLater()
to tell Java to move the work onto the Swing drawing thread.
Note that most of the time you do not want your work (like accessing a database) to occur on the EDT because it will make your user interface unresponsive. In other words, your program will be doing the work of accessing the database when it could, instead, be drawing your screen.
This code will fix your immediate problem, but you should consider accessing the database somewhere else (perhaps, for now, in your main
method), storing the result in a List
, and then passing the List
to your LedgerView
, which will result in a more responsive user interface.
public static void main(String[] args) {
final JFrame view = new JFrame();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
view.setVisible(true);
}
}
}