Solved

Qt / C++ / Override paintEvent

Posted on 2014-04-22
11
1,507 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
ID: 40018360
Wait a minute - you are saying the bitmap gets saved while the function is not being called?
0
 

Author Comment

by:PMH4514
ID: 40018422
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
ID: 40018459
Try moving 'QWebView::paintEvent(event);' into the 'if' statement.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 

Author Comment

by:PMH4514
ID: 40018466
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 33

Expert Comment

by:sarabande
ID: 40019513
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
 

Author Comment

by:PMH4514
ID: 40019743
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 33

Accepted Solution

by:
sarabande earned 500 total points
ID: 40020741
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
ID: 40026419
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
ID: 40031017
@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 33

Expert Comment

by:sarabande
ID: 40031650
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
ID: 40031942
Thank you Sara very insightful.
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

829 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