从服务器解析数据并定期更新GUI-java swing



所以我有这个程序,它最初应该使用objectinputstream从服务器接收数据。然后,程序应该将接收到的数据插入到ArrayList中,并用选项更新屏幕上的组合框。所有这些都很好,我只是把它放在这里作为上下文。

我遇到的问题是,一旦JFrame加载完毕,我希望GUI每10秒用来自服务器的新数据更新一次,但它不起作用。我试过使用swing.timer、ScheduledExecutiorService.scheduleAtFixedRate和TimerTask,但似乎都不起作用。程序只是冻结(特别是gui(,控制台中没有显示任何错误,也没有抛出任何异常。

在下面的代码示例中,我包含了我当前的尝试以及以前的一些尝试作为注释。

代码:

构造函数和设置函数:

public class UserMainGUI extends javax.swing.JFrame {
/**
* Creates new form UserMainGUI
*/
ArrayList<String> data;
JSONParser jsonParser;
ArrayList<String> weatherStationNames;
UserConnection connection;
UpdateDataTimerTask udtt;
Timer timer;
ActionListener taskPerformer;
public UserMainGUI() {
initComponents();
this.data = null;
jsonParser = new JSONParser();
udtt = new UpdateDataTimerTask();
}
public void setupGUI(UserConnection newConnection) //throws InterruptedException
{
connection = newConnection;
if(connection.WeatherStationConnectionCheck())
{
weatherStationOnline.setText("Select a weather station:");
System.out.println("First part working");
data = connection.getWeatherStationData();
if(data != null)
{
parseData();
updateData();
/*taskPerformer = (ActionEvent evt) -> {
data = connection.getWeatherStationData();
System.out.println("updated data: " + data);
parseData();
};
timer = new Timer(10000,taskPerformer);
timer.start(); */
//Thread.sleep(5000);
}
}
else
{
weatherStationComboBox.setVisible(false);
}
}

更新数据功能:

public void updateData()
{
taskPerformer = new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
data = connection.getWeatherStationData();
System.out.println("updated data: " + data);
SwingUtilities.invokeLater(() -> {
parseData();
});
}  
};
timer = new Timer(10000,taskPerformer);
timer.start();
/*Thread t = new Thread(new Runnable(){
public void run(){
data = connection.getWeatherStationData();
System.out.println("updated data: " + data);
SwingUtilities.invokeLater(() -> {
parseData();
});
try
{
java.lang.Thread.sleep(10000);
}
catch(Exception ex)
{
//System.err.println("Couldn't update data: " ex)
}
}
}); 
t.start(); */
/*Runnable retrieveRunnable = new Runnable()
{
@Override
public void run() {
try
{
data = connection.getWeatherStationData();
System.out.println("updated data: " + data);
parseData();
}
catch(Exception ex)
{
System.err.println("Could not update data: " + ex);
}
}   
};
ScheduledExecutorService executor = Executors.newScheduledThreadPool(20);
executor.scheduleAtFixedRate(retrieveRunnable, 0, 10, TimeUnit.SECONDS); */

}

Swing是单线程的。这意味着在事件调度线程的上下文中执行的任何长时间运行或阻塞操作都将导致UI冻结。

没有足够的信息可以确定,但我怀疑connection.getWeatherStationData()是一个阻塞操作,不应该在EDT中执行。

例如,您可以使用SwingWorker并在ScheduledExecutorService上运行它。。。

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel("---");
add(label);
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
LongRunningSufferingTask.secheduleForRun(service, new LongRunningSufferingTask.Tickable() {
private final DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
@Override
public void tick(LocalDateTime dateTime) {
label.setText(formatter.format(dateTime));
}
});
}
}
public static class LongRunningSufferingTask extends SwingWorker<Object, LocalDateTime> {
public interface Tickable {
public void tick(LocalDateTime dateTime);
}
private Tickable tickable;
private ScheduledExecutorService service;
private LongRunningSufferingTask(ScheduledExecutorService service, Tickable tickable) {
this.service = service;
this.tickable = tickable;
}
public static void secheduleForRun(ScheduledExecutorService service, Tickable tickable) {
service.schedule(new LongRunningSufferingTask(service, tickable), 10, TimeUnit.SECONDS);
}
@Override
protected void process(List<LocalDateTime> chunks) {
if (tickable == null) {
return;
}
LocalDateTime last = chunks.get(chunks.size() - 1); 
tickable.tick(last);
}
@Override
protected Object doInBackground() throws Exception {
publish(LocalDateTime.now());
// Sleed for a random amount of time to simulate some
// long runing work...
Thread.sleep((int) (Math.random() * 5000));
LongRunningSufferingTask.secheduleForRun(service, tickable);
return "";
}
}
}

此示例假设只有在当前任务完成后才会安排新任务。这防止了两个任务同时执行的可能性,因为在计划新任务之前,最后一个任务必须完成。这意味着每个任务都将在最后一个任务之后运行t + n,其中t是等待的时间量,n是完成最后任务所花费的时间量。

最新更新