help about PyQt Twisted Thread

268 views
Skip to first unread message

seeks

unread,
Aug 17, 2012, 12:37:08 AM8/17/12
to python_in...@googlegroups.com
Hello, everyone, I have a twisted use in python. The red part of the problem in the following code.
I want a process a call to the remote server command, but I failed, I can not find the reason, can help?



import sys,time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from net.client import FilmStudioClient
from twisted.python import log

def DefaultErrorHandler(exc):
    msg = '%s\n\n%s' % (exc.getErrorMessage(), str(exc))   
    log.msg(msg)   

class Window(QWidget):
    a = 0
    def __init__(self,reactor, parent = None):
   
        QWidget.__init__(self, parent)
        self.projects = []
        self.reactor = reactor
        button = QPushButton(self.tr("Click me"))
        self.resultLabel = QLabel(self.tr("..."))
        self.client = FilmStudioClient(reactor,self.onDisconnected)
        # New style: uses the connect method of a pyqtSignal object.
        self.connect(button, SIGNAL("clicked()"), self.handleClick)
       
        # Old style: uses the SIGNAL function to describe the signal.
        self.connect(self, SIGNAL("sendValue(PyQt_PyObject)"), self.handleValue)
       
        layout = QVBoxLayout(self)
        layout.addWidget(button)
        layout.addWidget(self.resultLabel)
       
        self.threadPool = []

    def connectAnonymous(self):
        self.client.connectAnonymous("192.168.0.108",7777).addCallback(self.onConnected).addErrback( DefaultErrorHandler ) 
    def handleClick(self):   
        #self.connectAnonymous()  
        self.threadPool.append( GenericThread(self.getP) )
        self.disconnect( self, SIGNAL("sendValue(PyQt_PyObject)"), self.handleValue )
        self.connect( self, SIGNAL("sendValue(PyQt_PyObject)"), self.handleValue )
        self.threadPool[len(self.threadPool)-1].start()

    def getP(self):
        while True:
            time.sleep(1)
            #self.connectAnonymous()
            # i can not get projects from QThread because getProjects_OK was not run.
            self.client.perspective.callRemote( 'getProjects').addCallback(self.getProjects_OK)
            #self.client.getProjects().addCallback(self.getProjects_OK).addErrback(self.getProjects_Failed)
            self.emit(SIGNAL("sendValue(PyQt_PyObject)"), self.projects)
           
    def handleValue(self, value):   
        self.resultLabel.setText(repr(value))       

    def onConnected(self, perspective):
        self.connected = True
    def onDisconnected(self):
        self.connected = False
       
    def getProjects_OK(self,info):
        print "get-ok",info,"done"
        self.projects = []
        for i in info:
            print "project:",i
            self.projects.append(i.name)
    def getProjects_Failed(self,exc):
        print "getProjects_Failed",exc
       
       
class GenericThread(QThread):
    def __init__(self, function, *args, **kwargs):
        QThread.__init__(self)
        self.function = function
        self.args = args
        self.kwargs = kwargs

    def __del__(self):
        self.wait()

    def run(self):
        self.function(*self.args,**self.kwargs)
        return      
       
def main():

    import sys
    try:
        import qt4reactor
    except ImportError:
        # Maybe qt4reactor is placed inside twisted.internet in site-packages?
        from twisted.internet import qt4reactor
    qt4reactor.install() 
   
    from twisted.internet import reactor   

    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create("Plastique"))   
    win = Window(reactor)
    win.connectAnonymous()
    win.show()
   


    reactor.run()

Donal McMullan

unread,
Aug 17, 2012, 1:05:44 AM8/17/12
to python_in...@googlegroups.com
There are a couple of red flags here. One is the use of "while True". The other is the use of time.sleep.

It seems that you may want to emit the signal in your callback method - until that method is called the "self.projects" attribute will not be (correctly) populated.

Something like this:


    def getP(self):
        df = self.client.perspective.callRemote('getProjects')
        df.addCallback(self.getProjects_OK)
        df.addErrback(self.getProjects_Failed)
        """
        Note: we don't have the result of 'getProjects' yet.
        """
        return df

          
    def getProjects_OK(self,info):
        """
        The result of 'getProjects' has arrived.
        """

        print "get-ok",info,"done"
        self.projects = []

        for i in info:
            print "project:",i
            self.projects.append(i.name)

        self.emit(SIGNAL("sendValue(PyQt_PyObject)"), self.projects)

    def getProjects_Failed(self,exc):
        print "getProjects_Failed",exc



I wonder which version of the reactor you're using? I imagine you want to use the qtreactor?

I'm not clear on what you wanted to use 'time.sleep' for... if you need to introduce a delay while some other step completes, it might be better to have a look at using reactor.callLater.

I hope that's helpful.

Donal
--
view archives: http://groups.google.com/group/python_inside_maya
change your subscription settings: http://groups.google.com/group/python_inside_maya/subscribe


-- 

Donal McMullan
Production Engineer

seeks

unread,
Aug 17, 2012, 1:54:04 AM8/17/12
to python_in...@googlegroups.com
hi,Cuchullain,Thank you for your quick reply, I modified a version is now able to work, I would like to get the latest news from the server.I do not know this good
        self.timer = QTimer()
        QObject.connect(self.timer,SIGNAL("timeout()"),self.getP)
        self.timer.start(200)
I reactor is used QtReator, and because I use is PyQt.
reactor.callLater (time, function) I also tried, but failed.



在 2012年8月17日星期五UTC+8下午12时37分08秒,seeks写道:

Donal McMullan

unread,
Aug 17, 2012, 2:44:59 AM8/17/12
to python_in...@googlegroups.com
I'm not sure what you're attempting here... are you trying to set a 200ms timeout for your request to self.getP ?

D

seeks

unread,
Aug 17, 2012, 4:04:12 AM8/17/12
to python_in...@googlegroups.com
Because I want the client every 200ms synchronization server message. The server provides the client calls the command, this is just my idea, it can work, for example, when I add a project on the server, or delete a project I want my client to get the server instant message.

在 2012年8月17日星期五UTC+8下午12时37分08秒,seeks写道:

Justin Israel

unread,
Aug 17, 2012, 12:05:09 PM8/17/12
to python_in...@googlegroups.com, python_in...@googlegroups.com
There is a lot going on with this code, so it is harder to understand. But I see some issues already. 
In your red code that is being run in a thread, you do an async callRemote to twisted with a callback. But then you emit a custom signal right after, as if data might be ready? 
Also, the callback you are giving it goes and appends into a list that is being shared by your main thread. This effectively makes the signaling pointless because you are doing unsafe memory sharing with that list. It could be clearing and appending while the main thread is reading on it. You would simply want to emit a signal with the incoming list as the callback, which will be thread safe because it will be placed into the queue and then run from the main event loop. 
But really, I dont think you should be using an async call like that in a thread loop anyways. It will jusg be firing off requests over and over and letting them constantly come back whenever they are done. You could do that with a normal QTimer if thats what you wanted. I think if you want a thread for this, then it should be a blocking call that waits for results, and emits a signal with them. 

You have some comments up top about new and old style signals, but really you are just using old signals. Are you sure the signatures are right and they are being fired?

New style looks like this...

#Connecting a signal
self.button.clicked.connect(self.handleClick)

And for custom signals, you define a class attribute at the top...

@pyqtSignal
sendValue(object)

Then when you want to emit...
self.sendValue.emit(new_projects)

Your GenericThread should still be able to accept the parent argument in the init. The you can transfer them to qt and not save them. For starting your thread, you can simply do:
t = GenericThread(fooFunc, parent=self)
t.start()
Reply all
Reply to author
Forward
0 new messages