def _init_images(self): A, = 'A'.encode('ascii') gs = Qt.QGraphicsScene() sti = Qt.QGraphicsSimpleTextItem() sti.setFont(Qt.QFont('Courier', pointSize=24, weight=Qt.QFont.Bold)) gs.addItem(sti) self.images = [] for char in range(A, A + 26): for i in range(0, 10): text = bytes([char]).decode('ascii') + str(i) sti.setText(text) scene_rect_f = gs.itemsBoundingRect() scene_rect = Qt.QRect( 0, 0, math.ceil(scene_rect_f.width()), math.ceil(scene_rect_f.height())) gs.setSceneRect(scene_rect_f) buffer = numpy.empty((scene_rect.height(), scene_rect.width(), 4), dtype=numpy.uint8) buffer[:] = 255 qimage = Qt.QImage(sip.voidptr(buffer.ctypes.data), scene_rect.size().width(), scene_rect.size().height(), Qt.QImage.Format_RGBA8888) qpainter = Qt.QPainter() qpainter.begin(qimage) qpainter.setRenderHint(Qt.QPainter.Antialiasing) qpainter.setRenderHint(Qt.QPainter.HighQualityAntialiasing) gs.render(qpainter) qpainter.end() self.images.append(Image(buffer.copy(), shape_is_width_height=False, name=text))
def _update_picture(self): if self._picture is None: self._picture = Qt.QPicture() ppainter = Qt.QPainter() with ExitStack() as stack: ppainter.begin(self._picture) stack.callback(ppainter.end) # The Qt API calls required for formatting multiline text such that it can be rendered to # a path are private, as can be seen in the implementation of # QGraphicsSimpleTextItem::paint, pasted below. (Specifically, QStackTextEngine is a private # component and thus not available through PyQt). # # void QGraphicsSimpleTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) # { # Q_UNUSED(widget); # Q_D(QGraphicsSimpleTextItem); # # painter->setFont(d->font); # # QString tmp = d->text; # tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); # QStackTextEngine engine(tmp, d->font); # QTextLayout layout(&engine); # # QPen p; # p.setBrush(d->brush); # painter->setPen(p); # if (d->pen.style() == Qt::NoPen && d->brush.style() == Qt::SolidPattern) { # painter->setBrush(Qt::NoBrush); # } else { # QTextLayout::FormatRange range; # range.start = 0; # range.length = layout.text().length(); # range.format.setTextOutline(d->pen); # QList<QTextLayout::FormatRange> formats; # formats.append(range); # layout.setAdditionalFormats(formats); # } # # setupTextLayout(&layout); # layout.draw(painter, QPointF(0, 0)); # # if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus)) # qt_graphicsItem_highlightSelected(this, painter, option); # } # # We would just use QGraphicsSimpleTextItem directly, but it is not derived from QGraphicsObject, so # it lacks the QObject base class required for emitting signals. It is not possible to add a QObject # base to a QGraphicsItem derivative in Python (it can be done in C++ - this is how QGraphicsObject # is implemented). # # Total lack of signal support is not acceptable; it would greatly complicate the task of # positioning a non-child item relative to a ContextualInfoItem. # # However, it's pretty easy to use that very paint function to generate paint commands that # we cache in self._picture, so we do that. For strings large enough that the relayout # performed on each refresh by QGraphicsSimpleTextItem exceeds the CPython interpreter overhead # for initiating the QPicture replay, our paint function is faster. # # Additionally, QGraphicsTextItem is very featureful, has a QObject base, and would be the first # choice, but the one thing it can not do is outline text, so it's out. i = Qt.QGraphicsSimpleTextItem(self.contextual_info.value) i.setFont(self._font) # Disabling brush/pen via setBrush/Pen(Qt.QBrush/Pen(Qt.Qt.NoBrush/Pen)) ought to be more intelligent # than disablind via setting to transparent color. However, using NoBrush or NoPen here seems to # cause extreme painting slowdowns on OS X. transparent_color = Qt.QColor(Qt.Qt.transparent) if self._pen is None or self._brush is None: i.setPen(Qt.QPen(transparent_color) if self._pen is None else self._pen) i.setBrush(Qt.QBrush(transparent_color) if self._brush is None else self._brush) i.paint(ppainter, Qt.QStyleOptionGraphicsItem(), None) else: # To ensure that character outlines never obscure the entirety of character interior, outline # is drawn first and interior second. If both brush and pen are nonempty, Qt draws interior first # and outline second. i.setBrush(Qt.QBrush(transparent_color)) i.setPen(self._pen) i.paint(ppainter, Qt.QStyleOptionGraphicsItem(), None) i.setBrush(self._brush) i.setPen(Qt.QPen(transparent_color)) i.paint(ppainter, Qt.QStyleOptionGraphicsItem(), None) self._bounding_rect = i.boundingRect()