[Solved]A class inherited from QGLwidget to display an image (the image can not be displaed)
-
Hello, everyone.
I am trying to write a class inherited from QGLWidget to display an image using openGL with basic pan & zoom etc. functions.
(I have realized one before, but I am trying to write a more clear one.)
Can anyone help me out of the problem?
The following includes all source code. Thank you in advance.
@
#include <QtOpenGL>
class FrameGLWidget : public QGLWidget
{
public:
FrameGLWidget(QWidget *parent);
~FrameGLWidget();
protected:
void initializeGL();
void paintGL();
void resizeGL(int w, int h);public:
void loadImage(QImage &img);
void loadImage(const QString &filename);void setBackgroundColor(QColor color);
private:
void showImage();
void showTitlePage();private:
QColor bg_color; //background color
float XPan_Ratio,YPan_Ratio,Zoom_Ratio;
int width_img,height_img; //image sizebool bImageConnected; bool bGridEnabled; bool bTextureCreated; GLuint texture;
};
@
@
#include "FrameGLWidget.h"
FrameGLWidget::FrameGLWidget(QWidget *parent) :
QGLWidget(parent)
{
setWindowTitle(tr("FrameGLWidget"));
bImageConnected=false;
bTextureCreated=false;
bGridEnabled=false;XPan_Ratio=0.0f; YPan_Ratio=0.0f; Zoom_Ratio=1.0f;
}
FrameGLWidget::~FrameGLWidget()
{
if(bTextureCreated)
glDeleteTextures(1,&texture);
}void FrameGLWidget::initializeGL()
{
glDisable(GL_DEPTH_TEST); //disable for 2D painting
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}void FrameGLWidget::resizeGL(int w, int h)
{
glViewport(0,0,w,h);
}void FrameGLWidget::paintGL()
{
qglClearColor(bg_color);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//set the window background color
if(!bImageConnected)
showTitlePage();
else
showImage();
}void FrameGLWidget::showImage()
{
float ox,oy;
float x1,y1,x2,y2,x3,y3,x4,y4;
float rw,rh;//rw=w_h_ratio_image/w_h_ratio_window; rw=1.0f;rh=1.0f; ox=XPan_Ratio*(1.0+Zoom_Ratio*rw); oy=YPan_Ratio*(1.0+Zoom_Ratio*rh); x1=ox-Zoom_Ratio*rw; y1=oy-Zoom_Ratio*rh; x2=ox+Zoom_Ratio*rw; y2=oy-Zoom_Ratio*rh; x3=ox+Zoom_Ratio*rw; y3=oy+Zoom_Ratio*rh; x4=ox-Zoom_Ratio*rw; y4=oy+Zoom_Ratio*rh; y3=0.0;y4=0.0; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0,0,this->width(),this->height()); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBegin( GL_QUADS ); glTexCoord2d(0.0,0.0); glVertex2d(x1,y1); glTexCoord2d(1.0,0.0); glVertex2d(x2,y2); glTexCoord2d(1.0,1.0); glVertex2d(x3,y3); glTexCoord2d(0.0,1.0); glVertex2d(x4,y4); glEnd(); glDrawBuffer(GL_BACK);
}
void FrameGLWidget::loadImage(QImage &img)
{
width_img=img.width();
height_img=img.height();/* Create texture object */ if(!bTextureCreated) { glGenTextures(1, &texture); bTextureCreated=true; } /* Now upload pixels */ if(img.format()!=QImage::Format_RGB32) img=img.convertToFormat(QImage::Format_RGB32); qDebug()<<"Color count:"<<img.colorCount(); qDebug()<<"Depth:"<<img.depth(); qDebug()<<"Format"<<img.format(); qDebug()<<"Has Alpha channel:"<<img.hasAlphaChannel(); QImage tex_image; tex_image = QGLWidget::convertToGLFormat(img); //make sure its not null if(tex_image.isNull()) { QMessageBox::warning(this, tr("Error"), tr("failed to transform image to opengl format.")); return ; } glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_image.width(), tex_image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, tex_image.bits()); bImageConnected=true; // Update scene updateGL(); return;
}
void FrameGLWidget::loadImage(const QString &filename)
{
QImage img;
img.load(filename);
if(img.isNull())
{
QMessageBox::warning(this, tr("Error"),
tr("Can not open specified file <%1>").arg(filename),
QMessageBox::Ok);
return;
}
else
{
loadImage(img);
return ;
}
}void FrameGLWidget::setBackgroundColor(QColor color)
{
bg_color=color;
}void FrameGLWidget::showTitlePage()
{
QFont serifFont("Times", 30, QFont::Bold);
setFont(serifFont);
QString text=tr("NO IMAGE");
QFontMetrics metrics = QFontMetrics(font());
int border = qMax(4, metrics.leading());
QRect rect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125),
Qt::AlignCenter | Qt::TextWordWrap, text);
renderText((width() - rect.width())/2,(height()-rect.height())/2,text);
}@
@
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
#include "FrameGLWidget.h"int main(int argc, char **argv)
{
QApplication app(argc, argv);
if (!QGLFormat::hasOpenGL() || !QGLFramebufferObject::hasOpenGLFramebufferObjects()) {
QMessageBox::information(0, "Warning",
"This system does not support OpenGL/framebuffer objects.");
return -1;
}FrameGLWidget frameGL(0); frameGL.resize(640, 480); frameGL.setBackgroundColor(Qt::darkGreen); frameGL.loadImage("test.jpg"); frameGL.show(); return app.exec();
}
@ -
Well, I think you want to debug this a bit first, and find out where the problem is before posting...
Just a stab in the dark, but maybe double-check
@glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ...@
since my code has
@glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ...@ -
I have solved the problem.
In the main program, I try to load the image file and construct texture before QGLwidget window shows. In fact , the opengl context will not be constructed until the QGLwidget shows is called (and then initializeGL is called). I just change the order
from
@
frameGL.loadImage("test.jpg");
frameGL.show();
@to
@
frameGL.show();
frameGL.loadImage("test.jpg");
@And then it works fine.
-
It's strange. I use your code without modification and it shows the image only in the lower half part of the window.
I mean, the jpg image's height is halved (its width is unmodified) and the image is drawn starting from the position (0, height/2).
Do you see an explanation ?