簡體   English   中英

Swing,Passive View和長時間運行的任務

[英]Swing, Passive View and Long running tasks

我正在嘗試實現基於被動 視圖的gui系統。 基本上我想保持我的視圖實現(實際包含swing代碼的部分)最小化,並在我的Presenter類中完成大部分工作。 演示者應該不依賴於搖擺,也應該“運行節目”,即告訴視圖要做什么而不是反過來。

在處理長時間運行的任務時,我遇到了問題,而且一般情況下線程分離。 我希望GUI更新在EDT上運行,並且演示者邏輯在不同的線程上運行。 如果我希望演示者更新GUI的某些部分,這很容易,我寫的是這樣的:

public interface View {
    void setText(String text);
}

public class Presenter {
    View view;
    ...
    public void setTextInVIew() {
        view.setText("abc");
    }
}

public class MyFrame implements View {
    JTextField textField;
    ...
    public void setText(final String text) {
        SwingUtilities.InvokeLater(new Runnable() {
            public void run() {
                textField.setText(text);
            }
        });
    }
}

但是,當GUI要通知演示者某些操作已經發生時,我想在不同的線程中切換出EDT對它做出反應:

public class Presenter {
    ...
    public void buttonPressed() {
         // shouldn't run on EDT
    }
}

public class MyFrame implements View {
    JButton button;
    public MyFrame() {
        ...
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                presenter.ButtonPressed();
            }
        });
    }
}

因為actionPerformed代碼是從EDT運行的,所以presenter.buttonPressed也是如此。 我知道swing有SwingWorker的概念 - 在不同的線程中運行任務,但是看起來我必須將swing代碼插入到我的演示者中,並且視圖正在運行show。 任何想法如何解決這個問題?

您可以執行以下操作,這將保持您的GUI代碼到位,並簡單地執行工作以退出EDT:

 button.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
           SwingWorker sw = new SwingWorker() {
             public Object doInBackground(){
                 presenter.ButtonPressed();             
                 return null;
            }
          }; 
          sw.execute();
        }
    });

您可能對Task API感興趣以避免所有樣板。 否則,akf的解決方案看起來很好(雖然不需要為SwingWorker創建變量,但您可以新建並執行匿名變量)。

其他人概述的SwingWorker解決方案的另一種方法是使用具有線程親和力的事件總線。 我實際上認為這可能是你想要的解耦類型的最佳選擇。

退房: EventBus

還有其他總線架構的實現,但EventBus很受歡迎。

- 更新 -

所以EventBus將提供一種從非EDT到EDT的非常簡潔的代理方式(比大量的對SwingUtilities.invokeLater()的顯式調用要好很多 - 但基本上做同樣的事情。雖然EventBus能夠捆綁許多通知並讓它們在單個EDT可運行中命中,因此性能會更好)。

但這並沒有解決從EDT代理事件並讓它們在工作線程上運行的需要。 EventBus中有一個ThreadSafeEventService類可以用作這種野獸的基礎 - 它可以與ExecutorService結合,例如,為某些監聽器處理某些事件注冊。

我想這對我來說關鍵在於無論你想出什么解決方案,都應該嘗試將旋轉封裝在EDT上。

順便說一句 - 你在這里問的問題與微軟的公寓線程模型非常相似。

好的 - 我還有另一種選擇: 旋轉

最終,所有這些解決方案都是線程之間的代理調用。 我認為我們的目標是找到一個不需要大量樣板代碼的解決方案。 例如,您可以連接所有偵聽器,以便檢查它們是否在適當的工作線程上,然后代理到ExecutorService(如果不是)。 但那是一個很大的麻煩。 更好的方法是在業務和視圖對象之間的層中進行代理 - 綁定/偵聽器/您想要將其稱為層的任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM