psadhukhan
25th November 2008, 08:04
Hi,
I am a newbie to Qt world. We have a product which follows Java AWT model (which is multithread enabled in that from any Java thread, the AWT libs will try to make GUI calls) and was working in Qt3 but it seems that the new Qt4 model is single threaded and wants all GUI calls to be only made from the main thread [the thread that calls exec()] as the tutorial seems to imply
Note that QCoreApplication::exec() must always be called from the main thread (the thread that executes main()), not from a QThread. In GUI applications, the main thread is also called the GUI thread because it's the only thread that is allowed to perform GUI-related operations.
Also, there is one more change in Qt4 w.r.t Qt3
When implementing custom widgets in Qt 3, it was possible to use QPainter to draw on a widget outside paint events
In Qt 4, it is only possible to paint on a widget from within its paintEvent() handler function. This restriction simplifies Qt's interaction with native window systems, improves the performance of applications by reducing the number of redraw operations, and also enables features to be implemented to improve the appearance of widgets, such as a backing store. Generally, we recommend redesigning applications to perform all painting operations in paintEvent() functions, deferring actual painting until the next time this function is called. Applications can post paint events to trigger repaints, and it may be possible to examine your widget's internal state to determine which part of the widget needs to be repainted
so, in Qt3, we did not have any paintEvent() method and whenever AWT lib calls any GUI related function like drawLine, drawRect, drawFont, drawImage it used to draw the shapes in the Qt window. One such example:
AWT_drawLine(int x1, int y1, int x2, int y2)
{
AWT_QT_LOCK; {
QPainter p(QtImageDescPool[QtGraphDescPool[qtGraphDesc].qid].qpd);
#ifdef QT_VER_4
p.setCompositionMode(QtGraphDescPool[qtGraphDesc].rasterOp);
#else
p.setRasterOp(QtGraphDescPool[qtGraphDesc].rasterOp);
#endif
p.setPen(*((QPen *)(QtGraphDescPool[qtGraphDesc].qp)));
setPainterClip(&p, qtGraphDesc);
p.drawLine(x1, y1, x2, y2);
printf("DrawLine called\n");
if(maskPainter(qtGraphDesc, p))
p.drawLine(x1, y1, x2, y2);
}
AWT_QT_UNLOCK;
}
In Qt3 [when QT_VER_4] was not defined, it used to work as paintEvent was not needed. But, I guess in Qt4, this way of execution will not display anything. I have created a native application which does the drawing in paintEvent() and the application work provided paintEvent is present. But, it's difficult to satisfy our AWT model if we have to draw in paintEvent()
I was thinking of the thread that executes exec() to draw all the GUI operations on offscreen surface[back buffer] and in paintEvent, periodically display the back buffer into the Qt screen.
Will that be a good way of doing it in Qt4? If not, can you please suggest some way?
If yes, can you please tell me how to create an offscreen [back buffer] [will that be a Qwidget] and how can we flush the back buffer into Qt screen?
Can you please tell me how can I modify the attached application so that drawline() function will draw the line in back buffer and paintEvent will take the back-buffer and flush on the Qt screen?
Thanks in advance.
Regards
Prasanta
The native application:
#include <Qt>
#include <QtCore>
#include <QtGui>
#include <QPainter>
#include <QWidget>
class QPen;
class QBrush;
#define qtApp ((QtApplication *)qApp)
void drawline(QPaintDevice *qpd);
class QtWindow : public QWidget
{
QBitmap transMask;
public:
QtWindow(int flags,
const char *name = "Sun AWT/Qt",
QWidget *parent = NULL) ;
virtual void paintEvent(QPaintEvent *);
};
class QtApplication : public QApplication {
public :
QtApplication(int &argc, char **argv);
int exec(); //overloadded exec from QApplication
};
QtApplication::QtApplication(int &argc, char **argv) : QApplication(argc, argv) {
}
int
QtApplication::exec(void) {
printf("QApplication exec called\n");
QApplication::exec();
printf("QApplication exec done\n");
}
QtWindow::QtWindow(int flags, const char *name, QWidget *parent) :
QWidget(parent, (Qt::WindowFlags)flags)
{
setMouseTracking(true);
}
void
QtWindow::paintEvent(QPaintEvent *event)
{
#if 0
printf("paintEvent called\n");
QPen *qp = new QPen();
QBrush *qb = new QBrush();
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Sou rceOver);
p.setPen(*qp);
p.setClipRect(0,0,800,600);
p.drawLine(30,135,790,135);
#endif
}
int main(int argc, char **argv)
{
printf("argc %d, argv %s\n",argc, *argv);
int m_x = 0,m_y=0,m_width=800,m_height=600;
new QtApplication(argc, argv);
QtWindow *m_window = new QtWindow(Qt::FramelessWindowHint|Qt::Window);
QBitmap bitmap(m_width, m_height);
qtApp->setActiveWindow(m_window);
QPaintDevice *qpd = m_window;
#if 1
drawline(qpd);
#endif
printf("exec called\n");
m_window->show();
qtApp->exec();
}
void
drawline(QPaintDevice *qpd)
{
QPen *qp = new QPen();
QBrush *qb = new QBrush();
QPainter p(qpd);
p.setCompositionMode(QPainter::CompositionMode_Sou rceOver);
p.setPen(*qp);
p.setClipRect(0,0,800,600);
p.drawLine(30,135,790,135);
}
I am a newbie to Qt world. We have a product which follows Java AWT model (which is multithread enabled in that from any Java thread, the AWT libs will try to make GUI calls) and was working in Qt3 but it seems that the new Qt4 model is single threaded and wants all GUI calls to be only made from the main thread [the thread that calls exec()] as the tutorial seems to imply
Note that QCoreApplication::exec() must always be called from the main thread (the thread that executes main()), not from a QThread. In GUI applications, the main thread is also called the GUI thread because it's the only thread that is allowed to perform GUI-related operations.
Also, there is one more change in Qt4 w.r.t Qt3
When implementing custom widgets in Qt 3, it was possible to use QPainter to draw on a widget outside paint events
In Qt 4, it is only possible to paint on a widget from within its paintEvent() handler function. This restriction simplifies Qt's interaction with native window systems, improves the performance of applications by reducing the number of redraw operations, and also enables features to be implemented to improve the appearance of widgets, such as a backing store. Generally, we recommend redesigning applications to perform all painting operations in paintEvent() functions, deferring actual painting until the next time this function is called. Applications can post paint events to trigger repaints, and it may be possible to examine your widget's internal state to determine which part of the widget needs to be repainted
so, in Qt3, we did not have any paintEvent() method and whenever AWT lib calls any GUI related function like drawLine, drawRect, drawFont, drawImage it used to draw the shapes in the Qt window. One such example:
AWT_drawLine(int x1, int y1, int x2, int y2)
{
AWT_QT_LOCK; {
QPainter p(QtImageDescPool[QtGraphDescPool[qtGraphDesc].qid].qpd);
#ifdef QT_VER_4
p.setCompositionMode(QtGraphDescPool[qtGraphDesc].rasterOp);
#else
p.setRasterOp(QtGraphDescPool[qtGraphDesc].rasterOp);
#endif
p.setPen(*((QPen *)(QtGraphDescPool[qtGraphDesc].qp)));
setPainterClip(&p, qtGraphDesc);
p.drawLine(x1, y1, x2, y2);
printf("DrawLine called\n");
if(maskPainter(qtGraphDesc, p))
p.drawLine(x1, y1, x2, y2);
}
AWT_QT_UNLOCK;
}
In Qt3 [when QT_VER_4] was not defined, it used to work as paintEvent was not needed. But, I guess in Qt4, this way of execution will not display anything. I have created a native application which does the drawing in paintEvent() and the application work provided paintEvent is present. But, it's difficult to satisfy our AWT model if we have to draw in paintEvent()
I was thinking of the thread that executes exec() to draw all the GUI operations on offscreen surface[back buffer] and in paintEvent, periodically display the back buffer into the Qt screen.
Will that be a good way of doing it in Qt4? If not, can you please suggest some way?
If yes, can you please tell me how to create an offscreen [back buffer] [will that be a Qwidget] and how can we flush the back buffer into Qt screen?
Can you please tell me how can I modify the attached application so that drawline() function will draw the line in back buffer and paintEvent will take the back-buffer and flush on the Qt screen?
Thanks in advance.
Regards
Prasanta
The native application:
#include <Qt>
#include <QtCore>
#include <QtGui>
#include <QPainter>
#include <QWidget>
class QPen;
class QBrush;
#define qtApp ((QtApplication *)qApp)
void drawline(QPaintDevice *qpd);
class QtWindow : public QWidget
{
QBitmap transMask;
public:
QtWindow(int flags,
const char *name = "Sun AWT/Qt",
QWidget *parent = NULL) ;
virtual void paintEvent(QPaintEvent *);
};
class QtApplication : public QApplication {
public :
QtApplication(int &argc, char **argv);
int exec(); //overloadded exec from QApplication
};
QtApplication::QtApplication(int &argc, char **argv) : QApplication(argc, argv) {
}
int
QtApplication::exec(void) {
printf("QApplication exec called\n");
QApplication::exec();
printf("QApplication exec done\n");
}
QtWindow::QtWindow(int flags, const char *name, QWidget *parent) :
QWidget(parent, (Qt::WindowFlags)flags)
{
setMouseTracking(true);
}
void
QtWindow::paintEvent(QPaintEvent *event)
{
#if 0
printf("paintEvent called\n");
QPen *qp = new QPen();
QBrush *qb = new QBrush();
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Sou rceOver);
p.setPen(*qp);
p.setClipRect(0,0,800,600);
p.drawLine(30,135,790,135);
#endif
}
int main(int argc, char **argv)
{
printf("argc %d, argv %s\n",argc, *argv);
int m_x = 0,m_y=0,m_width=800,m_height=600;
new QtApplication(argc, argv);
QtWindow *m_window = new QtWindow(Qt::FramelessWindowHint|Qt::Window);
QBitmap bitmap(m_width, m_height);
qtApp->setActiveWindow(m_window);
QPaintDevice *qpd = m_window;
#if 1
drawline(qpd);
#endif
printf("exec called\n");
m_window->show();
qtApp->exec();
}
void
drawline(QPaintDevice *qpd)
{
QPen *qp = new QPen();
QBrush *qb = new QBrush();
QPainter p(qpd);
p.setCompositionMode(QPainter::CompositionMode_Sou rceOver);
p.setPen(*qp);
p.setClipRect(0,0,800,600);
p.drawLine(30,135,790,135);
}