Mat*_*att 2 java swing multithreading jtable mq
我正在编写一个简单的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();
}
}
Run Code Online (Sandbox Code Playgroud)
这非常适用于较小的队列,但对于大型的队列,它需要一段时间来填充这个表,并在此期间,Swing应用程序被冻结,所以我调查的方式来填充JTable的背景,同时保持不只是应用程序,但JTable中本身可以使用和滚动.
我对线程并不是很熟悉,我尝试了一些东西,例如在SwingUtilities.invokeLater中包装一些部分并实现doInBackground(),但似乎没有任何工作.有人可以指出我正确的方向如何继续这个?
编辑
根据以下回复,以下是解决方案:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是听众:
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();
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
在Swing中进行线程化时,您需要了解必须在后台线程中完成工作,但任何UI更新都必须在Swing线程中完成.
这意味着您应该创建一个线程来获取消息.如果您有一个(或更多),则使用SwingUtilities与Swing线程同步并更新表.
在上面的代码段,这意味着你需要使用SwingUtilities每次您调用的方法时间modelMessages,txtMessage等等.
由于这非常昂贵,你通常会在列表中收集10个新行,然后使用一次调用将它们一次性添加SwingUtilities.invokeLater().
这是由于Swing架构.您必须了解正在执行侦听器的同一线程负责更多事情(例如,刷新UI).
我会用你的情况一个SwingWorker.这是一种特定于Swing的后台线程,具有特殊功能,可以在执行其长任务时安全地向UI发送更新.你可以在后台完成你的长期任务,并调用publish()它检索的每个相关结果.每次publish()调用时,都会调用您的process()方法(向引擎盖下的主线程发送更新),您可以更新表模型.
在这里您可以找到更多信息SwingWorker:
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
| 归档时间: |
|
| 查看次数: |
893 次 |
| 最近记录: |