Green Cell
Green Cell

Reputation: 4777

QGraphicsPathItem different colors

Is there a way to get 2 different fill colors for a single QGraphicsPathItem object?

For example:

    # Try to get a white text onto a grey rectangle
    itemPath = QtGui.QPainterPath()
    itemPath.setFillRule(QtCore.Qt.WindingFill)

    self.setBrush( QtGui.QColor(100, 100, 100) )
    itemPath.addRect(-10, -60, 150, 70)
    itemFont = QtGui.QFont()
    itemFont.setPointSize(50)
    self.setBrush( QtGui.QColor(255, 255, 255) )
    itemPath.addText(0, 0, itemFont, txt)

Right now it's just using the last brush color for the rectangle and text. I'd like to color them differently though, but still as the same QGraphicsPathItem. Or better yet, a way to give the text a background so it's easier to select.

Update

Here's an example. I want a white text with a red background, but I only get the last used brush color.

from PySide import QtGui, QtCore

class TextItem(QtGui.QGraphicsPathItem):
    def __init__(self):
        super(TextItem, self).__init__()

        itemPath = QtGui.QPainterPath()
        itemPath.setFillRule(QtCore.Qt.WindingFill)

        # Create rectangle with red color
        self.setBrush( QtGui.QColor(255, 0, 0) )
        itemPath.addRect(-10, -50, 130, 60)
        self.setPath(itemPath)

        # Create text with white color
        itemFont = QtGui.QFont()
        itemFont.setPointSize(40)
        self.setBrush( QtGui.QColor(255, 255, 255) )
        itemPath.addText(0, 0, itemFont, 'Test!')
        self.setPath(itemPath)

        self.moveBy(100, 100)

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.resize(500, 500)
        self.view = QtGui.QGraphicsView(self)
        self.view.setScene( QtGui.QGraphicsScene(self) )
        self.view.setSceneRect( 0, 0, 500, 500 )
        self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)        

        mainLayout = QtGui.QVBoxLayout()
        mainLayout.addWidget(self.view)
        self.setLayout(mainLayout)

        newItem = TextItem()
        self.view.scene().addItem( newItem )

    def run(self):
        self.show()

win = Window()
win.show()

Upvotes: 0

Views: 1594

Answers (1)

strubbly
strubbly

Reputation: 3477

The problem is that your first self.setPath and self.setBrush calls are just over-ridden by the second ones. These properties of the QGraphicsPathItem are not used until you get to the paint event. So the first settings do nothing and the values left in these properties after the initialisation are the ones used to paint the item.

It's not too difficult to do what you want but you have quite a lot of options, and you need to choose based on other aspects of your design.

The simplest option would be to just create a QGraphicsRectItem and then give it a QGraphicsSimpleTextItem child. This is particularly simple in that you wouldn't even need to create a subclass of your own: simply create the instances, set their Paths and Brushes and use them directly. I strongly recommend this approach if it does what you neeed.

    rectItem = QtGui.QGraphicsRectItem(0, 0, 130, 60)
    rectItem.setBrush(QtGui.QColor(255, 0, 0))

    textItem = QtGui.QGraphicsSimpleTextItem("Test!",rectItem)

    itemFont = QtGui.QFont()
    itemFont.setPointSize(40)
    textItem.setBrush( QtGui.QColor(200, 200, 200) )
    textItem.setFont(itemFont)
    textItem.setPos(10,0)

    self.view.scene().addItem( rectItem )

    rectItem.moveBy(100,100)

Another simple option would be just create the two items and then add them into a QGraphicsItemGroup. This makes sense if you might want to separate the items or work with them separately.

    rectItem = QtGui.QGraphicsRectItem(0, 0, 130, 60)
    rectItem.setBrush(QtGui.QColor(255, 0, 0))
    self.view.scene().addItem( rectItem )
    textItem = QtGui.QGraphicsSimpleTextItem("Test!")
    itemFont = QtGui.QFont()
    itemFont.setPointSize(40)
    textItem.setBrush( QtGui.QColor(200, 200, 200) )
    textItem.setFont(itemFont)
    textItem.setPos(10,0)
    self.view.scene().addItem( textItem )
    group = QtGui.QGraphicsItemGroup()
    group.addToGroup(rectItem)
    group.addToGroup(textItem)
    group.moveBy(100,100)
    self.view.scene().addItem( group )

If you need to create a class of your own for other reasons then you have quite a few options. The most general will be to subclass QGraphicsItem. You can create a MyTextItem with, for example, two Paths and two Brushes, and use them both when you paint the Item. You will have to implement boundingRect and paint but in this case both will be quite easy. This is probably a good way to go if you foresee adding lots of additional functionality to the item.

Other options would be to subclass QRectItem and add a text path to it. Again you will need to re-implement paint, but that might be all that was needed. Or you could subclass QSimpleTextItem and add a rect to it.

Upvotes: 1

Related Questions