diff --git a/examples/RemoteGraphicsView.py b/examples/RemoteGraphicsView.py index a5d869c9..2b74a8c6 100644 --- a/examples/RemoteGraphicsView.py +++ b/examples/RemoteGraphicsView.py @@ -13,7 +13,8 @@ from pyqtgraph.widgets.RemoteGraphicsView import RemoteGraphicsView app = pg.mkQApp() ## Create the widget -v = RemoteGraphicsView(debug=False) +v = RemoteGraphicsView(debug=False) # setting debug=True causes both processes to print information + # about interprocess communication v.show() v.setWindowTitle('pyqtgraph example: RemoteGraphicsView') diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index f6eafb60..810fecec 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -311,13 +311,15 @@ def image(*args, **kargs): return w show = image ## for backward compatibility -def dbg(): +def dbg(*args, **kwds): """ Create a console window and begin watching for exceptions. + + All arguments are passed to :func:`ConsoleWidget.__init__() `. """ mkQApp() from . import console - c = console.ConsoleWidget() + c = console.ConsoleWidget(*args, **kwds) c.catchAllExceptions() c.show() global consoles diff --git a/pyqtgraph/multiprocess/bootstrap.py b/pyqtgraph/multiprocess/bootstrap.py index 4ecfb7da..b82debc2 100644 --- a/pyqtgraph/multiprocess/bootstrap.py +++ b/pyqtgraph/multiprocess/bootstrap.py @@ -20,10 +20,8 @@ if __name__ == '__main__': if opts.pop('pyside', False): import PySide - #import pyqtgraph - #import pyqtgraph.multiprocess.processes + targetStr = opts.pop('targetStr') target = pickle.loads(targetStr) ## unpickling the target should import everything we need - #target(name, port, authkey, ppid) target(**opts) ## Send all other options to the target function sys.exit(0) diff --git a/pyqtgraph/multiprocess/processes.py b/pyqtgraph/multiprocess/processes.py index 7d147a1d..cf802352 100644 --- a/pyqtgraph/multiprocess/processes.py +++ b/pyqtgraph/multiprocess/processes.py @@ -48,9 +48,10 @@ class Process(RemoteEventHandler): it must be picklable (bound methods are not). copySysPath If True, copy the contents of sys.path to the remote process debug If True, print detailed information about communication - with the child process. + with the child process. Note that this option may cause + strange behavior on some systems due to a python bug: + http://bugs.python.org/issue3905 ============ ============================================================= - """ if target is None: target = startEventLoop @@ -81,8 +82,14 @@ class Process(RemoteEventHandler): self.debugMsg('Starting child process (%s %s)' % (executable, bootstrap)) ## note: we need all three streams to have their own PIPE due to this bug: - ## http://bugs.python.org/issue3905 - self.proc = subprocess.Popen((executable, bootstrap), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + ## http://bugs.python.org/issue3905 + if debug is True: # when debugging, we need to keep the usual stdout + stdout = sys.stdout + stderr = sys.stderr + else: + stdout = subprocess.PIPE + stderr = subprocess.PIPE + self.proc = subprocess.Popen((executable, bootstrap), stdin=subprocess.PIPE, stdout=stdout, stderr=stderr) targetStr = pickle.dumps(target) ## double-pickle target so that child has a chance to ## set its sys.path properly before unpickling the target diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py index 0c8921f6..fb535929 100644 --- a/pyqtgraph/widgets/GraphicsView.py +++ b/pyqtgraph/widgets/GraphicsView.py @@ -147,6 +147,11 @@ class GraphicsView(QtGui.QGraphicsView): #print "GV: paint", ev.rect() return QtGui.QGraphicsView.paintEvent(self, ev) + def render(self, *args, **kwds): + self.scene().prepareForPaint() + return QtGui.QGraphicsView.render(self, *args, **kwds) + + def close(self): self.centralWidget = None self.scene().clear() diff --git a/pyqtgraph/widgets/RemoteGraphicsView.py b/pyqtgraph/widgets/RemoteGraphicsView.py index 80f0fb4b..f8bbb6cf 100644 --- a/pyqtgraph/widgets/RemoteGraphicsView.py +++ b/pyqtgraph/widgets/RemoteGraphicsView.py @@ -18,12 +18,15 @@ class RemoteGraphicsView(QtGui.QWidget): """ def __init__(self, parent=None, *args, **kwds): + """ + The keyword arguments 'debug' and 'name', if specified, are passed to QtProcess.__init__(). + """ self._img = None self._imgReq = None self._sizeHint = (640,480) ## no clue why this is needed, but it seems to be the default sizeHint for GraphicsView. ## without it, the widget will not compete for space against another GraphicsView. QtGui.QWidget.__init__(self) - self._proc = mp.QtProcess(debug=kwds.pop('debug', False)) + self._proc = mp.QtProcess(debug=kwds.pop('debug', False), name=kwds.pop('name', None)) self.pg = self._proc._import('pyqtgraph') self.pg.setConfigOptions(**self.pg.CONFIG_OPTIONS) rpgRemote = self._proc._import('pyqtgraph.widgets.RemoteGraphicsView') @@ -123,6 +126,7 @@ class Renderer(GraphicsView): def __init__(self, *args, **kwds): ## Create shared memory for rendered image + #pg.dbg(namespace={'r': self}) if sys.platform.startswith('win'): self.shmtag = "pyqtgraph_shmem_" + ''.join([chr((random.getrandbits(20)%25) + 97) for i in range(20)]) self.shm = mmap.mmap(-1, mmap.PAGESIZE, self.shmtag) # use anonymous mmap on windows @@ -184,7 +188,11 @@ class Renderer(GraphicsView): self.img = QtGui.QImage(ch, self.width(), self.height(), QtGui.QImage.Format_ARGB32) else: address = ctypes.addressof(ctypes.c_char.from_buffer(self.shm, 0)) - self.img = QtGui.QImage(sip.voidptr(address), self.width(), self.height(), QtGui.QImage.Format_ARGB32) + try: + self.img = QtGui.QImage(sip.voidptr(address), self.width(), self.height(), QtGui.QImage.Format_ARGB32) + except TypeError: + # different versions of pyqt have different requirements here.. + self.img = QtGui.QImage(memoryview(buffer(self.shm)), self.width(), self.height(), QtGui.QImage.Format_ARGB32) self.img.fill(0xffffffff) p = QtGui.QPainter(self.img) self.render(p, self.viewRect(), self.rect())