我正在编写一个简单的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
这非常适用于较小的队列,但对于大型的队列,它需要一段时间来填充这个表,并在此期间,Swing应用程序被冻结,所以我调查的方式来填充JTable的背景,同时保持不只是应用程序,但JTable中本身可以使用和滚动.
我对线程并不是很熟悉,我尝试了一些东西,例如在SwingUtilities.invokeLater中包装一些部分并实现doInBackground(),但似乎没有任何工作.有人可以指出我正确的方向如何继续这个?
编辑
根据以下回复,以下是解决方案:
public class GetMessagesWorker extends SwingWorker{ //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 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(); } } } });
Aaron Digull.. 5
在Swing中进行线程化时,您需要了解必须在后台线程中完成工作,但任何UI更新都必须在Swing线程中完成.
这意味着您应该创建一个线程来获取消息.如果您有一个(或更多),则使用SwingUtilities
与Swing线程同步并更新表.
在上面的代码段,这意味着你需要使用SwingUtilities
每次您调用的方法时间modelMessages
,txtMessage
等等.
由于这非常昂贵,你通常会在列表中收集10个新行,然后使用一次调用将它们一次性添加SwingUtilities.invokeLater()
.