【问题标题】:JButton stays in pressed stateJButton 保持按下状态
【发布时间】:2011-09-25 07:56:19
【问题描述】:

在我的 Java GUI 应用程序中,我有一个 JButton,当单击它时,它会调用 function 来连接到 database,然后在 DB 中调用 functionclear table ,然后调用从一个文件中读取文本的function并加载variables,它调用从另一个文件中读取文本的function,比较两者中的data,然后调用function与@987654333中的任何一个@ 或 insert 数据库中的数据,所有这些都可以正常工作。

但是我的问题与JButton 相关,当它被点击时我想运行Indeterminate progress bar 只是为了让用户知道工作正在完成,然后在它离开action listener setIndeterminate to false 之前设置值progress bar100(complete),但在我的情况下,当您单击 button 时,它会保持单击状态,而 progress bar 会冻结。

我应该采取什么措施来防止这种情况发生?线程可能?但我对java中的线程很陌生。这是我的动作监听器:

    private class buttonListener implements ActionListener
        {
            public void actionPerformed(ActionEvent e)
            {
                if( e.getSource() == genButton )
                {
                    progressBar.setIndeterminate(true);
                    progressBar.setString(null);
                    try 
                    {
                        dbConnect(); //connects to DB
                        clearSchedules(); // deletes data in tables
                        readFile(); // reads first file and calls the other functions
                        dbClose();// closes the DB
                        progressBar.setIndeterminate(false);
                        progressBar.setValue(100);
                    } 
                    catch (Exception e1){
                        System.err.println("Error: " + e1.getMessage());
                    }
                }
            }
        }

顺便说一句,我想让操作栏随着程序的进行而实际移动,但我不确定如何监控它的进度。

谢谢,牛肉。

更新这是我的 SwingWorker 示例以及我如何使用它:

全局声明

 private functionWorker task;


    private abstract class functionWorker extends SwingWorker { 

        public void execute() {
            try {
                dbConnect();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            clearSchedules();
            try {
                readFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            dbClose();
        }
    }

在我的 actionPerformed 方法中

if( e.getSource() == genButton )
            {

                progressBar.setIndeterminate(true);
                progressBar.setString(null);
                try 
                {
                    task.execute();

                    progressBar.setIndeterminate(false);
                    progressBar.setValue(100);
                } 
                catch (Exception e1){
                    System.err.println("Error: " + e1.getMessage());
                }
            }

【问题讨论】:

  • 请学习java命名约定并遵守它们
  • 通常,覆盖 doInBackground 不执行 ... 无论如何都是最终的。检查您的 jdk 和类路径,如果在 6+ 上删除任何 swingworker.jar(旧的独立版本)
  • @kleopatra 我的命名约定到底有什么问题?我读了它,我看不出我哪里出错了,至少在这些代码 sn-ps
  • 类名应该大写
  • @kleopatra 啊谢谢,我会解决这个问题,我正在使用 jdk 7

标签: java swing actionlistener swingworker jprogressbar


【解决方案1】:

问题可能与连接到 UI 线程中执行昂贵的操作(连接到数据库、从文件读取、调用其他函数)有关。在任何情况下,您都不应从 UI 线程调用占用过多 CPU 时间的代码,因为整个界面在执行代码时无法继续,这会导致应用程序看起来“死”,组件仍处于其状态从昂贵的操作到完成之前的时间。您应该执行另一个线程,在其中完成昂贵的工作,然后使用 SwingUtilities.invokeLater(Runnable doRun) 和传递的可运行对象来更新进度。

可能存在与组件状态相关的同步问题,但您可以稍后解决这些问题。

【讨论】:

  • 昂贵的操作是指必须在java程序本身之外进行的操作,例如文本文件和db?
  • 是的。 CPU 时间成本高。
  • 那么我可以在执行操作时创建新线程并调用线程中的新函数,还是应该在实际函数本身内进行线程处理?
  • 您应该在侦听器方法中创建新线程。这并不是一项真正昂贵的手术。有一些方法可以改进这一点(例如,使用外部创建的执行器),但这并不重要。
  • 好的,我在java中没有做过很多线程,对我做的不是很了解,但我再试一次,谢谢你的帮助
【解决方案2】:

我可以在执行操作时创建新线程并调用线程中的新函数,还是应该在实际函数本身中进行线程处理?

您可以从按钮的处理程序中启动SwingWorker,如here 所示。实现Runnable 的相关示例见here

【讨论】:

  • 谢谢,我会看看我能从这些例子中得到什么,并尝试相应地实现它们
  • 仔细观察您的旁注,TwoRoot 是一个在SwingWorker 中显示增量进度的示例。
  • 再次感谢,一旦完成线程部分,我会检查一下,仍在尝试分解示例
  • 所以我会创建一个SwingWorker 就像private class functionWorker extends SwingWorker {} 但在SwingWorker 中调用我的4 个方法然后创建SwingWorker 的任务并在我的actionlistener 中执行该任务,似乎在第一个示例中发生了很多事情,我很难理解它
  • 确实,TableAddTest 看起来 更容易,但SwingWorker 提供更多杠杆作用。 [RandomDataDemo]() 显示一个数据库连接。它声明SwingWorker<List<Double>, Double>,但您必须选择所需的粒度。也许SwingWorker<List<Record>, Record>Record 代表一个文件的内容和元数据?
【解决方案3】:

处理进度条的一种方法是在类中扩展SwingWorkerSwingWorker 负责为您运行后台任务,因此您不必实现可能导致未知问题的自己的线程。 首先,处理进度条 UI 的类应该实现 PropertyChangeListener 并实现public void propertyChange(PropertyChangeEvent evt) { - 根据全局变量更新进度条状态。

后台任务类应该如下所示(这可能是一个内部类):

class ProgressTask extends SwingWorker<Void, Void> {
        @Override
        public Void doInBackground() {
             //handle your tasks here
             //update global variable to indicate task status.
        }
        @Override
        public void done() {
             //re-enabled your button
        }
}

在按钮的事件监听器上:

 public void actionPerformed(ActionEvent evt) {
    //disable your button
    //Create new instance of "ProgressTask"
    //make the task listen to progress changes by task.addPropertyChangeListener(this);
    //calll task.execute();
 }

我试图淡化代码示例,您必须阅读一些教程才能了解所有这些部分如何组合在一起。但是,要点是不要对线程进行编码,而是使用SwingWorker

【讨论】:

  • 我不确定我是否遵循,我的程序不喜欢 @Override 方法或 PropertyChangeListenerVoid, Void 参数的实现
  • 哎呀..你使用的是什么 JDK?所有这些都是 J2 SE 5 + 功能:)
  • 我使用的是最新版本,但我最近使用的是新用户帐户,所以我不太确定
【解决方案4】:
                    progressBar.setIndeterminate(true);
                    progressBar.setValue(0);                        
dbConnect(); //connects to DB
                    progressBar.setIndeterminate(true);
                    progressBar.setValue(10);
                    clearSchedules(); // deletes data in tables
                    progressBar.setIndeterminate(true);
                    progressBar.setValue(50);
                    readFile(); // reads first file and calls the other functions
                    progressBar.setIndeterminate(true);
                    progressBar.setValue(75);
                    dbClose();// closes the DB
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(100);

您需要告诉进度条已经取得了多少进展,因为它不知道完成的百分比。更好的是,编写一个更新和重新绘制进度条的方法,而不是在这里重复方法调用。

updateProgressBar(int progress, boolean isDeterminate, String msg){};

您还需要确保您的特定按钮正在触发执行的操作。

class IvjEventHandler implements java.awt.event.ActionListener {
        public void actionPerformed(java.awt.event.ActionEvent e) {
            if (e.getSource() == JMyPanel.this.getJButtonUpdate()) 
                connEtoC1(e);
    };
};

connEtoC1(e);应该执行一个控制器类或 SwingWorker 而不是从 GUI 触发

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 2018-07-27
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    相关资源
    最近更新 更多