简体   繁体   English

使用 Swing 工作线程更新 Swing 组件

[英]Update Swing Component using Swing Worker Thread

Currently i'm trying to build Swing application using SwingWorker to continuously update a panel.目前我正在尝试使用 SwingWorker 构建 Swing 应用程序以不断更新面板。

What i'm trying to accomplish here is load data from database and for each data will be published as an icon in the panel.我在这里要完成的是从数据库加载数据,并且每个数据都将作为面板中的图标发布。 the color of the icon is based on the value of severity field.图标的颜色基于严重性字段的值。 For example:例如:

Example Data In this picture, i have 12 data for object_id A001.示例数据在这张图片中,我有 object_id A001 的 12 个数据。 the function in the doInBackground() method will loop for 12 times and call publish() function to display the icon in the panel. doInBackground() 方法中的 function 将循环 12 次并调用 publish() function 以在面板中显示图标。 the color of the icon based on the highest value of the severity field for each object_id.基于每个 object_id 的严重性字段的最大值的图标颜色。

in the doInBackground() method, i used two method with different result:在 doInBackground() 方法中,我使用了两种结果不同的方法:

  1. Without Thread.sleep() function Console Result UI Result没有 Thread.sleep() function控制台结果UI 结果

  2. With Thread.sleep() function 10 milliseconds Console Result UI Result使用 Thread.sleep() function 10 毫秒控制台结果UI 结果

  3. With Thread.sleep() function 20 milliseconds Console Result UI Result使用 Thread.sleep() function 20 毫秒控制台结果UI 结果

Program that not use the Thread.sleep() function will print out only the last icon in the console as if the publish() function execute only once.不使用 Thread.sleep() function 的程序将只打印控制台中的最后一个图标,就好像 publish() function 只执行一次一样。

Program that use the Thread.sleep() function will print out all the icon in the console but it depends on the value that we use in the Thread.sleep() function.使用 Thread.sleep() function 的程序将打印出控制台中的所有图标,但这取决于我们在 Thread.sleep() function 中使用的值。 The lower the value, some of the icon might not be printed in the console.该值越低,某些图标可能不会在控制台中打印。

All the icon from the database is completely displayed in the UI panel but the color is inconsistent based on the used of Thread.sleep() function and the time used for the delay.数据库中的所有图标都完全显示在 UI 面板中,但颜色因 Thread.sleep() function 的使用和延迟使用的时间而不一致。

Personally, I don't want to use Thread.sleep() function due to the delay that might be higher when the data is bigger.就个人而言,我不想使用 Thread.sleep() function 因为当数据更大时延迟可能会更高。

the problem that I encountered may be due to the wrong logic in my program because this is the first time I use the SwingWorker.我遇到的问题可能是由于我的程序中的逻辑错误,因为这是我第一次使用 SwingWorker。

I also put my whole code regarding this issue if anyone want to try it hehehe.如果有人想尝试一下,我也会把我的整个代码放在这个问题上,呵呵。 https://drive.google.com/file/d/1Fs1r72HWEzOMwVY2FF9ujtl3eUd-4oIS/view?usp=sharing https://drive.google.com/file/d/1Fs1r72HWEzOMwVY2FF9ujtl3eUd-4oIS/view?usp=sharing

the processing data is done in the doInBackground() method then pass the value to process() method to update the panel.处理数据在 doInBackground() 方法中完成,然后将值传递给 process() 方法以更新面板。

Here is code of the SwingWorker thread:这是 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;
    }
}

thanks in advance.提前致谢。

When the "publish" method if invoked very frequently the values will probably be accumulated before the "process" is invoked on the EDT.当“发布”方法被非常频繁地调用时,这些值可能会在 EDT 上调用“进程”之前累积。

That is why the "process" method receives a List of object to publish.这就是为什么“处理”方法会收到要发布的 object 列表的原因。 It is the responsibility of your code to iterate through the List and update your GUI using all the data in the List.您的代码有责任遍历列表并使用列表中的所有数据更新您的 GUI。

So given that your "doInBackground" logic uses a for loop, I would suggest multiple values are accumulated and your "process" method is only process one of many.因此,鉴于您的“doInBackground”逻辑使用 for 循环,我建议累积多个值,并且您的“处理”方法只是处理其中之一。

When you use a Thread.sleep(...) you limit the number of objects that will potentially be consolidated into a single "process" event.当您使用 Thread.sleep(...) 时,您会限制可能合并为单个“进程”事件的对象数量。

So the solution is to make sure your "process" method iterates through all the objects in the List.因此解决方案是确保您的“过程”方法遍历列表中的所有对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM