【问题标题】:Update Swing Component using Swing Worker Thread使用 Swing 工作线程更新 Swing 组件
【发布时间】:2021-01-05 06:45:53
【问题描述】:

目前我正在尝试使用 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, 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, 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);
                        terminalList.put(terminalId, (LinkedHashMap<String, 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], count [%s]", terminal, ++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], count [%s]", terminal, terminalCount++));
//          if (!(terminal.equals(lastTerminal))) {
//              lastTerminal = terminal;
//              System.out.println(String.format("Terminal [%s], count [%s]", terminal, 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]", terminal, tempData.getObjectDetail(), sev));
//                              }
                            }
//                          System.out.println(String.format("Terminal [%s], object detail [%s], severity [%s]", terminal, tempData.getObjectDetail(), 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, 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;
    }
}

提前致谢。

【问题讨论】:

  • 你项目的目标是什么?我查看了您的 UI 结果图像,但我不知道哪个图像是“正确的”,或者为什么任何图像都不正确。请用答案编辑问题。我无法访问您的“完整代码”。请在问题中发布minimal reproducible example
  • 很抱歉给您带来不便。我已经更新了这个问题。问题中的链接不能下载吗?我已经设置了链接,所以它可以被公众下载。

标签: java multithreading swing swingworker


【解决方案1】:

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

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

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

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

因此解决方案是确保您的“进程”方法遍历列表中的所有对象。

【讨论】:

  • 哦,我明白了。所以在 doInBackground 处理完所有数据之后执行 publish(),在我的 process() 方法中,只处理最后一个 publish()。感谢您的解释,我会尝试修复我的程序。
  • 所以在 doInBackground 处理完所有数据之后执行 publish() - 不,我不是这么说的。我说可以合并发布,以便您一次获得 1 或 2 或 3 个项目。所以底线是你不能保证一次只发布一个项目,所以你需要遍历列表。但是,通过添加 Thread.sleep() 可以减少合并项目的机会,因此您最终一次只能处理一个项目。
猜你喜欢
  • 2016-06-02
  • 1970-01-01
  • 2011-01-15
  • 2011-04-04
  • 1970-01-01
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多