Qt / C++ / Override paintEvent

I'm new to Qt but having trouble finding answers or a solution  to something which I had assumed would be quite simple. My question on qt-project.org hasn't even had any responses.

I've extended QWebView with the hopes of overriding paintEvent.

I want to grab the rendered web view, "post process it" (ie. filter, invert colors, that sort of thing) and then display the processed result on the widget.

Here is what I have so far and below I will describe where it goes wrong:

void QMyCustomWebView::paintEvent(QPaintEvent *event)
{
    QWebView::paintEvent(event);

   if (!bGrabbing)
    {
        bGrabbing=true; // member variable to prevent the recursion when grabWidget also calls paintEvent.

        QPixmap pixmap(QPixmap::grabWidget(this));
        bGrabbing=false;

        QImage imgProcessed = pixmap.toImage();
        imgProcessed.invertPixels();

        QPainter paintFinal(this);
        paintFinal.begin(this);
        paintFinal.drawImage(0,0, imgProcessed);
        paintFinal.setPen( Qt::blue );
        paintFinal.drawEllipse(10,10,40,40);

        paintFinal.end();

        imgProcessed.save("c:\\test.bmp");
    }
}

Open in new window


Note I'm saving an image test.bmp.. As this runs, test.bmp actually contains what I would expect to see on screen.. The rendered WebView, with inverted pixels, and a small blue circle drawn over it.. so "imgProcessed" holds exactly what I'd expect.

But when I run it, what I see on screen is as if I hadn't even sub-classed QWebView

So I feel like that flag bGrabbing is a hack but since I'm new at Qt I don't know.  I'm finding that all of the ways of "grabbing" a widget (ie. render, grabWidget) all end up recursively calling paintEvent again and as stated, my "processed image" when saved to disc shows exactly what I want to show on screen.. So why is my QWebView widget not updated with the proper image? What am I doing wrong?

Thanks!
PMH4514Asked:
Who is Participating?
 
sarabandeConnect With a Mentor Commented:
yes, I understand that the bitmap is only a test. but nevertheless you should try to implement my suggestion just to see whether the image you rendered principally is ok.

if it works you would know two things:
(1) you cannot simply perform two painting actions with one event
(2) screen to bitmap and bitmap to screen works as desired.

the (1) could be because the QWebView already has used a QPainter object from begin to end and your additional painting was of no effect because the window was not invalidated again (a window normally was painted if it contents was "dirty") .  

generally it is not a good idea to let the baseclass paint, then grab the screenshot and then paint again. it would flicker or if the painting was only done partially, it would not work rightly. also any animations of the original would not happen.

if using two windows you could grab from the one and show the second with your paintings on it. you either could hide the first window or place the second window above the first one. or you have the second window only a frame (around the first view) and simply draw in the painEvent of the frame window onto the already painted view. the frame window then should be parent of the view window.

Sara
0
 
jkrCommented:
Wait a minute - you are saying the bitmap gets saved while the function is not being called?
0
 
PMH4514Author Commented:
Hi jkr,

No, the proper image gets saved because the function is being called once on every paintEvent, just as expected. The problem is that the widget as I see it on screen is not actually displaying my processed version of itself, rather, the widget renders exactly as if I had never overridden the paintEvent. This is what I can't figure out.
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

 
jkrCommented:
Try moving 'QWebView::paintEvent(event);' into the 'if' statement.
0
 
PMH4514Author Commented:
I've tried that already. The visible result on screen is unchanged, it still looks "normal", but the saved file is just a big gray rectangle rather than being the processed version of the widget.
0
 
sarabandeCommented:
you may try to skip the call to base class paintEvent at all and instead load the bitmap from file and paint it. if that works and the image is fine, the problem is that you can't paint twice within one event. you could solve that by using two views (one hidden) or by invalidating the window again after initial paint. if the image from file is not fine you may check your image creation.

Sara
0
 
PMH4514Author Commented:
Hi Sara. The bitmap file is only a "test" to see if the post processing worked. In real use there will be no file.  If I never call paintEvent in the base class, I never get that image data. (for performance reasons I wouldn't want to save and load a file on every paint anyway)

I simply want to grab and process the pixels of the QWebView before they are rendered to screen. I don't want to prevent any user interaction with the loaded page in the WebView.  Can you show an example of what you mean by doing that with two views?
0
 
PMH4514Author Commented:
excuse my silence, I have been traveling and my Qt trial license has expired simultaneously. I will try to work through your idea and post back as soon as I can. thanks
0
 
PMH4514Author Commented:
@Sara, success!

I changed QMyCustomWebView::paintEvent to "grab" just as it was to a class level QImage member variable, but then only post process it and not otherwise attempt to draw it.

I then made a new QFrame derived class and it stores a reference to the QMyCustomWebView instance. It also occupies the same rectangle and sets Qt::WA_TransparentForMouseEvents.   Within this "transparent frame" I overrode paintEvent such that it only draws the processed image as held by QMyCustomWeb and now the result is what I was going for - interactivity with the underlying WebView, but seeing only the processed result.

Thanks for the good direction!

My only question is with the way I used a member variable in my QFrame derived class to point to the QMyCustomWebView widget.  Would signals/slots have been more appropriate?
0
 
sarabandeCommented:
I used a member variable in my QFrame derived class to point to the QMyCustomWebView widget.  Would signals/slots have been more appropriate?
generally, pointers to other objects are normally not the best idea especially when the objects were managed somewhere else. so for example if the view was closed the pointer becomes invalid and any action from the QFrame after this time may lead to a crash, then.

you could make it safe by handling the "destroy event" of your view and post a message  (signal) to the QFrame that it should set the pointer to NULL.

generally you may check whether you need the pointer of the view as a member or if there are other ways where you retrieve the pointer before use and where you could check whether it is valid.  for example, the frame window should be "parent window" of the "view window" if so, you should be able to "find" the view via the parent-child relation.

signal/slot technique might be not appropriate for your purpose cause the initial paint event probably should be closed with the final painting of your view. if you give the control back to the QT between both drawings it could lead to a flicker effect because of mutual invalidation of the windows. but that is a guess only. you may try and it could be very well that my concerns are reasonless.

Sara
0
 
PMH4514Author Commented:
Thank you Sara very insightful.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.