如何使用SwingWorker?

4

朋友们,我正在开发一个Java应用程序,用于性能监控。其中一个类中获取数值并在另一个类中绘制图形。我希望使用SwingWorker来交替执行这两个类。

        ResultSet rs;
        Connection conn = null;

        conn = (Connection)getMySqlConnection();

        Statement st = conn.createStatement();
        rs = st.executeQuery("SHOW GLOBAL STATUS");
        while(rs.next())
        {
            Map_MySql.put(rs.getString(1), rs.getString(2));
        }
        conn.close();

上面的类用于收集服务器状态并将其存储在哈希映射中。这个类被称为"MySQLClass"。

        System.out.println("Graph Occur");
        XYDataset Dataset;
        TimeSeries Series = new TimeSeries("Random Data");
        Second sec = new Second();
        ChartPanel CPanel;
        if(Operation_Combo.getSelectedItem().toString() == "MySQL")
        {
         if(MySQLClass.Map_MySql.get(""+MainWindow.SelectedNode+"") == null)
         {
             Value = 0;
         }
         else
         {
             Value = Integer.parseInt(MySQLClass.Map_MySql.get(""+MainWindow.SelectedNode+""));
         }
         System.out.println(Value);
        }
        if(Operation_Combo.getSelectedItem().toString() == "SQL Server")
        {
         if(SqlServerClass.Map_SQLServer.get(""+MainWindow.SelectedNode+"") == null)
         {
             Value = 0;
         }
         else
         {
             Value = Integer.parseInt(SqlServerClass.Map_SQLServer.get(""+MainWindow.SelectedNode+""));
         }
         System.out.println(Value);
        }
        String CounterName = MainWindow.SelectedNode.toString();
        Series.add(sec, Value);
        Dataset = new TimeSeriesCollection(Series);
        Chart = ChartFactory.createTimeSeriesChart(CounterName, "Time", "Range", Dataset, true, false, false);
        XYPlot Plot = (XYPlot)Chart.getPlot();
        Plot.setBackgroundPaint(Color.LIGHT_GRAY);
        Plot.setDomainGridlinePaint(Color.WHITE);
        Plot.setRangeGridlinePaint(Color.RED);
        CPanel = new ChartPanel(Chart);
        Panel1.revalidate();
        Panel1.add(CPanel);
        System.out.println("Chart Added");
        Panel1.validate();
        Panel1.repaint();
        Thread.sleep((int)MainWindow.Interval_Combo.getSelectedItem() * 1000);
        System.out.println("Sleep="+((int)MainWindow.Interval_Combo.getSelectedItem() * 1000));
        System.gc();

以下是绘制名为“Graph”的类的代码。 如果您知道如何使用Swing Worker来执行此操作并在每次迭代中绘制图形,请帮助我。
请注意,本文不会解释任何技术内容。

2
请查看使用Swing进行并发操作。其中有一个关于使用SwingWorker的部分。 - Paul Samsotha
无关内容:请学习Java命名规范并坚持遵循。 - kleopatra
可能是[JFreeChart在线程的每次迭代中都没有显示图形?]的重复问题(http://stackoverflow.com/questions/20884694/jfreechart-does-not-show-the-graph-at-every-iteration-on-thread) - trashgod
2个回答

7

SwingWorker很容易使用,比它看起来要简单得多。

基本上,您需要做出一些关于您想要实现什么的基本决策。

  • 您是希望在进程运行时定期返回更新还是
  • 您是希望返回进程的结果……或者两者都?
  • 您是希望提供进度更新吗?

根据您想要做什么,将改变声明SwingWorker的方式。

例如......

public class HardWorker extends SwingWorker<ReturnValueType, PeriodicalType> {

其中ReturnValueType是工作线程最终生成的结果,而PeriodicalType是可以发送回UI线程的对象类型,如果您想执行定期更新,则可以指定这些值。

如果您不关心这些值中的任何一个,可以将其设置为VoidObject

执行时,SwingWorker将调用doInBackground方法,在其自己的线程中调用此方法,允许在事件分派线程之外执行长时间运行的任务。

如果您想在doInBackground方法完成之前向UI发送值,则可以调用publish(instanceOfPeriodicalType)。传递给此方法的值最终将传递到process方法中。

由于可能向publish方法发送多个项目,因此process方法提供了一个List<PeriodicalType>参数。调用此方法时,将在EDT上下文中执行此方法,允许您更新UI。

一旦doInBackground完成,它将返回ReturnValueType类型的返回值(如果您不关心,则返回null)。

如果您对此结果感兴趣,应该使用SwingWorker#get,但是您应该注意,此方法将阻塞直到doInBackground返回,这意味着在EDT中不应调用此方法,直到您知道doInBackground方法已返回。您可以使用其isDoneisCancelled方法检查工作线程的状态,或者...

您可以使用PropertyChangeListener并监视state属性或覆盖SwingWorkerdone方法。

如果您想在doInBackground方法中提供进度更新,则可以调用setProgress来更新工作线程的进度。这将触发一个名为progressPropertyChangeEvent,您可以通过PropertyChangeListener监视它。对此侦听器的调用将在EDT上下文中进行。

请参阅:

获取更多详细信息。

通常,为了使用SwingWorker,您需要将设计分为两组。所有可以在后台完成的工作和所有需要在EDT中完成的工作。
您可以开始构建您的工作者的基本概念。
基本示例...
这假设很多情况。基本上,它假定UI已经设置好,并且将用于选择新结果并将它们传回特定系列。
基本上,根据需要,将实例化工作者,并将序列传递给它...
GraphWorker worker = new GraphWorker(series);
worker.execute();

工作将执行查询并将结果传回到process方法。
public class GraphWorker extends SwingWorker<Void, String[]> {

    private TimeSeries series;
    private Second sec;

    public GraphWorker(TimeSeries series) {
        this.series = series;
        sec = new Second();
    }

    @Override
    protected Void doInBackground() throws Exception {
        ResultSet rs;
        Connection conn = null;
        try {

            conn = (Connection) getMySqlConnection();

            Statement st = conn.createStatement();
            rs = st.executeQuery("SHOW GLOBAL STATUS");
            while (rs.next()) {
                publish(new String[]{rs.getString(1), rs.getString(2)});
            }
        } finally {
            conn.close();
        }
        return null;
    }

    @Override
    protected void process(List<String[]> chunks) {
        for (String[] value : chunks) {

            try {
                int iValue = Integer.parseInt(value[1]);
                series.add(sec, Value);
            } catch (NumberFormatException exp) {
                exp.printStackTrace();
            }

        }            
    }

}

有人能告诉我如何交替调用这两组Swingworker代码吗?如果有任何适用于我的问题的示例格式,也非常感激。谢谢。 - A.Mohamed Bilal
@A.MohamedBilal:这里有一个完整的示例,可以在这里查看。 - trashgod
哦,谢谢。但那是用于生成图形编码的。我想知道如何使用Swing Worker使这两个类交替工作,并且我想在每次迭代中生成图形。你能否只给出那段代码?如果我得到了这个,我的项目就完成了。拜托了。@trashgod - A.Mohamed Bilal
所引用的示例在每次迭代中向图表添加一个点。 - trashgod
MySQLClass MySQL = new MySQLClass(); MySQL.execute(); 这是我的代码。我只是在doinBackground函数中编写查询,将这些详细信息存储在哈希映射表中并发布哈希映射表。在process函数中,我只是编写生成图形的代码。在那里,我得到的输出不是替代形式。输出如下:MySql Occur MySql Occur Connection Close Connection Close Graph Occur 71547 Chart Added Sleep=1000 Graph Occur 71547 Chart Added Sleep=1000 我应该怎么做才能以替代形式执行它。 - A.Mohamed Bilal
显示剩余2条评论

0
起初,我只是从MySQL.execute();中调用doInBackground()函数,使用这个。然后在doInBackground()函数中,我只是收集那些计数器的值,并使用publish();函数传递特定的值。 在这里,我只是传递标志以表示数据已成功收集。 publish(GraphLock); 调用Publish();方法后,会调用Process(List chunks)方法。在这个方法中,我只是检查条件并调用Graph类来生成图形。
    if(GraphLock==true)
        SwingUtilities.invokeLater(new Graph());

它正常工作...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接