PDA

View Full Version : in porting Qt3 to Qt4, problem with bitBlt



impeteperry
17th June 2006, 19:24
Hi, I am trying to rewrite a Qt3 progrom in Ot4. and I am having a problem with my resizeEvent function. In Qt3 I have
void edpForm::resizeEvent( QResizeEvent* event )
{
QPixmap save( baseBuffer );
baseBuffer = QPixmap( event->size() );
baseBuffer.fill( QColor( 240, 240, 255 ) );
bitBlt ( &baseBuffer, 0, 0, &save );
}
and now I get a "bitBlt" not declared in this scope. Going to the Qt3 to Qt4 documentation I find.

To reimplement painter backends one previously needed to reimplement the virtual function QPaintDevice::cmd(). This function is taken out and should is replaced with the function QPaintDevice::paintEngine() and the abstract class QPaintEngine. QPaintEngine provides virtual functions for all drawing operations that can be performed on a painter backend.

bitBlt() and copyBlt() are now only compatibility functions. Use QPainter::drawPixmap() instead.
It is possible I have missed somthing in a header file someplace to cause the error message and not the change from Qt3 to Qt4. If the latter is the case some help on the proper way to handle a resize event would be appreciated.

This is a graphic program which uses the buffer/bitBlt a great deal.

Thanks.

jacek
17th June 2006, 20:39
I guess you can write your own bitBlt (not tested):
void bitBlt( QPixmap& dst, int x, int y, const QPixmap& src )
{
QPainter p( &dst );
p.drawPixmap( x, y, src );
}

impeteperry
17th June 2006, 22:46
Thanks for info, But I'm not looking for a "work around".O'Reilly in his "Programming with QT" spent a lot of time on "buffers, paintEvents, resizeEvents, mouseEvents etc." all of which had an organized structure to them.
I use buffers for different layers in a drawing and use the "bitBlt" function to save and/or display a layer that is stored in a particular buffer.

One of my questions was "Have they changed the procedures in Qt4 or have I screwed up. If they have changed it, I could not find documentation on it.

I am still learning Qt programming.

Thanks for your tip, I understasd it.

jacek
17th June 2006, 23:08
One of my questions was "Have they changed the procedures in Qt4 or have I screwed up. If they have changed it, I could not find documentation on it.
I haven't read that book, so I'm not sure what is the purpose of those buffers, but now in Qt4 all widgets are double-buffered, so you don't need a buffer to avoid flicker. You might still need those buffers, if your painting routines are complex.

As for bitBlt() --- there is no such method in Qt4, so if you want to paint one pixmap over another you have to use QPainter.

impeteperry
18th June 2006, 00:39
Thanks , you answared my question. Now I have to figure out what to do.

impeteperry
20th June 2006, 21:10
Thanks
There is somthing simple I'm missing.

I want to draw a line ( xs, ys, xe, ye ) on a QFrame.

In Qt3 i had
QPainter p( drawings ); /// set drawing pixmap
and
p.drawLine( xs, ys, xe, ye );
In Qt4 with the same code I get A SIGABRT abort message.
I have writen small program to try to work things.out.
I used designer for the layout /home/pete/DF-Tutorial/pgn35 (hope you get this ).
my header code
#ifndef EDPFORM_H
#define EDPFORM_H

#include <QtGui>
#include <qrect.h>

#include "ui_edpform.h"
class edpForm: public QMainWindow
{
Q_OBJECT
public:
edpForm();
public slots:
protected:
void paintEvent(QPaintEvent *event);
protected slots:
private:
Ui::edpForm ui;
private slots:
void slotPb1();
void slotPb2();
signals:
void fk1clicked();
void fk2clicked();
};
#endif
and the cpp file
#include "edpform.h"
#include <qpainter.h>
#include <qpixmap.h>
edpForm::edpForm()
{
ui.setupUi(this);
connect( ui.pb3, SIGNAL( clicked() ), this, SLOT( close() ) );
connect( ui.pb1, SIGNAL( clicked() ), this, SLOT( slotPb1() ) );
connect( ui.pb2, SIGNAL( clicked() ), this, SLOT( slotPb2() ) );
ui.input->setFocus();
}
void edpForm::slotPb1()
{
int width = ui.drawingBox->width();
int height = ui.drawingBox->height();
QPainter p( ui.drawingBox );
p.drawLine( 0, 0, width, height );
}
void edpForm::slotPb2()
{
ui.input->clear();
}
void edpForm::paintEvent(QPaintEvent *event)
{
QPrinter printer;

ui.input->setText(" Test" ); /// when displayed show "paintEvent" has been accesed.
} This compiles ok, but when run I get "widget painting begins as a result of paintEvent".

Right now I don't what I'm missing.When I start the program, it goes to the paintEvent because I get the "WoW" is the "input" box.
I know I missing somthing simple, but I'm about brain dead over this.

Thanks for the help.

munna
21st June 2006, 06:00
Why are you declaring QPrinter in the paintEvent ? You are not using it anywhere.

The only major difference between Qt3 and Qt4 relating to this is that you cannot draw anything outside the paintEvent in Qt 4 whereas it was possible in Qt3. If you want to draw something outside the paintEvent in Qt4 then you will need to set the appropriate flags before doing this.

From Qt docs:


Warning: Unless a widget has the Qt::WA_PaintOutsidePaintEvent attribute set. A QPainter can only be used on a widget inside a paintEvent() or a function called by a paintEvent(). On Mac OS X, you can only paint on a widget in a paintEvent() regardless of this attribute's setting.

Also, can we see the Qt 3 code which is working fine and the Qt 4 code which is giving the error.

impeteperry
21st June 2006, 14:42
thanks munn, but I am still in the learning phase and I want to do things the Qt4 way which is the reason for rewriting the program.

I understand what triggers a mouseEvent or a keypressEvent, but I don't know what triggers a paint Event.

I look at the "circle" example, but I don't see the event that acttvates the paintEvent.

I guess I am sort of looking for a "SIGNAL" but I know there isn't one per se. The best I can explain my understanding is, these event handlers monitor program activity and when somthing happens they like, they jump in and do their thing.

In my program I get user input of a set of coordinates for a line. The input is in string form. I attach this string to a QStringList. Now I want to display all, some, or just one of these lines in a "ui.drawingBox" ( a QFrame In designer ).I know I can extract the numeric coordinates, scale them either in a program module or in a paint Event. But what has to happen for the paintEvent to go into action?

What I tried to show in my last post was a simple program that had a drawing area (ui.drawingBox), QLineEdit, and 3 push buttons. "Draw", "Clear" & "Exit".
The "user" enters " 0, 0, 50, 75".,clicks on the "draw" button and the line is displyed on the screen.

If Trolltech would do somthing like this, a simple example for each of their functions, it would make life much simplier.

jacek
21st June 2006, 16:18
Qt will send a QPaintEvent to your widget when it needs to redraw it. For example when that widget was shown for the first time or part of it became visible after some other window has been closed. You can tell Qt that widget needs a redraw by invoking one of the QWidget::update() methods (you can also use QWidget::repaint() if you really want to).

If you want to draw anything on a widget, you should do it in its paintEvent(). This means that either paintEvent() implementation must be able to access all information required for drawing in a short time or it will just copy the contents of a buffer (i.e. QPixmap), that was prepared earlier.

If you have to draw a set of lines (or other objects) that can be changed by the user, you might consider using Q3Canvas.

impeteperry
21st June 2006, 17:31
What you are telling me is that a program can not directily. draw a line directly.
If you want to draw anything on a widget, you should do it in its paintEvent(). This means that either paintEvent() implementation must be able to access all information required for drawing in a short time or it will just copy the contents of a buffer (i.e. QPixmap), that was prepared earlier.
Llook at the "circle" example. The "window" function sends "stuff" to the "circleWidget" and somthing triggers the "paintEvent" in the circleWidged" and it does the drawing

I can't see why or when the paintEvent kicked in

This is what I want to do, send stuff to a module and then have the "paintEvent" in the module do its stuff.

what event made the paintEvent kick in or what in my code dio I have to have to make my paintEvent kick in.

I have looked at paga after page of documentation, but have not found a simple explaination that I can understand. i want to know when a paintEvent takes over so i know how to use it in the future.

Thanks for your patients.

jacek
21st June 2006, 17:49
I can't see why or when the paintEvent kicked in
In Window's contructor you have:
...
connect(timer, SIGNAL(timeout()), circleWidgets[i][j], SLOT(nextAnimationFrame()));
...
timer->start(100);so every 100 ms CircleWidget::nextAnimationFrame() slot of each CircleWidget will be invoked.

This slot looks like this:
void CircleWidget::nextAnimationFrame()
{
++frameNo;
update();
}It just changes the frame number and invokes QWidget::update(), which notifies Qt that widget has to be redrawn (actually it just sends a QPaintEvent). A moment later QPaintEvent is picked up by the event loop, which invokes the paintEvent() method.

impeteperry
21st June 2006, 18:45
Thanks.
I looked at QTimer. You have to be kidding. At least I know where to start. I have my trigger. I will get back to you with some comments when I know more about this. I just can't believe it.

Thanks I really mean it.

pete

jacek
21st June 2006, 18:56
QTimer is needed only for animation. For static contents it will be enough if you invoke QWidget::update() when something changes.

impeteperry
23rd June 2006, 03:18
Thanks, talk about being confused, boy am I ever.

Using designer I have a "ui.drawingBox" which is a QFrame.
I have a "edpForm" which is my base class.
I start off with
edpForm::edpForm()
{
ui.setupUi(this);
help = new HelpFunction( this );
drawings = new DrawingFunctions( this );
controls = new ControlFunctions( this );
plus many more classes. In my constructor I have

drawings->setupDrawing( ui.drawingFrame, &baseBuffer, ui.centerBox );and in my DrawingFunction class I have
DrawingFunctions::DrawingFunctions( QWidget *parent ) : QWidget(parent)
{
}
void DrawingFunctions::setupDrawing( QFrame *f, QPixmap *p, QFrame *t)
{
drawings = f;
buffer = p;
frmTable = t;
pi = 3.1459265358979;

and start off with
QPainter p( drawings ); /// set drawing pixmap
QPainter b( buffer ) ; /// set buffer pixmap

slotSetDrawingScale();
count = lines.count();
start = 0;

if( code == "supports" )
and come down to this
for( n = start; n < count; ++ n )
{
k = lines[n]; // get line coordinates string
temp = k.split( "//" ); // split into coordinates

h = temp[0];
dim = h.toLong( &ok );
xs = (int) ( deltaX + scaleFactor * dim );

h = temp[1];
dim = h.toLong( &ok );
ys = (int) ( deltaY + scaleFactor * ( maxY - dim ) );

h = temp[2];
dim = h.toLong( &ok );
xe = (int) ( deltaX + scaleFactor * dim );

h = temp[3];
dim = h.toLong( &ok );
ye = (int) (deltaY + scaleFactor * ( maxY - dim ) );

p.drawLine( xs, ys, xe, ye );
b.drawLine( xs, ys, xe, ye );This all works fine for Qt3.

For Qt4 I have tried about everything I can think of. I have added a paintEvent
DrawingFunctions::paintEvent( QPaintEvent* event)
{
QPainter painter(drawing); // drawing being the ui.drawingBox;
painter.drawLine( xs, ys, xe, ye );
}
I have tried the "timer" after looking at the "Detailed Description".
I just now tried a "drawings->update(); no luck.
I have loaded my program into KDevelope which I find much easier to work with then DDD. for single stepping.
In get either a "sig...." error or a runaway message saying I need to access a paintEvent.
Unfortunately the Programming with Qt4 book by Blanchette & Summerfield hasn't been released yet.

Somewhere I saw you could write to a Pixmap and then have it transfer the image to paintEvent, but I think this is just a bitBlt subutitute.

Am I the only one having this kind of trouble?

Thanks.

As you can see, I don't know what the h... i'm doing

munna
23rd June 2006, 05:14
I think it should be something like



DrawingFunctions::paintEvent( QPaintEvent* event)
{
QPainter painter(this);
painter.drawLine( xs, ys, xe, ye );
}


The points are calculated somewhere else and on every piantEvent the line is drawn. If you are not able to see the line then check if the co-ordiantes are negative or beyond the widget's size.

I think the buffer part i.e.



QPainter p( drawings ); /// set drawing pixmap
QPainter b( buffer ) ;


is not needed since from Qt 4.0, QWidget automatically double-buffers its painting, so there's no need to write double-buffering code in paintEvent() to avoid flicker.

I think you can first try out painting examples that come with Qt to get a better picture of the whole thing.

impeteperry
24th June 2006, 02:49
Thanks, I have writen a short program that finallly works and I think I understand why.

In addition to the great help you all have given me, I also had some help by, e-mail, from a very nice person from India who monitors this forum.

One of the great things about Linux is the paople who use it. Thanks again