使用 Swing Worker Thread

问题描述

目前我正在尝试使用 SwingWorker 构建 Swing 应用程序以持续更新面板。

在这里想要完成的是从数据库加载数据,并且每个数据都将作为面板中的图标发布。图标的颜色基于严重性字段的值。例如:

Example Data 在这图片中,我有 object_id A001 的 12 个数据。 doInBackground() 方法中的函数将循环 12 次并调用 publish() 函数在面板中显示图标。图标的颜色基于每个 object_id 的严重性字段的最大值。

在 doInBackground() 方法中,我使用了两种不同结果的方法

  1. 没有 Thread.sleep() 函数 Console Result UI Result

  2. 用Thread.sleep()函数10毫秒 Console Result UI Result

  3. 用Thread.sleep()函数20毫秒 Console Result UI Result

不使用 Thread.sleep() 函数的程序将只打印控制台中的最后一个图标,就好像 publish() 函数只执行一次一样。

使用 Thread.sleep() 函数的程序将打印出控制台中的所有图标,但这取决于我们在 Thread.sleep() 函数中使用的值。值越小,部分图标可能不会打印在控制台中。

数据库中的所有图标都完全显示在UI面板中,但根据Thread.sleep()函数的使用和延迟所用的时间,颜色不一致。

就个人而言,我不想使用 Thread.sleep() 函数,因为数据较大时延迟可能会更高。

我遇到的问题可能是我的程序逻辑错误,因为这是我第一次使用SwingWorker。

如果有人想尝试的话,我也把我的全部代码在这个问题上,呵呵。 https://drive.google.com/file/d/1Fs1r72HWEzOMwVY2FF9ujtl3eUd-4oIS/view?usp=sharing

处理数据在 doInBackground() 方法中完成,然后将值传递给 process() 方法以更新面板。

这是 SwingWorker 线程的代码

package com.akbar.thread;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TreeMap;

import javax.persistence.TypedQuery;
import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import com.akbar.datastructure.TerminalData;
import com.akbar.sources.RoundImageButton;

public class MonitorThread extends SwingWorker<Void,LinkedHashMap<String,String>> {
    private static final String GREEN = "/com/akbar/resources/green48.png";
    private static final String YELLOW = "/com/akbar/resources/yellow48.png";
    private static final String RED = "/com/akbar/resources/red48.png";
    private static final String BLACK = "/com/akbar/resources/black48.png";
    private static final int SEVERITY_LEVEL = 0;
    
    private boolean print = false;
    
    private int newCount = 0;
    private int updCount = 0;
    private int terminalSev;
    private int terminalCount = 0;
    
    private String lastTerminal;
    private String terminalId;
    private String termDetail;
    private String terminalStatus;
    
    private JPanel terminalPanel;
    private JScrollPane terminalScroll;
    
    private TerminalData terminalData;
    
    private TreeMap<String,JButton> updatedTerminal;
    
    private LinkedHashMap<String,TerminalData>> terminalList;
    private LinkedHashMap<String,TerminalData> terminalDetail;
    private LinkedHashMap<String,String> zCommand;
    
    private SessionFactory factory = generateSessionFactory();
    private Session session;
    private Transaction tx;
    private TypedQuery<TerminalData> query;
    
    public MonitorThread(JPanel terminalPanel,JScrollPane terminalScroll) {
        this.terminalPanel = terminalPanel;
        this.terminalScroll = terminalScroll;
        
        updatedTerminal = new TreeMap<String,JButton>();
        terminalDetail = new LinkedHashMap<String,TerminalData>();
        terminalList = new LinkedHashMap<String,TerminalData>>();
        zCommand = new LinkedHashMap<String,String>();
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Void doInBackground() throws Exception {
        try {
            session = factory.openSession();
            tx = (Transaction) session.beginTransaction();
            query = session.createquery("FROM TerminalData",TerminalData.class);
            List<TerminalData> result = query.getResultList();
            
            if (result.size() > 0) {
                for (int i = 0; i < result.size(); i++) {
                    terminalData = (TerminalData)result.get(i);
                    terminalSev = 0;
                    termDetail = terminalData.getobjectDetail();
                    terminalId = terminalData.getobjectId();
                    if (terminalList.get(terminalId) != null) {
                        terminalDetail.put(termDetail,terminalData);
                        terminalList.put(terminalId,(LinkedHashMap<String,TerminalData>)terminalDetail.clone());
                        zCommand.put("UPD",terminalId);
                        publish(zCommand);
//                      if (!(terminalId).equals(lastTerminal)) {
//                          lastTerminal = terminalId;
//                          updCount++;
//                      }
                    } else {
//                      if("125006".equals(terminalId)) {
//                          System.out.println("test");
//                      }
                        terminalDetail = new LinkedHashMap<String,TerminalData>();
                        terminalDetail.put(termDetail,TerminalData>)terminalDetail.clone());
                        zCommand.put("NEW",terminalId);
                        publish(zCommand);
//                      newCount++;
                    }
                    Thread.sleep(20);
                }
//              System.out.println(String.format("New count: [%s],Update count: [%s]",newCount,updCount));
            }
        } catch (Exception e) {
            e.printstacktrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return null;
    }
    
    @Override
    protected void process(List<LinkedHashMap<String,String>> chunks) {
        LinkedHashMap<String,String> test = chunks.get(chunks.size() - 1);
        List<String> commandKey = new ArrayList<String>(test.keySet());
        LinkedHashMap<String,TerminalData> tempDetail;
        List<String> terminalKey;
        List<String> detailKeys;

        TerminalData tempData = new TerminalData();
        
        int sev = 0;
        
        String color;
        String command = commandKey.get(0);
        String terminal = test.get(command);
        zCommand.remove(command);

//      if (!(terminal.equals(lastTerminal))) {
//          lastTerminal = terminal;
//          System.out.println(String.format("Terminal [%s],count [%s]",terminal,++terminalCount));
//      }
        
        switch (command) {
        case "NEW":
            System.out.println(String.format("Newly Terminal [%s],++terminalCount));
            lastTerminal = terminal;
            updatedTerminal = new TreeMap<String,JButton>();
            terminalKey = new ArrayList<String>(terminalList.keySet());
            tempDetail = new LinkedHashMap<String,TerminalData>();
            for (int i = 0; i < terminalKey.size(); i++) {
                tempDetail = terminalList.get(terminalKey.get(i));
                detailKeys = new ArrayList<String>(tempDetail.keySet());
                sev = 0;
                for (int j = 0; j < detailKeys.size(); j++) {
                    tempData = tempDetail.get(detailKeys.get(j));
                    int tempSev = Integer.parseInt(tempData.getSeverity());
                    if (tempSev > sev) {
                        sev = tempSev;
                    }
                }
                color = terminalKey.get(i).equals(terminal) ? BLACK : getIconColor(sev);
                updatedTerminal.put(tempData.getobjectId(),new RoundImageButton(tempData.getobjectId(),color,tempData.getobjectId(),new Dimension(130,48)));
            }
            updatePanel(updatedTerminal);
            break;
            
        case "UPD":
//          System.out.println(String.format("Updated Terminal [%s],terminalCount++));
//          if (!(terminal.equals(lastTerminal))) {
//              lastTerminal = terminal;
//              System.out.println(String.format("Terminal [%s],terminalCount++));
//          }
            sev = 0;
            tempDetail = new LinkedHashMap<String,TerminalData>();
            Component[] comps = terminalPanel.getComponents();
            if (comps.length > 0) {
                for (Component comp : comps) {
                    if (comp instanceof JButton) {
                        if (terminal.equals(comp.getName())) {
                            tempDetail = new LinkedHashMap<String,TerminalData>();
                            tempDetail = terminalList.get(terminal);
                            detailKeys = new ArrayList<String>(tempDetail.keySet());
                            for (int j = 0; j < detailKeys.size(); j++) {
                                tempData = tempDetail.get(detailKeys.get(j));
                                int tempSev = Integer.parseInt(tempData.getSeverity());
                                if (tempSev > sev) {
                                    sev = tempSev;
                                }
//                              if ("125006".equals(terminal)) {
//                                  System.out.println(String.format("Terminal [%s],object detail [%s],severity [%s]",tempData.getobjectDetail(),sev));
//                              }
                            }
//                          System.out.println(String.format("Terminal [%s],sev));
                            color = getIconColor(sev);
                            ((AbstractButton) comp).setIcon(new ImageIcon(getClass().getResource(color)));
                            break;
                        }
                    }
                }
            }
            break;
            
        case "RMV":
            break;
        
        default:
            break;
        }
    }
    
    @Override
    protected void done() {
        super.done();
    }
    
    private void updateComponent(String terminal) {
        LinkedHashMap<String,TerminalData> temp = terminalList.get(terminal);
        List<String> key = new ArrayList<String>(temp.keySet());
        TerminalData data;
        int highestSeverity = 0;
        int severity = 0;
        for (int i = 0; i < key.size(); i++) {
            data = temp.get(key.get(i));
            severity = Integer.parseInt(data.getSeverity());
            if (severity > highestSeverity) {
                highestSeverity = severity;
            }
        }
        
        if (highestSeverity > SEVERITY_LEVEL) {
            
        }
    }
    
    private String getIconColor(int severity) {
        if (severity >= 0 && severity <= 10) {
            return GREEN;
        } else if (severity > 10 && severity <= 30) {
            return YELLOW;
        } else if (severity > 30 && severity <= 40) {
            return RED;
        }
        return BLACK;
    }
    
    private TreeMap<String,JButton> retrievedisplayedTerminal() {
        TreeMap<String,JButton> temp = new TreeMap<String,JButton>();
        Component[] comps = terminalPanel.getComponents();
        if (comps.length > 0) {
            for (Component comp : comps) {
                if (comp instanceof JButton) {
                    temp.put(comp.getName(),(JButton) comp);
                }
            }
        }
        return temp;
    }
    
    private boolean checkCurrentTerminal(String terminal) {
        Component[] comps = terminalPanel.getComponents();
        if (comps.length > 0) {
            for (Component comp : comps) {
                if (comp instanceof JButton) {
                    if ((comp.getName()).equals(terminal)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    private void updatePanel(TreeMap<String,JButton> terminals) {
        final int MAX_COLUMN = 14;
        JButton button;
        Component[] components = terminalPanel.getComponents();
        if (components.length > 0) {
            for (Component comp : components) {
                if (comp instanceof JButton) {
                    terminalPanel.remove(comp);
                    terminalPanel.validate();
                    terminalPanel.repaint();
                    terminalScroll.validate();
                    terminalScroll.repaint();
                }
            }
        }
        
        GridBagConstraints gc = new GridBagConstraints();
        gc.insets = new Insets(0,5,0);
        
        int currentLine = 1;
        int size = terminals.size();
        int totalLine = size / MAX_COLUMN;
        if (totalLine == 0) {
            totalLine += 1;
        } else {
            int temp = size % MAX_COLUMN;
            if (temp > 0) {
                totalLine += 1;
            }
        }
        
        int xCount = -1;
        int yCount = 0;
        
        List<String> keyList = new ArrayList<String>(terminals.keySet());
        for (int i = 0; i < size; i++) {
            if (terminals.get(keyList.get(i)) instanceof JButton) {
                button = terminals.get(keyList.get(i));
                if (xCount == MAX_COLUMN - 1) {
                    currentLine++;
                    yCount++;
                    xCount = 0;
                    gc.gridx = xCount;
                    gc.gridy = yCount;
                    gc.weightx = 0.0;
                    gc.weighty = (currentLine == totalLine ? 50.0 : 0.1);
                    gc.anchor = GridBagConstraints.norTHWEST;
                    gc.fill = GridBagConstraints.HORIZONTAL;
                } else {
                    xCount++;
                    gc.gridx = xCount;
                    gc.gridy = yCount;
                    gc.weightx = 0.0;
                    gc.weighty = 0.1;
                    gc.anchor = GridBagConstraints.norTH;
                    gc.fill = GridBagConstraints.NONE;
                }
                terminalPanel.add(button,gc);
            }
        }
        terminalPanel.validate();
        terminalPanel.repaint();
        terminalScroll.validate();
        terminalScroll.repaint();
    }
    
    private SessionFactory generateSessionFactory() {
        try {
            return new Configuration().configure().buildSessionFactory();
        } catch (Exception e) {
            e.printstacktrace();
        }
        return null;
    }
}

提前致谢。

解决方法

如果频繁调用“发布”方法,则可能会在 EDT 上调用“进程”之前累积值。

这就是“process”方法接收要发布的对象列表的原因。您的代码有责任遍历 List 并使用 List 中的所有数据更新 GUI。

因此,考虑到您的“doInBackground”逻辑使用 for 循环,我建议累积多个值,而您的“处理”方法只是处理众多值之一。

当您使用 Thread.sleep(...) 时,您会限制可能合并为单个“进程”事件的对象数量。

所以解决方案是确保您的“处理”方法遍历列表中的所有对象。