Bugfixes:

- GraphicsView.render now correctly invokes GraphicsScene.prepareForPaint
 - Fixed RemoteGraphicsView renderer to use new PyQt QImage API.
 - multiprocess.Process now pipes stdout/err directly to console when in debugging mode
This commit is contained in:
Luke Campagnola 2013-11-06 23:14:27 -05:00
parent ea8079334f
commit 31928e70a5
6 changed files with 33 additions and 12 deletions

View File

@ -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')

View File

@ -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__() <pyqtgraph.console.ConsoleWidget.__init__>`.
"""
mkQApp()
from . import console
c = console.ConsoleWidget()
c = console.ConsoleWidget(*args, **kwds)
c.catchAllExceptions()
c.show()
global consoles

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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())