Unsolved rendering text in QOpenGLWidget
-
Hi,
I'm trying to render some text on a QOpenGLWidget using QPainter.
painter->setRenderHint(QPainter::TextAntialiasing);
QPen pen = painter->pen();
pen.setColor(QColor(m_fgc.r, m_fgc.g, m_fgc.b));
painter->setPen(pen);
painter->setFont(QFont(m_font, m_font_size));
painter->drawText(x0, y0, m_w, m_h, Qt::AlignLeft| Qt::AlignVCenter, QString(szlabel));The text gets drawn, but looks corrupted. Is this a bug? Am I doing something wrong? Is there another way of rendering text without QPainter? I'm kind of stuck on a project because of this issue so I'd really appreciate it if someone could offer some help. Thanks!
-
If it may help, here is a small example code that produces the issue.
#include <QApplication> #include <QOpenglWidget> #include <QPainter> class MyOpenGLWidget : public QOpenGLWidget { public: MyOpenGLWidget(){} void initializeGL() { glClearColor(1.f, 1.f, 1.f, 1.f); } void resizeGL(int w, int h) { glViewport(0, 0, w, h); } void paintGL() { glClear(GL_COLOR_BUFFER_BIT); QPainter painter(this); painter.setPen(Qt::black); painter.setFont(QFont("Arial", 16)); painter.drawText(0, 0, width(), height(), Qt::AlignCenter, "Hello World!"); painter.end(); } }; int main(int argc, char **argv) { QApplication app(argc, argv); MyOpenGLWidget wnd; wnd.resize(400, 300); wnd.show(); return app.exec(); }
-
I tried your example and it worked fine. I changed the size of the font from 16 to 56 and didn't see anything that I would consider 'corrupted'.
I am using OSX 10.10 Qt 5.4.0 XCode 7.2
One thing that seems to be missing from your example is the QOpenGLFunctions. From the Qt help file showing an example of the QOpenGLWidget using the QOpenGLFunctions:
class MyGLWidget : public QOpenGLWidget { public: MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } protected: void initializeGL() { // Set up the rendering context, load shaders and other resources, etc.: QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); ... } void resizeGL(int w, int h) { // Update projection matrix and other size related settings: m_projection.setToIdentity(); m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f); ... } void paintGL() { // Draw the scene: QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClear(GL_COLOR_BUFFER_BIT); ... } };
I realize you are using QPainter to draw the text but it is possible it is not using the same rendering context you setup.
Your updated example program:
class MyOpenGLWidget : public QOpenGLWidget { public: MyOpenGLWidget(){} void initializeGL() { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.f, 1.f, 1.f, 1.f); } void resizeGL(int w, int h) { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glViewport(0, 0, w, h); } void paintGL() { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClear(GL_COLOR_BUFFER_BIT); QPainter painter(this); painter.setPen(Qt::black); painter.setFont(QFont("Arial", 56)); painter.drawText(0, 0, width(), height(), Qt::AlignCenter, "Hello World!"); painter.end(); } };
-
Thanks for the reply. Unfortunately, it didn't work. I added the QOpenGLFunctions to the example but the text remains corrupted. (The reason I am not using QOpenGLFunctions is because it does not appear to support glBegin()/glEnd() which I need since I'm porting some old fixed functionality code to Qt). It sounds like it might be an OS issue then (I'm using Windows7).
-
I'm on Windows 10 and there's no issue either. Can you show a screenshot of what "corrupted" means?
Technically when you're mixing QPainter and native GL calls you should put the latter in a painter's begin/end native paint clause. Although clearing the buffer is simple and should just work you might try this:
QPainter painter(this); painter.beginNativePainting(); glClear(GL_COLOR_BUFFER_BIT); painter.endNativePainting(); painter.setPen(Qt::black); painter.setFont(QFont("Arial", 16)); painter.drawText(0, 0, width(), height(), Qt::AlignCenter, "Hello World!");
Btw. a call to
end()
is not needed here. It will be called by the painter's destructor implicitly. -
This post is deleted! -
I had this issue when I needed to draw axis and corresponding ticks. In Qt4, I can use the following code:
for (int i = _Ymin; i <= _Ymax; i = i + _yGrid) { double yPos = (_Ymax-i)*_yscaleF*_yscalingF; double xPos = -_xmin*_xscaleF-_shiftX; if(yPos < (_Ymax-_Ymin)*_yscaleF-_shiftY+1) { glBegin(GL_LINES); glVertex2f(xPos-2, yPos); glVertex2f(xPos+2, yPos); glEnd(); renderText (xPos - offset,yPos+5 , 0, QString::number(i/10.0)); } } glScalef(_xscalingF,_yscalingF,0);
However, when I try to migrate my code to Qt6, there's no renderText anymore. After searching on the web and investigating the source code of renderText, finally I found the solution, one needs to save/load gl status:
glBegin(GL_LINES); glVertex2f(xPos-4, yPos); glVertex2f(xPos+4, yPos); glEnd(); qt_save_gl_state(); renderText(xPos - offset,yPos+5 , QString::number(i/10.0)); qt_restore_gl_state();
Here are the def of qt_save_gl_state, renderText, qt_restore_gl_state:
static void qt_save_gl_state() { glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } static void qt_restore_gl_state() { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } void GLWidgetnew::renderText(double x, double y, const QString text) { GLdouble textPosX = x, textPosY = y; // Retrieve last OpenGL color to use as a font color GLdouble glColor[4]; glGetDoublev(GL_CURRENT_COLOR, glColor); QColor fontColor = QColor(glColor[0]*255, glColor[1]*255, glColor[2]*255, glColor[3]*255); // Render text QPainter painter(this); painter.translate(float(_shiftX),float(_shiftY)); //This is for my own mouse event (scaling) painter.setPen(fontColor); QFont f; f.setPixelSize(10); painter.setFont(f); painter.drawText(textPosX, textPosY, text); painter.end(); }
Note that one might need to adjust the renderText function for some special purposes (e.g., scaling, translation etc)
src code of the project can be found here QtSignalProcessing