Solved

Qt / C++ / Override paintEvent

Posted on 2014-04-22
11
1,396 Views
Last Modified: 2014-04-30
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!
0
Comment
Question by:PMH4514
  • 6
  • 3
  • 2
11 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Wait a minute - you are saying the bitmap gets saved while the function is not being called?
0
 

Author Comment

by:PMH4514
Comment Utility
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
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Try moving 'QWebView::paintEvent(event);' into the 'if' statement.
0
 

Author Comment

by:PMH4514
Comment Utility
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
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:PMH4514
Comment Utility
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
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
Comment Utility
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
 

Author Comment

by:PMH4514
Comment Utility
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
 

Author Comment

by:PMH4514
Comment Utility
@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
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
 

Author Comment

by:PMH4514
Comment Utility
Thank you Sara very insightful.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now