【问题标题】:Swing: The Order of Execution of FunctionsSwing:函数的执行顺序
【发布时间】:2014-03-22 17:53:56
【问题描述】:

在我使用 Java SwingMySQL 实现的一个 DBMS 项目中,我遇到了一个非常有趣的问题。

考虑以下代码:

if(source == insert){
    insertRecord(columnNames, numOfColumns);
    getAllRecords();
    displayAllRecords();
}

预期结果:

此代码是事件处理程序的一部分,它决定单击按钮时要执行的操作。

当用户想要插入一条记录时,他单击按钮并调用insertRecord() 函数。这个插入函数继承自一个抽象类。

插入getAllRecords() 函数后,将执行“SELECT”查询并将结果存储到全局结果集中。

然后displayAllRecords()函数在屏幕上以表格的形式显示记录。

显然会发生什么:

在执行insertRecord() 函数时,其他两个函数getAllRecords()displayAllRecords() 也会执行。

这意味着插入后显示的不是我的数据,而是插入前存在的数据。

问题:

这似乎是一个与 Swing 和线程中的并发相关的问题,但是我可以应用任何简单的解决方案来使代码按照我想要的方式工作,并且不会对我的程序产生不利影响吗?

(如果你想看其他代码,请在cmets中告诉我,我会将它们作为编辑发布。原始代码很长,因此我没有发布。)


编辑 1:为上述方法添加代码:

getAllRecords() 代码

public void getAllRecords(){
    // res is a global ResultSet field  
    try{
        res = sqlConn.getStatement().executeQuery("SELECT * FROM " + tableName);
    }catch(Exception e){
        System.out.println("Error obtaining data!");
    }
}

代码:displayAllRecords()

public void displayAllRecords() {

    try{
        table = new JTable(buildTableModel());      // code provided at bottom
    }
    catch(SQLException e){
        e.printStackTrace();
        JOptionPane.showMessageDialog(null, "Unexpected error!");
    }
    displayResult();
}

displayResult()代码

public void displayResult(){
    //updates the view port of the JScrollPane that is used for the table
    tablePane.getViewport().remove(table);
    table.revalidate();
    tablePane.getViewport().add(table);
    custFrame.repaint();
}

buildTableModel() 代码

public DefaultTableModel buildTableModel() throws SQLException{
    //res is a global ResultSet field
    Vector<String> columnNames = new Vector<String>();
    Vector<Vector<Object>> data = new Vector<Vector<Object>>();
    ResultSetMetaData metadata = res.getMetaData();

    //getting names of columns
    int columnCount = metadata.getColumnCount();
    for(int i = 0; i < columnCount; i++){
        columnNames.add(metadata.getColumnName(i+1));
    }

    //getting all data
    while(res.next()){
        Vector<Object> vec = new Vector<Object>();
        for(int i = 0; i < columnCount; i++){
            vec.add(res.getObject(i+1));
        }
        data.add(vec);
    }
    return new DefaultTableModel(data, columnNames);        
}

insertRecord() 的代码

public void insertRecord(ArrayList<String> columnNames, int numOfColumns){

    //creation of the GUI... don't know if it matters so kept it
    formFrame = new JFrame("INSERT DATA IN TABLE");
    labelList = new ArrayList<JLabel>();
    textList  = new ArrayList<JTextField>();
    submit = new JButton("SUBMIT");      
    prompt = new JLabel("Enter all the details:");

    formFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    formFrame.setAlwaysOnTop(true);
    formFrame.setResizable(false);
    formFrame.setAutoRequestFocus(true);

    formFrame.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();

    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.insets = new Insets(10, 10, 10, 10);
    gbc.fill = GridBagConstraints.BOTH;

    formFrame.add(prompt, gbc);
    gbc.gridy++;

    for(int i = 0; i < numOfColumns; i++, gbc.gridy++){

        labelList.add(new JLabel());
        labelList.get(i).setText(columnNames.get(i).toUpperCase());
        formFrame.add(labelList.get(i), gbc);

    }

    gbc.gridx = 1;
    gbc.gridy = 1;

    for(int i = 0; i < numOfColumns; i++, gbc.gridy++){

        textList.add(new JTextField(30));
        formFrame.add(textList.get(i), gbc);

    }

    gbc.gridx = 0;
    gbc.gridwidth = 2;
    formFrame.add(submit, gbc);

    formFrame.pack();
    formFrame.setVisible(true); 

    // creation and processing of the insert query

    class InsertHandler implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e){

            String query = "INSERT INTO " + tableName
                    + " VALUES( "; 

            int numOfColumns = textList.size();
            for(int i = 0; i < numOfColumns - 1; ++i){
                query +=  "'" + textList.get(i).getText() + "', ";
            }

            query += "'" + textList.get(numOfColumns-1).getText() + "')";

            try {
                sqlConn.getStatement().executeUpdate(query);
            } catch (SQLException e1) {
                JOptionPane.showMessageDialog(null, "Insertion failed!");
            }

        }

    };

    submit.addActionListener(new InsertHandler());

}

(抱歉,代码太长太复杂了。我已尽力评论它。我将不胜感激您提供的任何帮助。)

【问题讨论】:

  • 问题出在您的代码中。向我们展示这些方法的代码。此处使用单个线程,即事件调度线程。
  • 我在 Swing 中遇到过类似的并发问题。在一个程序中我首先通过自定义方法移动一个JPanel,然后在移动后获取位置;但是每次我在搬家前得到位置。
  • 添加了代码。还评论了它以使其更易于理解,因为我是一名学生,我的编程方法可能看起来有点粗糙。
  • +1 对于一个写得很好的问题。问题主要是并发问题。不确定,但阅读文档可能会有所帮助:docs.oracle.com/javase/tutorial/uiswing/concurrency
  • @JBNizet:你能帮我解决这个问题吗?

标签: java mysql swing concurrency


【解决方案1】:

您的insertRecord() 方法不会在数据库中插入记录。它所做的只是显示一个新框架。然而,您希望在显示这个新框架之后,记录被插入并准备好被读取和显示。事实并非如此。

要插入,用户必须盯着框架,喝完咖啡,去洗手间,回来,最后决定点击提交按钮。然后,只有这样,数据才会被插入到数据库中。但是getAllRecords()displayAllRecords()方法会执行很久,因为只要一帧显示出来,调用的方法就继续执行。

所以,这里有两个解决方案:

  1. insertRecord() 显示的框架替换为模态JDialog。模态 JDialog 将阻止执行,直到对话框关闭。然后,您将能够检查用户是否确实单击了提交按钮,并刷新显示的数据。

  2. 数据插入成功后,调用InsertHandler.actionPerformed()方法中的方法刷新数据。

【讨论】:

  • 所以这意味着我的insertRecord()函数不等待用户输入,而只是显示表单并返回。当用户输入不属于insertRecord() 方法的部分时。对吗?
  • 你明白了。模态 JDialog 将具有您期望的行为。否则,Swing 是基于事件的,并且永远不会阻塞等待用户输入。
  • 非常感谢先生。非常感谢您浏览我的代码并帮助我。
  • 我有一个请求。你能告诉我如何在我的程序中使用模态对话框方法吗?只需一个示例或一段代码即可提供帮助。
  • 代码几乎和你现在的一样。您可以使用new JDialog(true),而不是new JFrame()。只需确保最后调用 setVisible(true),因为 setVisible(true) 之后的所有内容都将被阻止,直到用户关闭对话框。
猜你喜欢
  • 2016-04-07
  • 2017-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多