How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Hi guys,
I would like to render text to a QPixmap and then draw the QPixmap to a QGLWidget that will be presented on screen. The reason I want to render text to the QPixmap is so that I can set the background color of the box bounding the text to be something different than the background already on the QGLWidget. Here is the code I have so far, with client being the QGLWidget and self._image being the QPixmap.
Code:
def show(self, client, x_pos, y_pos, width, height):
glEnable(GL_TEXTURE_2D)
tex_id = client.bindTexture(self._image)
self._painter.begin(self._image)
self._painter.fillRect(self._image.rect(), self._background_color)
self._painter.setPen(self._text_color)
self._painter.setFont(self._font)
self._painter.drawText(self._rect, QtCore.Qt.TextExpandTabs | QtCore.Qt.TextSingleLine | \
QtCore.Qt.AlignLeft, self._text)
self._painter.end()
glTranslate(x_pos/width, y_pos/height, 0)
width_norm = self.width()/width
height_norm = self.height()/height
glBegin(GL_QUADS)
glTexCoord(0.0, 0.0); glVertex(-width_norm, height_norm, 0.0)
glTexCoord(1.0, 0.0); glVertex(width_norm, height_norm, 0.0)
glTexCoord(1.0, 1.0); glVertex(width_norm, -height_norm, 0.0)
glTexCoord(0.0, 1.0); glVertex(-width_norm, -height_norm, 0.0)
glEnd()
glTranslate(-x_pos/width, -y_pos/height, 0)
client.deleteTexture(tex_id)
glDisable(GL_TEXTURE_2D)
show is called as part of QGLWidget paintEvent.
All I get with this is painting unallocated memory within the extent of what should be the text, using the current OpenGL drawing color.
Any suggestions?
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
I figured out to abandon the intervening QPixmap and use QPainter::fillRect before drawing the text. I've also got text working with the following code. Note that the class is now descended from QPainter.
Code:
def draw(self, client, x_pos, y_pos):
self.begin(client)
area = client.rect()
self.setFont(self._font)
self.setPen(self._text_color)
self.setBrush(QtCore.Qt.NoBrush)
self._rect.
moveCenter(QtCore.
QPoint(x_pos
+area.
width()/2, y_pos
+area.
height()/2)) self.fillRect(self._rect, self._background_color)
self.drawText(self._rect, QtCore.Qt.TextExpandTabs, self._text)
self.end()
Now however whenever I draw to the client, the painter object redraws the entire client space with a white background. How do I only draw that portion of the client that is indicated by the self._rect object?
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
QPainter::rect() returns the entire widget rectangle. Besides, for QGLWidget always the whole widget is redrawn.
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
client is a QGLWidget, not a QPainter.
Are you saying it is impossible to perform several such operations consecutively on a QGLWidget without the QGLWidget being entirely redrawn? For example, if i wish to call draw() two times between calls to paintGL so that there are two text objects on the QGLWidget object, then the second text object will overwrite the first?
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Quote:
Originally Posted by
MasterMuddler
Yet you are calling QPainter's rect:
Code:
self.fillRect(self._rect, self._background_color)
Quote:
Are you saying it is impossible to perform several such operations consecutively on a
QGLWidget without the
QGLWidget being entirely redrawn? For example, if i wish to call draw() two times between calls to paintGL so that there are two text objects on the
QGLWidget object, then the second text object will overwrite the first?
First of all you can't draw on the widget when the GL context is not active so unless you make it active yourself, you can only draw during paintGL(). Second of all each paintGL() causes the whole QGLWidget to be rerendered. That's all I'm saying, I don't know if it clears your doubts or not.
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
First off thanks for your help.
The object that draw() is a member of is stored in a list that is iterated through whenever paintGL is called. So if there are two objects derived from QPainter in the list, then draw() will be called on each of them in paintGL, and after makeCurrent() has been called on the QGLWidget being drawn to. The problem that occurs is that first the black background of the QGLWidget is replaced with a white background after calling fillRect and drawText the first time, and the text generated from this first call to draw() is replaced when draw() is called again.
Is there any way to prevent all of the area of QGLWidget outside the area drawn to by fillRect and drawText to not be touched, or to be drawn transparently? I don't want the background to be drawn white at any time. I just want the text objects to be able to accumulate on the black background.
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Quote:
Originally Posted by
MasterMuddler
So if there are two objects derived from
QPainter in the list,
I have to admit the concept of deriving something from QPainter seems very odd to me. What is the point of doing that?
Quote:
Is there any way to prevent all of the area of
QGLWidget outside the area drawn to by fillRect and drawText to not be touched, or to be drawn transparently?
But you are drawing on the whole area of the widget! You are calling fillRect() on the painter's rect which holds the widget's rect. There is no "outside" here.
Quote:
I don't want the background to be drawn white at any time. I just want the text objects to be able to accumulate on the black background.
If you don't want something to be drawn then don't draw it. I don't understand what your problem is. I think the real problem is that you incorrectly assume what QPainter is if you derive your own classes from it and this causes an effect different from what you expect.
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Quote:
You are calling fillRect() on the painter's rect which holds the widget's rect. There is no "outside" here.
self._rect is not the entire area of the QPainter. It's just a subsection and this works corrctly. The problem is that everything else was drawn white.
However I did not realize that calling QPainter::begin made the entire client area subject to the painter. Is there a method of QGLWidget to return a subsection of its client area as something that can be passed to QPainter?
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Quote:
Originally Posted by
MasterMuddler
However I did not realize that calling
QPainter::begin made the entire client area subject to the painter. Is there a method of QGLWidget to return a subsection of its client area as something that can be passed to QPainter?
QPainter works on a QPaintDevice. QGLWidget is a QPaintDevice. "Subsection of QGLWidget" is not a QPaintDevice.
How does your complete paintGL() implementation look like and why are you subclassing QPainter? Doesn't the white colour come from setting the OpenGL fill colour to white?
2 Attachment(s)
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
I'm subclassing QPainter because the object that draw is a part of is an object that paints, for example, only text.
Here is what the widget looks like after the first call to draw():
Attachment 5916
Here is what the widget looks like after the second call to draw():
Attachment 5917
The second image should contain both text objects.
If I set glColor to be black before drawing, I still get the white background. glClearColor is set to black as well.
Re: How to draw text to a QPixmap and then draw the pixmap to a QGLWidget? (PyQt4)
Quote:
Originally Posted by
MasterMuddler
I'm subclassing QPainter because the object that draw is a part of is an object that paints, for example, only text.
This doesn't justify inheriting QPainter. Imagine QPainter is a tool box with different tools inside like hammers, screwdrivers and such. If you want to build a fence, you don't say that your fence is a special kind of tool box but rather you use tools available in the tool box to create the fence. You can also combine tools you have to do work of other (custom) tools. The tool box itself is not modified in any way here.