Java:在后台更新有大量行的 JTable

2024-03-22

我正在编写一个简单的 Java Swing 实用程序,它将从 MQ JMS 服务器读取消息并将它们显示在 JTable 中。

private void getMessages() {
        try {
            if (null != Queue) {
                Queue.close();  //Close previous queue connection if there is one.
            }
            Queue = new MQQueue(QueueManager, tableQueues.getValueAt(tableQueues.getSelectedRow(), 1).toString(), MQConstants.MQOO_INPUT_SHARED | MQConstants.MQOO_BROWSE | MQConstants.MQOO_OUTPUT, queueManager, null, null);
            int count = 0;
            modelMessages.setRowCount(0);
            MQGetMessageOptions getOptions = new MQGetMessageOptions();
            getOptions.options = MQConstants.MQGMO_BROWSE_FIRST;
            ArrayList<Object[]> rows = new ArrayList<Object[]>();
            while(true) {
                if (count > 0) {
                    getOptions.options = MQConstants.MQGMO_BROWSE_NEXT;
                }
                MQMessage message = new MQMessage();
                try {
                    Queue.get(message, getOptions);
                    byte[] b = new byte[message.getMessageLength()];
                    message.readFully(b);
                    rows.add(new Object[]{count + 1, new String(b)});
                    modelMessages.addRow(new Object[]{count + 1, new String(b)});
                    message.clearMessage();
                    count++;
                }
                catch (IOException e) {
                    break;
                }
                catch (MQException e) {
                    if (e.completionCode == 2 && e.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) {
                        break;
                    }
                }
            }
            modelMessages.fireTableDataChanged();
        } catch (MQException e) {
            txtMessage.setText("MQJE001: Completion Code '" + e.completionCode + "', Reason '" + e.reasonCode + "'.");
            modelMessages.setRowCount(0);
            modelMessages.fireTableDataChanged();
        }
    }

这对于较小的队列很有效,但对于大型队列,填充该表需要一段时间,同时,Swing 应用程序被冻结,因此我正在研究在后台填充 JTable 的方法,同时不仅保留应用程序,还保留 JTable在此期间本身可用且可滚动。

我对线程不太熟悉,并且尝试了一些方法,例如将某些部分包装在 SwingUtilities.invokeLater 中并实现 doInBackground() 但似乎没有任何效果。有人可以指出我如何进行此操作的正确方向吗?

EDIT

根据以下回复,解决方案如下:

public class GetMessagesWorker extends SwingWorker<DefaultTableModel, Object[]> {

    //http://stackoverflow.com/questions/22072480/java-updating-jtable-with-lots-of-rows-in-the-background#

    private final DefaultTableModel model;

    public GetMessagesWorker(DefaultTableModel model){
        this.model = model;
    }

    @Override
    protected DefaultTableModel doInBackground() throws Exception {
        try {
            if (null != Queue) {
                Queue.close();  //Close previous queue connection if there is one.
            }
            Queue = new MQQueue(QueueManager, tableQueues.getValueAt(tableQueues.getSelectedRow(), 1).toString(), MQConstants.MQOO_INPUT_SHARED | MQConstants.MQOO_BROWSE | MQConstants.MQOO_OUTPUT, queueManager, null, null);
            int count = 0;
            modelMessages.setRowCount(0);
            MQGetMessageOptions getOptions = new MQGetMessageOptions();
            getOptions.options = MQConstants.MQGMO_BROWSE_FIRST;
            while(true) {
                if (count > 0) {
                    getOptions.options = MQConstants.MQGMO_BROWSE_NEXT;
                }
                MQMessage message = new MQMessage();
                try {
                    Queue.get(message, getOptions);
                    byte[] b = new byte[message.getMessageLength()];
                    message.readFully(b);
                    Object[] row = {count + 1, new String(b)};
                    publish(row);
                    message.clearMessage();
                    count++;
                    if (isCancelled()) {
                        modelMessages.setRowCount(0);
                        count = 0;
                        message.clearMessage();
                        return model;
                    }
                }
                catch (IOException e) {
                    break;
                }
                catch (MQException e) {
                    if (e.completionCode == 2 && e.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) {
                        break;
                    }
                }
            }
            //modelMessages.fireTableDataChanged();
        } catch (MQException e) {
            txtMessage.setText("MQJE001: Completion Code '" + e.completionCode + "', Reason '" + e.reasonCode + "'.");
            modelMessages.setRowCount(0);
            modelMessages.fireTableDataChanged();
        }
        return model;
    }

    @Override
    protected void process(List<Object[]> chunks){
        for(Object[] row : chunks){
            model.addRow(row);
        }
    }

}

这是听众:

    tableQueues = new JTable(modelQueues);
    tableQueues.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
        public void valueChanged(ListSelectionEvent e) {
            if (!e.getValueIsAdjusting()) {
                txtMessage.setText("");
                if (tableQueues.getSelectedRow() > -1) {
                    gmw.cancel(false);
                    gmw = new GetMessagesWorker(modelMessages);
                    gmw.execute();
                }
            }
        }
    });

这是由于 Swing 架构造成的。您必须了解,执行侦听器的同一个线程负责更多的事情(例如,刷新 UI)。

我会在你的情况下使用SwingWorker。这是一种特定于 Swing 的后台线程,具有特殊功能,可以在执行长任务时安全地将更新发送到您的 UI。你会在后台完成你的长期任务并打电话publish()对于它检索到的每个相关结果。每次publish()被称为,你的process()方法将被调用(在后台向主线程发送更新),您可以在那里更新您的表模型。

在这里您可以找到更多信息SwingWorker:

http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java:在后台更新有大量行的 JTable 的相关文章

  • 通过推送通知唤醒

    Suppose 有一些对象 例如 一个数组a 和依赖于对象的条件 例如 a empty 当前线程以外的某些线程可以操作该对象 a 因此条件评估值的真实性会随着时间的推移而变化 如何让当前线程在代码中的某个时刻休眠 并在条件满足时通过推送通知
  • 如何使用 runOnUiThread 而不出现“无法对非静态方法进行静态引用”编译器错误

    我有一个主课 ClientPlayer extends Activity 和一项服务 LotteryServer extends Service implements Runnable 当尝试在此服务的 run 方法中使用 RunOnUiT
  • 为什么即使我的哈希码值相同,“==”也会返回 false

    我写了一个像这样的课程 public class HashCodeImpl public int hashCode return 1 public static void main String args TODO Auto generat
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • 如何在 Java 中向时间戳添加/减去时区偏移量?

    我正在使用 JDK 8 并且玩过ZonedDateTime and Timestamp很多 但我仍然无法解决我面临的问题 假设我得到了格式化的Timestamp在格林威治标准时间 UTC 我的服务器位于某处 假设它设置为Asia Calcu
  • Android studio - 如何保存先前活动中选择的数据

    这是我的代码片段 这Textview充当按钮并具有Onclicklistner在他们 当cpu1000时Textview单击它会导致cpu g1000其代码如下所示的类 public class Game 1000 extends AppC
  • 提供节点名或服务名,或未知 Java

    最近我尝试运行我的 Java 项目 每当我运行它并将其打开到我得到的服务器地址时 Unable to determine host name java net UnknownHostException Caused by java net
  • Java 中如何将 char 转换为 int? [复制]

    这个问题在这里已经有答案了 我是Java编程新手 我有例如 char x 9 我需要得到撇号中的数字 即数字 9 本身 我尝试执行以下操作 char x 9 int y int x 但没有成功 那么我应该怎么做才能得到撇号中的数字呢 ASC
  • 如何在java中将日期格式从YYMMDD更改为YYYY-MM-DD? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我从机器可读代码中获取日期格式为 YYMMDD 如何将其更改为 YYYY MM DD 例如我收到 871223 YYMMDD 我想把它改成
  • Sun 在 EDT 之外做 GUI 工作的演示?

    我正在看SplashDemo java http download oracle com javase tutorial uiswing examples misc SplashDemoProject src misc SplashDemo
  • Java Applet 中的 Apache FOP - 未找到数据的 ImagePreloader

    我正在研究成熟商业产品中的一个问题 简而言之 我们使用 Apache POI 库的一部分来读取 Word DOC 或 DOCX 文件 并将其转换为 XSL FO 以便我们可以进行标记替换 然后 我们使用嵌入到 Java 程序中的 FOP 将
  • 从jar中获取资源

    我有包含文件的 jar myJar res endingRule txt myJar wordcalculator merger Marge class 在 Marge java 中我有代码 private static final Str
  • 如何在.NET中使用java.util.zip.Deflater解压缩放气流?

    之后我有一个转储java util zip Deflater 可以确认它是有效的 因为 Java 的Inflater打开它很好 并且需要在 NET中打开它 byte content ReadSample sampleName var inp
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • 轻松的反应

    我有一个与这里描述的类似的案例 动态更改RESTEasy服务返回类型 https stackoverflow com questions 3786781 dynamically change resteasy service return
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • 将 JavaFX FXML 对象分组在一起

    非常具有描述性和信息性的答案将从我这里获得价值 50 声望的赏金 我正在 JavaFX 中开发一个应用程序 对于视图 我使用 FXML
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何
  • 使我的 COM 程序集调用异步

    我刚刚 赢得 了在当前工作中维护用 C 编码的遗留库的特权 这个dll 公开使用 Uniface 构建的大型遗留系统的方法 除了调用 COM 对象之外别无选择 充当此遗留系统与另一个系统的 API 之间的链接 在某些情况下 使用 WinFo

随机推荐