From 8899e8d858d0e4740f9a339a40647ca6808202c1 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Wed, 26 Dec 2012 16:29:29 -0500 Subject: [PATCH] Updated image, SVG, and print exporters. Image export works well; SVG and print still need work. Added ability to run examples with a specific Qt graphics system --- examples/__main__.py | 15 +++-- examples/exampleLoaderTemplate.ui | 30 +++++++++ examples/exampleLoaderTemplate_pyqt.py | 18 ++++- examples/exampleLoaderTemplate_pyside.py | 20 +++++- examples/initExample.py | 12 +++- exporters/ImageExporter.py | 18 +++-- exporters/PrintExporter.py | 16 +++-- exporters/SVGExporter.py | 2 +- graphicsItems/ArrowItem.py | 5 ++ graphicsItems/GraphicsItem.py | 20 +++++- graphicsItems/PlotCurveItem.py | 12 +--- graphicsItems/ScatterPlotItem.py | 43 ++++++------ graphicsItems/TextItem.py | 83 +++++++++++------------- 13 files changed, 194 insertions(+), 100 deletions(-) diff --git a/examples/__main__.py b/examples/__main__.py index 6f4bf138..1dbe7b9a 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -126,6 +126,9 @@ class ExampleLoader(QtGui.QMainWindow): extra.append('pyqt') elif self.ui.pysideCheck.isChecked(): extra.append('pyside') + + if self.ui.forceGraphicsCheck.isChecked(): + extra.append(str(self.ui.forceGraphicsCombo.currentText())) if fn is None: return @@ -163,22 +166,26 @@ def buildFileList(examples, files=None): buildFileList(val, files) return files -def testFile(name, f, exe, lib): +def testFile(name, f, exe, lib, graphicsSystem): global path fn = os.path.join(path,f) #print "starting process: ", fn - + os.chdir(path) sys.stdout.write(name) sys.stdout.flush() + import1 = "import %s" % lib if lib != '' else '' + import2 = os.path.splitext(os.path.split(fn)[1])[0] + graphicsSystem = '' if graphicsSystem is None else "pg.QtGui.QApplication.setGraphicsSystem('%s')" % graphicsSystem code = """ try: + %s + import pyqtgraph as pg %s import %s import sys print("test complete") sys.stdout.flush() - import pyqtgraph as pg import time while True: ## run a little event loop pg.QtGui.QApplication.processEvents() @@ -187,7 +194,7 @@ except: print("test failed") raise -""" % ("import %s" % lib if lib != '' else "", os.path.splitext(os.path.split(fn)[1])[0]) +""" % (import1, import2, graphicsSystem) #print code process = subprocess.Popen(['exec %s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) process.stdin.write(code.encode('UTF-8')) diff --git a/examples/exampleLoaderTemplate.ui b/examples/exampleLoaderTemplate.ui index 1453240c..cd5ce921 100644 --- a/examples/exampleLoaderTemplate.ui +++ b/examples/exampleLoaderTemplate.ui @@ -57,6 +57,36 @@ + + + + + + Force Graphics System: + + + + + + + + native + + + + + raster + + + + + opengl + + + + + + diff --git a/examples/exampleLoaderTemplate_pyqt.py b/examples/exampleLoaderTemplate_pyqt.py index 26e55a44..f359cc32 100644 --- a/examples/exampleLoaderTemplate_pyqt.py +++ b/examples/exampleLoaderTemplate_pyqt.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' # -# Created: Fri Oct 26 07:53:55 2012 +# Created: Mon Dec 24 00:33:38 2012 # by: PyQt4 UI code generator 4.9.1 # # WARNING! All changes made in this file will be lost! @@ -44,6 +44,18 @@ class Ui_Form(object): self.pysideCheck.setObjectName(_fromUtf8("pysideCheck")) self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck.setObjectName(_fromUtf8("forceGraphicsCheck")) + self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) + self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo.setObjectName(_fromUtf8("forceGraphicsCombo")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) + self.verticalLayout.addLayout(self.horizontalLayout_2) self.loadBtn = QtGui.QPushButton(self.layoutWidget) self.loadBtn.setObjectName(_fromUtf8("loadBtn")) self.verticalLayout.addWidget(self.loadBtn) @@ -62,5 +74,9 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) self.pyqtCheck.setText(QtGui.QApplication.translate("Form", "Force PyQt", None, QtGui.QApplication.UnicodeUTF8)) self.pysideCheck.setText(QtGui.QApplication.translate("Form", "Force PySide", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCheck.setText(QtGui.QApplication.translate("Form", "Force Graphics System:", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/exampleLoaderTemplate_pyside.py b/examples/exampleLoaderTemplate_pyside.py index a81f7299..113c1654 100644 --- a/examples/exampleLoaderTemplate_pyside.py +++ b/examples/exampleLoaderTemplate_pyside.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' # -# Created: Fri Oct 26 07:53:57 2012 -# by: pyside-uic 0.2.13 running on PySide 1.1.0 +# Created: Mon Dec 24 00:33:39 2012 +# by: pyside-uic 0.2.13 running on PySide 1.1.2 # # WARNING! All changes made in this file will be lost! @@ -39,6 +39,18 @@ class Ui_Form(object): self.pysideCheck.setObjectName("pysideCheck") self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck.setObjectName("forceGraphicsCheck") + self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) + self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo.setObjectName("forceGraphicsCombo") + self.forceGraphicsCombo.addItem("") + self.forceGraphicsCombo.addItem("") + self.forceGraphicsCombo.addItem("") + self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) + self.verticalLayout.addLayout(self.horizontalLayout_2) self.loadBtn = QtGui.QPushButton(self.layoutWidget) self.loadBtn.setObjectName("loadBtn") self.verticalLayout.addWidget(self.loadBtn) @@ -57,5 +69,9 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) self.pyqtCheck.setText(QtGui.QApplication.translate("Form", "Force PyQt", None, QtGui.QApplication.UnicodeUTF8)) self.pysideCheck.setText(QtGui.QApplication.translate("Form", "Force PySide", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCheck.setText(QtGui.QApplication.translate("Form", "Force Graphics System:", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/initExample.py b/examples/initExample.py index 1b38363b..908f5fb0 100644 --- a/examples/initExample.py +++ b/examples/initExample.py @@ -3,6 +3,14 @@ import sys, os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) if 'pyside' in sys.argv: ## should force example to use PySide instead of PyQt - import PySide + from PySide import QtGui elif 'pyqt' in sys.argv: - import PyQt4 + from PyQt4 import QtGui +else: + from pyqtgraph.Qt import QtGui + +for gs in ['raster', 'native', 'opengl']: + if gs in sys.argv: + QtGui.QApplication.setGraphicsSystem(gs) + break + diff --git a/exporters/ImageExporter.py b/exporters/ImageExporter.py index 763b615d..cb6cf396 100644 --- a/exporters/ImageExporter.py +++ b/exporters/ImageExporter.py @@ -27,12 +27,12 @@ class ImageExporter(Exporter): def widthChanged(self): sr = self.getSourceRect() - ar = sr.height() / sr.width() + ar = float(sr.height()) / sr.width() self.params.param('height').setValue(self.params['width'] * ar, blockSignal=self.heightChanged) def heightChanged(self): sr = self.getSourceRect() - ar = sr.width() / sr.height() + ar = float(sr.width()) / sr.height() self.params.param('width').setValue(self.params['height'] * ar, blockSignal=self.widthChanged) def parameters(self): @@ -51,6 +51,8 @@ class ImageExporter(Exporter): targetRect = QtCore.QRect(0, 0, self.params['width'], self.params['height']) sourceRect = self.getSourceRect() + + #self.png = QtGui.QImage(targetRect.size(), QtGui.QImage.Format_ARGB32) #self.png.fill(pyqtgraph.mkColor(self.params['background'])) bg = np.empty((self.params['width'], self.params['height'], 4), dtype=np.ubyte) @@ -60,11 +62,19 @@ class ImageExporter(Exporter): bg[:,:,2] = color.red() bg[:,:,3] = color.alpha() self.png = pg.makeQImage(bg, alpha=True) + + ## set resolution of image: + origTargetRect = self.getTargetRect() + resolutionScale = targetRect.width() / origTargetRect.width() + #self.png.setDotsPerMeterX(self.png.dotsPerMeterX() * resolutionScale) + #self.png.setDotsPerMeterY(self.png.dotsPerMeterY() * resolutionScale) + painter = QtGui.QPainter(self.png) + #dtr = painter.deviceTransform() try: - self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background']}) + self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background'], 'painter': painter, 'resolutionScale': resolutionScale}) painter.setRenderHint(QtGui.QPainter.Antialiasing, self.params['antialias']) - self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect) + self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect)) finally: self.setExportMode(False) painter.end() diff --git a/exporters/PrintExporter.py b/exporters/PrintExporter.py index 4a47af2e..5b31b45d 100644 --- a/exporters/PrintExporter.py +++ b/exporters/PrintExporter.py @@ -3,8 +3,8 @@ from pyqtgraph.parametertree import Parameter from pyqtgraph.Qt import QtGui, QtCore, QtSvg import re -#__all__ = ['PrintExporter'] -__all__ = [] ## Printer is disabled for now--does not work very well. +__all__ = ['PrintExporter'] +#__all__ = [] ## Printer is disabled for now--does not work very well. class PrintExporter(Exporter): Name = "Printer" @@ -38,9 +38,15 @@ class PrintExporter(Exporter): if dialog.exec_() != QtGui.QDialog.Accepted: return; + #dpi = QtGui.QDesktopWidget().physicalDpiX() + #self.svg.setSize(QtCore.QSize(100,100)) #self.svg.setResolution(600) - res = printer.resolution() + #res = printer.resolution() + sr = self.getSourceRect() + #res = sr.width() * .4 / (self.params['width'] * 100 / 2.54) + res = QtGui.QDesktopWidget().physicalDpiX() + printer.setResolution(res) rect = printer.pageRect() center = rect.center() h = self.params['height'] * res * 100. / 2.54 @@ -52,8 +58,8 @@ class PrintExporter(Exporter): sourceRect = self.getSourceRect() painter = QtGui.QPainter(printer) try: - self.setExportMode(True) - self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect) + self.setExportMode(True, {'painter': painter}) + self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect)) finally: self.setExportMode(False) painter.end() diff --git a/exporters/SVGExporter.py b/exporters/SVGExporter.py index 2d040282..134330d4 100644 --- a/exporters/SVGExporter.py +++ b/exporters/SVGExporter.py @@ -46,7 +46,7 @@ class SVGExporter(Exporter): painter = QtGui.QPainter(self.svg) try: - self.setExportMode(True) + self.setExportMode(True, {'painter': painter,}) self.render(painter, QtCore.QRectF(targetRect), sourceRect) finally: self.setExportMode(False) diff --git a/graphicsItems/ArrowItem.py b/graphicsItems/ArrowItem.py index 153ea712..22d0065b 100644 --- a/graphicsItems/ArrowItem.py +++ b/graphicsItems/ArrowItem.py @@ -54,3 +54,8 @@ class ArrowItem(QtGui.QGraphicsPathItem): def paint(self, p, *args): p.setRenderHint(QtGui.QPainter.Antialiasing) QtGui.QGraphicsPathItem.paint(self, p, *args) + + def shape(self): + #if not self.opts['pxMode']: + #return QtGui.QGraphicsPathItem.shape(self) + return self.path \ No newline at end of file diff --git a/graphicsItems/GraphicsItem.py b/graphicsItems/GraphicsItem.py index 43b8148c..d3021b75 100644 --- a/graphicsItems/GraphicsItem.py +++ b/graphicsItems/GraphicsItem.py @@ -28,10 +28,13 @@ class GraphicsItem(object): self._viewWidget = None self._viewBox = None self._connectedView = None + self._exportOpts = False ## If False, not currently exporting. Otherwise, contains dict of export options. if register: GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items() - + + + def getViewWidget(self): """ Return the view widget for this item. If the scene has multiple views, only the first view is returned. @@ -82,6 +85,9 @@ class GraphicsItem(object): Return the transform that converts local item coordinates to device coordinates (usually pixels). Extends deviceTransform to automatically determine the viewportTransform. """ + if self._exportOpts is not False and 'painter' in self._exportOpts: ## currently exporting; device transform may be different. + return self._exportOpts['painter'].deviceTransform() + if viewportTransform is None: view = self.getViewWidget() if view is None: @@ -476,4 +482,16 @@ class GraphicsItem(object): return tree + def setExportMode(self, export, opts): + """ + This method is called by exporters to inform items that they are being drawn for export + with a specific set of options. Items access these via self._exportOptions. + When exporting is complete, _exportOptions is set to False. + """ + if export: + self._exportOpts = opts + #if 'antialias' not in opts: + #self._exportOpts['antialias'] = True + else: + self._exportOpts = False \ No newline at end of file diff --git a/graphicsItems/PlotCurveItem.py b/graphicsItems/PlotCurveItem.py index c49ce30b..dbbeb077 100644 --- a/graphicsItems/PlotCurveItem.py +++ b/graphicsItems/PlotCurveItem.py @@ -52,7 +52,6 @@ class PlotCurveItem(GraphicsObject): self.clear() self.path = None self.fillPath = None - self.exportOpts = False ## this is disastrous for performance. @@ -404,8 +403,8 @@ class PlotCurveItem(GraphicsObject): path = self.path prof.mark('generate path') - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] + if self._exportOpts is not False: + aa = self._exportOpts.get('antialias', True) else: aa = self.opts['antialias'] @@ -487,13 +486,6 @@ class PlotCurveItem(GraphicsObject): ev.accept() self.sigClicked.emit(self) - def setExportMode(self, export, opts): - if export: - self.exportOpts = opts - if 'antialias' not in opts: - self.exportOpts['antialias'] = True - else: - self.exportOpts = False class ROIPlotItem(PlotCurveItem): """Plot curve that monitors an ROI and image for changes to automatically replot.""" diff --git a/graphicsItems/ScatterPlotItem.py b/graphicsItems/ScatterPlotItem.py index 2528d35b..2e41cb7c 100644 --- a/graphicsItems/ScatterPlotItem.py +++ b/graphicsItems/ScatterPlotItem.py @@ -239,7 +239,6 @@ class ScatterPlotItem(GraphicsObject): 'useCache': True, ## If useCache is False, symbols are re-drawn on every paint. 'antialias': pg.getConfigOption('antialias'), } - self.exportOpts = False self.setPen(200,200,200, update=False) self.setBrush(100,100,150, update=False) @@ -546,7 +545,7 @@ class ScatterPlotItem(GraphicsObject): if invalidate: self.invalidate() - def getSpotOpts(self, recs): + def getSpotOpts(self, recs, scale=1.0): if recs.ndim == 0: rec = recs symbol = rec['symbol'] @@ -561,11 +560,12 @@ class ScatterPlotItem(GraphicsObject): brush = rec['brush'] if brush is None: brush = self.opts['brush'] - return (symbol, size, fn.mkPen(pen), fn.mkBrush(brush)) + return (symbol, size*scale, fn.mkPen(pen), fn.mkBrush(brush)) else: recs = recs.copy() recs['symbol'][np.equal(recs['symbol'], None)] = self.opts['symbol'] recs['size'][np.equal(recs['size'], -1)] = self.opts['size'] + recs['size'] *= scale recs['pen'][np.equal(recs['pen'], None)] = fn.mkPen(self.opts['pen']) recs['brush'][np.equal(recs['brush'], None)] = fn.mkBrush(self.opts['brush']) return recs @@ -675,18 +675,20 @@ class ScatterPlotItem(GraphicsObject): rect = QtCore.QRectF(y, x, h, w) self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect)) - def setExportMode(self, export, opts): - if export: - self.exportOpts = opts - if 'antialias' not in opts: - self.exportOpts['antialias'] = True - else: - self.exportOpts = False - + def setExportMode(self, *args, **kwds): + GraphicsObject.setExportMode(self, *args, **kwds) + self.invalidate() def paint(self, p, *args): #p.setPen(fn.mkPen('r')) #p.drawRect(self.boundingRect()) + if self._exportOpts is not False: + aa = self._exportOpts.get('antialias', True) + scale = self._exportOpts.get('resolutionScale', 1.0) ## exporting to image; pixel resolution may have changed + else: + aa = self.opts['antialias'] + scale = 1.0 + if self.opts['pxMode'] is True: atlas = self.fragmentAtlas.getAtlas() #arr = fn.imageToArray(atlas.toImage(), copy=True) @@ -701,13 +703,9 @@ class ScatterPlotItem(GraphicsObject): p.resetTransform() - if not USE_PYSIDE and self.opts['useCache'] and self.exportOpts is False: + if not USE_PYSIDE and self.opts['useCache'] and self._exportOpts is False: p.drawPixmapFragments(self.fragments, atlas) else: - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] - else: - aa = self.opts['antialias'] p.setRenderHint(p.Antialiasing, aa) for i in range(len(self.data)): @@ -715,23 +713,20 @@ class ScatterPlotItem(GraphicsObject): frag = self.fragments[i] p.resetTransform() p.translate(frag.x, frag.y) - drawSymbol(p, *self.getSpotOpts(rec)) + drawSymbol(p, *self.getSpotOpts(rec, scale)) else: if self.picture is None: self.picture = QtGui.QPicture() p2 = QtGui.QPainter(self.picture) for rec in self.data: - + if scale != 1.0: + rec = rec.copy() + rec['size'] *= scale p2.resetTransform() p2.translate(rec['x'], rec['y']) - drawSymbol(p2, *self.getSpotOpts(rec)) + drawSymbol(p2, *self.getSpotOpts(rec, scale)) p2.end() - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] - else: - aa = self.opts['antialias'] - p.setRenderHint(p.Antialiasing, aa) self.picture.play(p) diff --git a/graphicsItems/TextItem.py b/graphicsItems/TextItem.py index a85e919d..b5666f6e 100644 --- a/graphicsItems/TextItem.py +++ b/graphicsItems/TextItem.py @@ -27,25 +27,27 @@ class TextItem(UIGraphicsItem): #*angle* Angle in degrees to rotate text (note that the rotation assigned in this item's #transformation will be ignored) - + self.anchor = pg.Point(anchor) + #self.angle = 0 UIGraphicsItem.__init__(self) self.textItem = QtGui.QGraphicsTextItem() + self.textItem.setParentItem(self) self.lastTransform = None self._bounds = QtCore.QRectF() if html is None: self.setText(text, color) else: self.setHtml(html) - self.anchor = pg.Point(anchor) self.fill = pg.mkBrush(fill) self.border = pg.mkPen(border) - self.angle = angle - #self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport + self.rotate(angle) + self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport def setText(self, text, color=(200,200,200)): color = pg.mkColor(color) self.textItem.setDefaultTextColor(color) self.textItem.setPlainText(text) + self.updateText() #html = '%s' % (color, text) #self.setHtml(html) @@ -70,38 +72,41 @@ class TextItem(UIGraphicsItem): self.textItem.setFont(*args) self.updateText() - def updateText(self): - self.viewRangeChanged() - - #def getImage(self): - #if self.img is None: - #br = self.textItem.boundingRect() - #img = QtGui.QImage(int(br.width()), int(br.height()), QtGui.QImage.Format_ARGB32) - #p = QtGui.QPainter(img) - #self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) - #p.end() - #self.img = img - #return self.img + #def setAngle(self, angle): + #self.angle = angle + #self.updateText() - def textBoundingRect(self): - ## return the bounds of the text box in device coordinates - pos = self.mapToDevice(QtCore.QPointF(0,0)) - if pos is None: - return None - tbr = self.textItem.boundingRect() - return QtCore.QRectF(pos.x() - tbr.width()*self.anchor.x(), pos.y() - tbr.height()*self.anchor.y(), tbr.width(), tbr.height()) + + def updateText(self): + + ## Needed to maintain font size when rendering to image with increased resolution + self.textItem.resetTransform() + #self.textItem.rotate(self.angle) + if self._exportOpts is not False and 'resolutionScale' in self._exportOpts: + s = self._exportOpts['resolutionScale'] + self.textItem.scale(s, s) + + #br = self.textItem.mapRectToParent(self.textItem.boundingRect()) + self.textItem.setPos(0,0) + br = self.textItem.boundingRect() + apos = self.textItem.mapToParent(pg.Point(br.width()*self.anchor.x(), br.height()*self.anchor.y())) + #print br, apos + self.textItem.setPos(-apos.x(), -apos.y()) + + #def textBoundingRect(self): + ### return the bounds of the text box in device coordinates + #pos = self.mapToDevice(QtCore.QPointF(0,0)) + #if pos is None: + #return None + #tbr = self.textItem.boundingRect() + #return QtCore.QRectF(pos.x() - tbr.width()*self.anchor.x(), pos.y() - tbr.height()*self.anchor.y(), tbr.width(), tbr.height()) def viewRangeChanged(self): - br = self.textBoundingRect() - if br is None: - return - self.prepareGeometryChange() - self._bounds = fn.invertQTransform(self.deviceTransform()).mapRect(br) - #print self._bounds + self.updateText() def boundingRect(self): - return self._bounds + return self.textItem.mapToParent(self.textItem.boundingRect()).boundingRect() def paint(self, p, *args): tr = p.transform() @@ -110,23 +115,9 @@ class TextItem(UIGraphicsItem): self.viewRangeChanged() self.lastTransform = tr - - tbr = self.textBoundingRect() - - #p.setPen(pg.mkPen('r')) - #p.drawRect(self.boundingRect()) - p.setPen(self.border) p.setBrush(self.fill) + p.setRenderHint(p.Antialiasing, True) + p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) - - #p.fillRect(tbr) - p.resetTransform() - #p.drawRect(tbr) - - - p.translate(tbr.left(), tbr.top()) - p.rotate(self.angle) - p.drawRect(QtCore.QRectF(0, 0, tbr.width(), tbr.height())) - self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) \ No newline at end of file