Pyside6: click text on QPixMap

Heads up! You've already completed this tutorial.

Axel | 2021-03-21 00:25:14 UTC | #1

Hello, in the new Pyside6 book there is an example on page 414 where a text is created.

python
def draw_something(self):
        painter = QtGui.QPainter(self.canvas)
        pen = QtGui.QPen()
        pen.setWidth(1)
        pen.setColor(QtGui.QColor("green"))
        painter.setPen(pen)
        font = QtGui.QFont()
        font.setFamily("Times")
        font.setPointSize((40))
        painter.setFont(font)
        painter.drawText(50, 100, "Hello World")
        painter.end()
        self.label.setPixmap(self.canvas)

Is it possible to make this text clickable to modify it afterwards? There could potentially be several items draws, but I do not see how to select them.

A hint into the right direction would be highly appreciated


Axel | 2021-03-22 21:17:40 UTC | #2

I guess the moonsweeper example is pointing me into the right direction... :-)


martin | 2021-04-07 14:12:17 UTC | #3

Hi @Axel welcome to the forum, sorry for the delay in getting back to you -- been busy with the PyQt6 edition of the book!

To answer your question, it's a bit tricky as what we're doing in that block of code is drawing text onto a bitmap: we're turning it into pixels in an image. Once the text has been placed, the text object itself doesn't exist. But that doesn't mean it's impossible! Some ideas in case you want to try this out --

How to update text in a bitmap

In my Paint example you can place a text object onto an image and type into it. Once you press enter the text is written to the image, and can't be changed. The way this works is to keep track of the current text and draw it onto the pixmap on each change, removing the previous text each time. You will need some way to remove the previous text -- or end up with changes mashed over one another. There are two ways to do this --

  1. you can take a copy of the background before writing the text, and re-paste it before re-drawing the new value
  2. you can write it using a XOR (exclusive-OR) -- this is a logic operation which when repeated gets you back to the original result. This is what is used in the Paint app -- write the text XOR, then (on change) write the text XOR again, to remove it, write the new text XOR. Once the text is finalised, you need to write the final version normally.

If you stored the text, a QRect of the clickable dimensions & the background you could detect clicks, rewrite the previous background and then write your new text. But it's going to turn into a mess if you draw over the top of the text and then try and edit it.

Redraw the scene

An alternative which will work if you only have a few elements is to store the elements of the image themselves -- effectively as "layers" in the pixmap in a list. These can all then remain editable -- e.g. a text object you could change the text. After any change you just reconstruct the image from a blank pixmap applying the layers based on the stored data.

This will get you a fully editable pixmap, although I'm not sure how it will hold up for more complex images!

Use QGraphicsScene

Qt provides QGraphicsScene which is a vector based graphics view -- objects in there remain live and can be clicked, dragged, edited (rotated, scaled, anything) and the view will update itself automatically. I don't have a tutorial on this yet but will be adding some shortly -- in the meantime, I have an example Solitaire application here which makes use of it.


Over 10,000 developers have bought Create GUI Applications with Python & Qt!

To support developers in [[ countryRegion ]] I give a [[ localizedDiscount[couponCode] ]]% discount with the code [[ couponCode ]] — Enjoy!

For [[ activeDiscount.description ]] I'm giving a [[ activeDiscount.discount ]]% discount with the code [[ couponCode ]] — Enjoy!

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak