运行GUI时有关线程的问题[重复]

问题描述 投票:0回答:2

这个问题在这里已有答案:

我正在为Uni编写一个程序,该程序使用RFID跟踪器跟踪RFID标签通过时的移动情况。这是模仿钱包穿过房间时的动作。

我在GUI中添加了一个按钮,用于初始化跟踪器并在标签通过时更新我的​​数据库。他们在线保持60秒,一切正常。但是,按下此按钮后,我的GUI将冻结,直到进程停止。这可以防止我的GUI更新表。

我意识到我需要使用线程,我发现SwingWorker看起来不错但是经过一段时间试图理解它我似乎无法弄明白。

我想知道是否有比我更多经验的人能告诉我SwingWorker是否能满足我的需要并给我一些如何使用它的建议。

以下是我的代码的一些片段:

跟踪JButton:

JButton trackingButton = new JButton("Start Tracking");
trackingButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        try {
            RFIDHandler.openRFID(); //runs the RFID readers
        } catch (PhidgetException | SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
});

我的openRFID方法的开始:

public static void openRFID() throws PhidgetException, SQLException {   

    RFID phid1 = new RFID();
    RFID phid2 = new RFID();
    WalletDAO dao = new WalletDAO();

    // Open and start detecting rfid cards
    phid1.open(5000);  // wait 5 seconds for device to respond
    phid2.open(5000);  // wait 5 seconds for device to respond


    phid1.setAntennaEnabled(true);
    phid2.setAntennaEnabled(true);

    // Make the RFID Phidget able to detect loss or gain of an rfid card
    phid1.addTagListener(new RFIDTagListener() {
        public void onTag(RFIDTagEvent e) {
            try {
                Wallet w = dao.getWallet(e.getTag());                   
                String location = w.getLocation();
                System.out.println(location);

                if(Objects.equals(location, "Room A")) {
                    System.out.println(w.getName() + "'s Wallet read");
                    w.setLocation("Room B");
                    try {
                        dao.updateLocation(w);
                        WalletLocatorInterface.refreshTable(); // refreshes table on GUI
                        System.out.println("Currently in room B");
                    } catch (SQLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
                // ... else statement + another TagListener 

    System.out.println("Gathering data for 60 seconds\n\n");
    try {
        Thread.sleep(60000);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    phid1.close();
    phid2.close();
    System.out.println("\nClosed RFIDs");
}

如果你需要我清除任何事情,请告诉我,谢谢。

java swingworker
2个回答
1
投票

你的问题是Thread.sleep。你可以用ScheduledExecutorService完成你在这里做的事。只需将您的代码修改为:

...
    System.out.println("Gathering data for 60 seconds\n\n");
    try {
        Thread.sleep(60000);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    Executors.newScheduledThreadPool(1).schedule(() -> {
        phid1.close();
        phid2.close();
        System.out.println("\nClosed RFIDs");
    }, 60, TimeUnit.SECONDS);
}

(顺便说一句,我使用了lambda表达式,可以解释为here。)

关于SwingWorker,我没有太多经验。但是,使用SwingWorker,您可以在后台执行操作,而不会在更新时使GUI断断续续。但是,如果你没有真正更新GUI,就像@MadProgrammer所说,那么你就不会真正受益于使用SwingWorker


0
投票

当你尝试设计这样的东西时,你需要以更加独立的方式重新思考你的方法。

我可能做的第一件事是定义一个可以传递信息的委托,这使得处理起来更容易,因为你不需要搞乱SwingWorkers PropertyChangeListener它可以让你解耦代码......

public interface RFIDWorkerDelegate {
    public void locationsUpdated(List<String> locations);
}

接下来,您需要执行可能阻止UI的操作并将它们放入SwingWorkers doInBackfground

然后,您需要决定使用所需更改来更新UI的最佳时间。然后,您调用publish来“发布”结果。这些将传递给process方法,该方法在Event Dispatching Thread的上下文中调用,例如......

public class RFIDWorker extends SwingWorker<Void, String> {

    private RFIDWorkerDelegate delegate;

    public RFIDWorker(RFIDWorkerDelegate delegate) {
        this.delegate = delegate;
    }

    @Override
    protected void process(List<String> chunks) {
        delegate.locationsUpdated(chunks);
    }

    @Override
    protected Void doInBackground() throws Exception {
        RFID phid1 = new RFID();
        RFID phid2 = new RFID();
        WalletDAO dao = new WalletDAO();

        // Open and start detecting rfid cards
        phid1.open(5000);  // wait 5 seconds for device to respond
        phid2.open(5000);  // wait 5 seconds for device to respond

        phid1.setAntennaEnabled(true);
        phid2.setAntennaEnabled(true);

        // Make the RFID Phidget able to detect loss or gain of an rfid card
        phid1.addTagListener(new RFIDTagListener() {
            public void onTag(RFIDTagEvent e) {
                Wallet w = dao.getWallet(e.getTag());
                String location = w.getLocation();
                System.out.println(location);

                publish(location);

                if (Objects.equals(location, "Room A")) {
                    System.out.println(w.getName() + "'s Wallet read");
                    w.setLocation("Room B");
                    try {
                        dao.updateLocation(w);
                        WalletLocatorInterface.refreshTable(); // refreshes table on GUI
                        System.out.println("Currently in room B");
                    } catch (SQLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });

        System.out.println("Gathering data for 60 seconds\n\n");
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        phid1.close();
        phid2.close();
        System.out.println("\nClosed RFIDs");
        return null;
    }
}

然后你可以称之为......

new RFIDWorker(new RFIDWorkerDelegate() {
    @Override
    public void locationsUpdated(List<String> locations) {
        // Update the UI as required
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.