[Paraview] python plugin custom dialog causes paraview to hang
pat marion
pat.marion at kitware.com
Thu Oct 14 13:48:50 EDT 2010
Are you working from a paraview installer, or compiling paraview yourself?
I was able to reproduce the linux bug (by putting a 'print "hello"' at the
end) and then solve it by commenting out two lines in
ParaView/Qt/Python/pqPythonShell.cxx. Just search for the lines with
"processEvents" and comment them out and then recompile.
I'll try to explain it why this fixes the problem-
Before paraview executes the python script it acquires a lock. The lock is
part of the python C api to help make things thread safe (
http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock).
Paraview doesn't use threads, but it uses multiple python
interpreters,
and each interpreter has its own "thread state". So before any code is
executed by the paraview python shell, the shell acquires the lock to
activate its interpreter.
Next, the python script hits a print statement which sends an output string
to the paraview python shell. The shell calls processEvents so that the
widget has an opportunity to repaint itself (make the text appear on your
screen) without having to wait for the entire python script to complete
execution. The problem is that during processEvents, the events generated
by calling show on a PyQt widget are also processed. While processing these
events, PyQt tries to acquire the lock itself, fails, and then waits-
paraview hangs because this all happens in the same thread. The fix is
either to comment out the processEvents call in pqPythonShell.cxx, or
release the lock before calling processEvents and then reacquire it
afterward.
I have never tested PyQt+Paraview on Windows, there may be further bugs.
Also, there could be other scenarios where the paraview python shell and
PyQt fight over the lock.
Hope this helps a bit!
Pat
On Wed, Oct 13, 2010 at 5:29 PM, <m.c.wilkins at massey.ac.nz> wrote:
>
> Hi
>
> I posted about this ages ago, and with your help got it working on
> linux, but now I am having problems getting it going under Windows.
>
> Let me summarize what I am doing.
>
> I am writing a Python plugin, and I want to popup a custom dialog.
> For simple dialogs I have found:
>
> import PyQt4.QtGui
> l = PyQt4.QtGui.QInputDialog.getText(wid, 'Slice', 'Length')
>
> to work fine. But I need more complicate dialogs. Yes I have read
>
> http://paraview.markmail.org/message/6h767kpak5dcoqwt
>
> (thanks Pat), otherwise surely I would not have made it this far!
>
> My code is below. It runs fine under paraview linux, and it runs fine
> in a nonparaview simple test app under Windows, but when running under
> paraview on Windows, it hangs when I push the OK button.
>
> In the URL above, it says one shouldn't use exec_() and I am
> (incidentally it works under linux ok). I tried to use setModal(True)
> then show(), but control returns immediately to me, then paraview
> hangs anyway.
>
> Also in the URL above, the example works just fine for me, unless I
> put a simple 'print "hello"' at the end, then paraview hangs.
> Something way beyond my meagre skills is happening here. Please any
> help is much appreciated!
>
>
> import os,sys
> from PyQt4.QtGui import *
> from PyQt4.QtCore import *
> import paraview
>
> def callback_wrapper(func):
> v = paraview.vtk.vtkObject()
> def wrap(*args, **kwargs):
> v._args = args
> v._kwargs = kwargs
> v.Modified()
> def callback(o, e): func(*v._args, **v._kwargs)
> v.AddObserver("ModifiedEvent", callback)
> return wrap
>
> class MyDialog(QDialog):
>
> def __init__(self, *args):
> QDialog.__init__(self, *args)
> self.start = 0
>
> buttonBox = QDialogButtonBox()
> okButton = buttonBox.addButton(buttonBox.Ok)
>
> QObject.connect(okButton, SIGNAL("clicked()"), self.accepted)
> layout = QVBoxLayout()
> layout.addWidget(buttonBox)
> self.setLayout(layout)
>
> @callback_wrapper
> def accepted(self):
> self.start = 1
> self.accept()
>
> #app = QApplication(sys.argv)
>
> foo = MyDialog()
>
> # this hangs paraview under windows
> #foo.setModal(True)
> #foo.show()
>
> # this works on linux, but hangs (just prints OK:) under windows if
> # user pushes OK
> if foo.exec_():
> print "OK:", foo.start
> else:
> print "They cancelled", foo.start
>
>
>
>
> Matt Wilkins
>
> On Thu, Jun 17, 2010 at 10:33:08AM +1200, m.c.wilkins at massey.ac.nz wrote:
> >
> > Hi,
> >
> > I hang my head in shame, I really should have thrown my code into a
> > nonparaview test app. I will do that in future.
> >
> > Pat you simply are the best! Thank you so much.
> >
> > The business about self.acceptfoo vs self, acceptfoo arises from my
> > lack of understanding about the slots/signals in Qt. I've seen stuff
> > like:
> >
> > QObject.connect(a, SIGNAL("clicked()"), a, SLOT("quit()"))
> >
> > which indicate you put target object, then the slot, but also stuff
> > like:
> >
> > QObject.connect(a, SIGNAL("clicked()"), self.rejectfoo)
> >
> > which I guess you use when the target of the signal is not a Qt SLOT
> > as such.
> >
> > Anyway, I am very thankful to you Pat, and this list in general.
> >
> > Matt
> >
> > On Wed, Jun 16, 2010 at 06:11:01PM -0400, pat marion wrote:
> > > Hi,
> > >
> > > So at the very end of that email that you linked, I mentioned the
> problem that
> > > paraview hangs when it encounters a runtime error, instead of reporting
> the
> > > error. I haven't had the chance to investigate the problem, but it's
> really
> > > annoying!
> > >
> > > Anyway, I think your problem is just a few typos... try adding:
> > >
> > >
> > > from PyQt4.QtCore import *
> > >
> > >
> > > at the top. Also, you had commas instead of periods in two places:
> > >
> > > foo,input1 --> foo.input1
> > > self, acceptfoo --> self.acceptfoo
> > >
> > >
> > > I debugged the problems by running your script in regular python. I
> commented
> > > out the callback_wrapper and then just added:
> > >
> > > import sys
> > > app = QApplication(sys.argv)
> > >
> > > before the main script begins. Doing it this way made it easy to spot
> the
> > > typos.
> > >
> > >
> > > Pat
> > >
> > >
> > > On Wed, Jun 16, 2010 at 5:14 PM, <m.c.wilkins at massey.ac.nz> wrote:
> > >
> > >
> > > Hi,
> > >
> > > I am writing a Python plugin, and I want to popup a custom dialog.
> > > For simple dialogs I have found:
> > >
> > > import PyQt4.QtGui
> > > l = PyQt4.QtGui.QInputDialog.getText(wid, 'Slice', 'Length')
> > >
> > > to work fine. But I need more complicate dialogs. I just can't
> get
> > > the signals/slots to work. Yes I have read
> > >
> > > http://paraview.markmail.org/message/6h767kpak5dcoqwt
> > >
> > > (thanks Pat), otherwise surely I would not have made it this far!
> > >
> > > Here is my plugin, and any time I uncomment either of the connect
> > > lines, paraview (built from git about a week ago) just hangs.
> Without
> > > those lines, the dialog doesn't work of course; I can cancel it
> with
> > > the window decorator, but that is it.
> > >
> > > Thank you for any help, this is beyond me, just reading the
> definition
> > > of callback_wrapper makes my head hurt, I hope it doesn't hurt
> yours
> > > ;-)
> > >
> > > Matt
> > >
> > >
> > > from PyQt4.QtGui import *
> > >
> > > def callback_wrapper(func):
> > > v = paraview.vtk.vtkObject()
> > > def wrap(*args, **kwargs):
> > > v._args = args
> > > v._kwargs = kwargs
> > > v.Modified()
> > > def callback(o, e): func(*v._args, **v._kwargs)
> > > v.AddObserver("ModifiedEvent", callback)
> > > return wrap
> > >
> > > class MyDialog(QDialog):
> > >
> > > def __init__(self, *args):
> > > QDialog.__init__(self, *args)
> > >
> > > buttonBox = QDialogButtonBox()
> > > okButton = buttonBox.addButton(buttonBox.Ok)
> > > cancelButton = buttonBox.addButton(buttonBox.Cancel)
> > >
> > > label0 = QLabel("Foo", self)
> > > self.le0 = le0 = QLineEdit(self)
> > >
> > > label1 = QLabel("Bar", self)
> > > self.le1 = le1 = QLineEdit(self)
> > >
> > > # either of these lines cause paraview to lock up
> > > #QObject.connect(okButton, SIGNAL("clicked()"), self,
> acceptfoo)
> > > #QObject.connect(cancelButton, SIGNAL("clicked()"),
> self.rejectfoo)
> > >
> > > layout = QGridLayout()
> > > layout.addWidget(label0, 0, 0)
> > > layout.addWidget(le0, 0, 1)
> > > layout.addWidget(label1, 1, 0)
> > > layout.addWidget(le1, 1, 1)
> > > layout.addWidget(buttonBox, 2, 0, 1, 2)
> > > self.setLayout(layout)
> > >
> > > @callback_wrapper
> > > def acceptfoo(self):
> > > self.input0 = self.le0.text()
> > > self.input1 = self.le1.text()
> > > self.accept()
> > >
> > > @callback_wrapper
> > > def rejectfoo(self):
> > > print "Doing reject"
> > > self.reject()
> > >
> > >
> > > foo = MyDialog()
> > > if foo.exec_():
> > > print "OK:", foo.input0, foo,input1
> > > else:
> > > print "They cancelled"
> > >
> > >
> > >
> > > _______________________________________________
> > > Powered by www.kitware.com
> > >
> > > Visit other Kitware open-source projects at
> http://www.kitware.com/
> > > opensource/opensource.html
> > >
> > > Please keep messages on-topic and check the ParaView Wiki at:
> http://
> > > paraview.org/Wiki/ParaView
> > >
> > > Follow this link to subscribe/unsubscribe:
> > > http://www.paraview.org/mailman/listinfo/paraview
> > >
> > >
> > _______________________________________________
> > Powered by www.kitware.com
> >
> > Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
> >
> > Please keep messages on-topic and check the ParaView Wiki at:
> http://paraview.org/Wiki/ParaView
> >
> > Follow this link to subscribe/unsubscribe:
> > http://www.paraview.org/mailman/listinfo/paraview
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.paraview.org/pipermail/paraview/attachments/20101014/c1524cf3/attachment-0001.htm>
More information about the ParaView
mailing list