2013-10-07 37 views
1

我需要,當用戶點擊一個按鈕,該按鈕觸發回調,並傳遞給她一些參數,每次,參數將有所不同。Twisted矩陣回調呼叫一次又一次

我看過的文檔,但似乎對於循環的部分缺失:

Looping 

A common form of dependency is needing to perform the asynchronous operation all over again. The canonical example of this an HTTP redirect: when the callback for a deferred from a page request is returned, it could be the result, or it could be an empty body with the Location HTTP header set, in which case you simply perform the operation over again. 

[ here is the HTTP redirect example. It also should have pictures. ] 

的,如果工作時,也嘗試,但回調只運行一次

if happen this: 
    try: 
    print "I'm here!" 
    myobjectx.addCallback(test,x,y,z) 
    myobjectx.callback() 

    except: 
    ... 

剛得到如何工作的想法:

1) create the myobject that do nothing for now 
2) when an event is fired prepare the callback for the myobject e execute it 
3) how can I redo the callback next time the event happen again? 

我正在尋找pymodbus庫的例子async cl ient:

https://pymodbus.readthedocs.org/en/latest/examples/asynchronous-client.html

我有2個文件:

MAINPROCESS 
MODBUSLIB 

從MAINPROCESS我打電話

myobjectx = MODBUSLIB.protocol.ClientCreator(reactor, ModbusClientProtocol 
     ).connectTCP("localhost", Defaults.Port) 

然後由IF觸發的功能:

if ('Gigiisclicked' in existkeys): 

     myobjectx.addCallback(beginAsynchronousTest) 
     myobjectx.callback(beginAsynchronousTest) 
     print "executed" 

這是,當事件發生時,打印重複一遍又一遍,但回調no。

+1

我很困惑。你想每次按下按鈕時運行一個回調嗎?或者你是否想要單擊一次按鈕導致重複調用回調?如果是後者,什麼決定了多少次以及回調被重新調用的時間? –

+0

我想要一個每次按下按鈕時都會運行的回調,只需單擊一下執行關係即可。但現在只有第一次點擊工作,接下來會被忽略。 – user2239318

+0

這個問題取決於你正在使用的GUI庫。沒有這些信息很難回答。 –

回答

3

我想這裏的一個誤解是關於如何使用Deferred的實例。

您應該認爲Deferred有兩種不同的(儘管高度相關)用途。

一個用途是能夠從一些知道如何注意事件已經發生的代碼發佈事件,其他代碼可能有興趣知道事件已經發生。

此用法的一個示例是ClientCreator.connectTCP:此API的實現知道TCP連接嘗試何時成功(或失敗)並使用Deferred將此信息發佈到其他代碼。這樣使用Deferred的代碼實際上是實例化Deferred(例如,d = Deferred())並且稍後使用Deferred.callbackDeferred.errback的代碼。

Deferred的另一個用途是允許對發生過的事件感興趣的代碼瞭解這些事件已經發生。例如,這是您的應用程序需要TCP連接以交換數據 - 但需要等待一個正在設置之前,它可以繼續。這樣使用Deferred的代碼是使用Deferred.addCallbackDeferred.addErrback(在最近版本的Twisted中也是Deferred.cancel)的代碼。

Deferred.addCallback是您用來指定在Deferred最終獲得結果時要運行的代碼的API。

Deferred.callback是您用於將結果提供給Deferred的API。而且,重要的是,一個Deferred只能得到一個結果。每個Deferred實例表示完成單個操作或發生單個事件。

有一些一些例外,有些微妙進一步,但一個很好的經驗法則是,如果你的代碼沒有實例化Deferred那麼你的代碼不應該使用它callback(或errback)方法。調用其中之一是任何創建Deferred的代碼的工作。

鑑於這種情況,我希望這是明確的,在該代碼使用Deferred的API有需要解決的一些問題:

myobjectx = MODBUSLIB.protocol.ClientCreator(reactor, ModbusClientProtocol 
    ).connectTCP("localhost", Defaults.Port) 

... 

if ('Gigiisclicked' in existkeys): 

    myobjectx.addCallback(beginAsynchronousTest) 
    myobjectx.callback(beginAsynchronousTest) 
    print "executed" 

最直接的是,你不應該在這裏呼籲myobjectx.callback。這是ClientCreator.connectTCP的作業(最重要的是,beginAsynchronousTest可能是沒有意義的,結果這個Deferred有)。

相反,我認爲你要使用的ModbusClientProtocol實例的方法是ClientCreator.connectTCP最終會爲你創建。在您鏈接的示例中,請注意beginAsynchronousTest被定義爲接受名爲client的一個參數。

beginAsynchronousTest由於被傳遞給由ClientCreator.connectTCP返回的DeferredaddCallback方法,這意味着它將與ClientCreator初始化所用的協議的實例(在此情況下,ModbusClientProtocol)被調用。換句話說,它將盡快建立連接稱爲 - beginAsynchronousTest將作爲Deferred給出其結果由ClientCreator實施儘快調用。建立一個TCP連接需要一定的時間,因爲它涉及通過任意網絡鏈路與任意其他計算機交換數據 - 不知道這些資源需要多長時間才能完成部分連接設置。

一旦beginAsynchronousTest叫你有一個連接 - 由ModbusClientProtocol實例將傳入表示。這是您的程序中的一個重點,您可以開始執行多項任務(例如,每次單擊按鈕時都會執行某些操作)。

此時Deferred您的程序開始時(在上面的代碼片段中稱爲myobjectx)已經完成,不再有用或有趣,因此您將不再使用它。相反,您將調用方法ModbusClientProtocolread_coilswrite_coil或其他任何您想要執行的操作)。這些方法中的每一種都可能會返回代表該特定操作結果的全新Deferred。您需要使用addCallback以瞭解其結果。

其他地方的人屢受挫折是搞清楚如何使這些附加的方法調用。如果您要添加代碼的beginAsynchronousTest身體那麼它是相當簡單的如何做到這一點:

reading = client.read_coils(1, 1) 

不過,我懷疑你不會希望你的按鍵處理代碼添加到beginAsynchronousTest身體。相反,您的程序中可能有其他位置的事件處理程序,每次按下按鈕時都會調用它。幸運的是,處理這種情況並不複雜。

關鍵是要記住,任何時候你有一個參考到連接,你就可以使用它。在beginAsynchronousTest的內部,您可以參考它 - client參數。您也可以將此引用也用於程序的其他部分:在由程序的必要部分共享的對象上設置屬性是一種常見的,相當好的方法。

class ButtonModbusSomething(object): 
    def __init__(self): 
     self.client = None 

    def connect(self): 
     creator = MODBUSLIB.protocol.ClientCreator(reactor, ModbusClientProtocol) 
     connecting = creator.connectTCP("localhost", Defaults.Port) 
     connecting.addCallback(self._connected) 
     connecting.addErrback(log.err) 

    def _connected(self, client): 
     self.client = client 

    def buttonClicked(self, existkeys): 
     if self.client is not None: 
      if "Gigiisclicked" in existkeys: 
       self.client.read_coil(1, 1) 

注意如何ButtonModbusSomethingclient屬性開始了爲NonebuttonClicked需要如何檢查這種情況。如上所述,建立連接可能需要一些時間,並且您需要知道等待調用_connected需要多長時間。此檢查可確保如果在連接存在之前單擊某個按鈕,該事件將被忽略(您可能希望更好地處理該事件 - 例如,通過以禁用狀態啓動用戶界面,然後僅在連接建立)。

此外,我遺漏了代碼,你可能也想處理你的連接丟失。發生這種情況時,client屬性不再有用。它仍然是連接的ModbusClientProtocol的參考,但由於該協議實例不再有連接,所以很難做任何有用的操作。當連接丟失或者至少開始再次忽略按鈕時,您可能需要重新禁用用戶界面。

此外,請注意,ClientCreator實際上來自twisted.internet.protocol而不是MODBUSLIB.protocol

+0

我沒有閱讀全部內容,但輸入努力爲+1。 – aIKid