Results 1 to 8 of 8

Thread: Painting within different Widgets and updating them individually

  1. #1
    Join Date
    Dec 2015
    Posts
    5
    Qt products
    Qt5
    Platforms
    Windows

    Question Painting within different Widgets and updating them individually

    Hello,

    I'm new to Qt and I'm working on a program where I need to paint on different Widgets. In the end, I would like to display these widgets frameless and use the main window to change the paintings in these widgets step by step (text, picture, basic drawings). I'm using Qt 5.5 under Windows.

    Currently my program consists of a main window with three buttons:
    1. Start -> creates five Widgets (class OutputWindow)
    2. Test -> paints within the main window
    3. Quit -> ends the program

    By clicking inside one of the five OutputWindow(s) (A, B, C, D and E), I can paint within each of these Widgets. Unfortunately, I can only paint within one Widget at a time. But I need to preserve the paintings in each Widget and change them individually. How can I preserve the current paintings while drawing on another Widget? (How should I handle update() / this situation?)

    The second problem is that I'm not able to trigger the paintEvent for the OutputWindow(s) from within the Main Window. How can I use (for example) a button from the Main Window (class ControlWindow) to call a paintEvent from another class (OutputWindow) to paint on a Widget derived from this class?

    I'm not sure if I've understod the use / reimplementation of paintEvent correctly

    To make my problem clear, I've attached some screenshots. And of course here is a part of the Code (you can find the whole project attached as a zip-file!):

    controllerWindow.cpp | set variable true if button "Test" (btnTest) was pushed
    Qt Code:
    1. void ControllerWindow::tempButtonPushed()
    2. {
    3. vtempButtonPushed = true;
    4. update();
    5. }
    To copy to clipboard, switch view to plain text mode 

    controllerWindow.cpp | paintEvent
    Qt Code:
    1. void ControllerWindow::paintEvent(QPaintEvent*)
    2. {
    3. if (vtempButtonPushed == true)
    4. {
    5. QPainter painter(this);
    6. QPen pen(Qt::red, 10, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
    7.  
    8. painter.setPen(pen);
    9. painter.drawLine(0, 0, 800, 800);
    10.  
    11. vtempButtonPushed = false;
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    outputWindow.cpp | set variable true if mouse button was clicked
    Qt Code:
    1. void OutputWindow::mousePressEvent(QMouseEvent*)
    2. {
    3. vtempButtonPushed = true;
    4. update();
    5. }
    To copy to clipboard, switch view to plain text mode 

    outputWindow.cpp | paintEvent
    Qt Code:
    1. void OutputWindow::paintEvent(QPaintEvent*)
    2. {
    3. if (vtempButtonPushed == true)
    4. {
    5. QPainter painter(this);
    6. QPen pen(Qt::blue, 10, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
    7.  
    8. painter.setPen(pen);
    9. painter.drawLine(0, 0, 800, 800);
    10.  
    11. vtempButtonPushed = false;
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    Thank you in advance!
    Max
    Attached Images Attached Images
    Attached Files Attached Files

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Painting within different Widgets and updating them individually

    In your painEvent() you reset vtempButtonPushed back to false, so after one paint you reset the condition for painting.

    So the next time paintEvent() is called you draw nothing.

    If you want the line to be persistent, don't reset the condition that enables it

    Cheers,
    _

  3. #3
    Join Date
    Dec 2015
    Posts
    5
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Painting within different Widgets and updating them individually

    Hey anda_skoa,
    you're right! That's what I love about programming Simple errors can drive you crazy... Thanks a lot!
    Conclusion: update() repaints all my widgets. If I want to "keep" a painting, I've to repaint it = don't reset the condition that enables it, as you've pointed out previously.

    I'm using vtempButtonPushed as a variable to keep track of possible "states" (= different paintings). Is this a suitable way or may another way/method be a better approach for my intention? Here is the corresponding Code:

    Using the mousPressEvent to go through the different states:
    Qt Code:
    1. void OutputWindow::mousePressEvent(QMouseEvent*)
    2. {
    3. // vtempButtonPushed has 3 possible states (see paintEvent() above). If mouse button is clicked, move to the next state. After the state 3, draw nothing (vtempButtonPushed == 4) and move back to state 1 with the next click
    4. if (vtempButtonPushed <=3)
    5. {
    6. vtempButtonPushed += 1;
    7. }
    8. else
    9. {
    10. vtempButtonPushed = 1;
    11. }
    12.  
    13. update();
    14. }
    To copy to clipboard, switch view to plain text mode 
    Checking the current state and choose the painting accordingly:
    Qt Code:
    1. void OutputWindow::paintEvent(QPaintEvent*)
    2. {
    3. // vtempButtonPushed == 0 do nothing / 1 blue line / 2 red line / 3 green line
    4. if (vtempButtonPushed == 1)
    5. {
    6. QPainter painter(this);
    7. QPen pen(Qt::blue, 10, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
    8.  
    9. painter.setPen(pen);
    10. painter.drawLine(0, 0, 800, 800);
    11. }
    12. else if (vtempButtonPushed == 2)
    13. {
    14. QPainter painter(this);
    15. QPen pen(Qt::red, 10, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
    16.  
    17. painter.setPen(pen);
    18. painter.drawLine(0, 0, 800, 800);
    19. }
    20. else if (vtempButtonPushed == 3)
    21. {
    22. QPainter painter(this);
    23. QPen pen(Qt::green, 10, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
    24.  
    25. painter.setPen(pen);
    26. painter.drawLine(0, 0, 800, 800);
    27. }
    28. }
    To copy to clipboard, switch view to plain text mode 
    This works for my outputWindow Widgets individually (see picture attached). Although I can control the individual behaviour of each Widget by using objectName() as part of my if-conditions like this:
    Qt Code:
    1. if (vtempButtonPushed == 1 && (this->objectName() != "outputWindowA"))
    To copy to clipboard, switch view to plain text mode 


    Regarding my second question: How can I use (for example) a button from the Main Window (class ControlWindow) to call a paintEvent from another class (OutputWindow) to paint on a Widget derived from this class?
    I had tried to connect a button, which is part of the Main Window, to the SLOT of another class (OutputWindow) which is not part of the form. It has not occured to me that this may not be possible within the designer and that I've to code that manually. I've found this thread where someone else had the same problem (he although shows his solution): https://forum.qt.io/topic/16847/how-...n-class-slot/5
    I'll try this approach and post again if I need some more assistance.

    Thank you very much
    Max
    Attached Images Attached Images
    Last edited by The EYE; 6th January 2016 at 13:34. Reason: reformatted to look better

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Painting within different Widgets and updating them individually

    Quote Originally Posted by The EYE View Post
    Conclusion: update() repaints all my widgets.
    update() schedules a paint event on the widget you call update on.
    Usually that does not affect other widgets.

    Quote Originally Posted by The EYE View Post
    I'm using vtempButtonPushed as a variable to keep track of possible "states" (= different paintings). Is this a suitable way or may another way/method be a better approach for my intention?
    That looks ok, though I would reset to 0 instead of going to 4 when you've reached the end, so that all values are either used in paintEvent() or at least appear in a comment.
    Even better would be to use an enum with respectively named values instead of integer literals.

    Quote Originally Posted by The EYE View Post
    Although I can control the individual behaviour of each Widget by using objectName() as part of my if-conditions
    While this works, it will get hard to understand quickly.
    There are usually better ways to separate different behavior, but it really depends on what you need to be different.

    Quote Originally Posted by The EYE View Post
    Regarding my second question: How can I use (for example) a button from the Main Window (class ControlWindow) to call a paintEvent from another class (OutputWindow) to paint on a Widget derived from this class?
    QWidget::update() is a slot, so you can simply connect the button's clicked signal to it.
    But of course that will just result in paintEvent() being called, i.e. refreshing the already displayed drawing.

    Quote Originally Posted by The EYE View Post
    I've found this thread where someone else had the same problem (he although shows his solution): https://forum.qt.io/topic/16847/how-...n-class-slot/5
    My recommendation would be to use explicit connects instead, see QObject::connect().

    Cheers,
    _

  5. #5
    Join Date
    Dec 2015
    Posts
    5
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Painting within different Widgets and updating them individually

    Quote Originally Posted by anda_skoa View Post
    update() schedules a paint event on the widget you call update on.
    Usually that does not affect other widgets.
    The program example in my first post showed exactly this behaviour: update() affected all widgets, no matter from which class they derived from. That's why it was a problem that I'd reset the "paint condition". If update() wouldn't have had an affect on the other widgets, the missing "paint condition" wouldn't have mattered, because Qt wouldn't have called the paintEvent. At least this is the way I see it. Did I get something wrong?

    Quote Originally Posted by anda_skoa View Post
    That looks ok, though I would reset to 0 instead of going to 4 when you've reached the end, so that all values are either used in paintEvent() or at least appear in a comment.
    Even better would be to use an enum with respectively named values instead of integer literals.
    Good point! I've changed it - now it goes from 0 to 3. And I'm going to look into the possibilities using enum. But I'm not sure if I can come up with some meaningful descriptions for the different states.

    Quote Originally Posted by anda_skoa View Post
    While this works, it will get hard to understand quickly.
    There are usually better ways to separate different behavior, but it really depends on what you need to be different.
    In the end the five (black) widgets are going to show the following things:
    1. some (blinking) drawings to show the user something (by using a projector in the real world)
    2. a progessbar
    3. instructions on what to do
    4. again some drawings to assist the user in the real world
    5. a picture

    The user has to be able to move through this process step by step. That's why I'm not sure if I can come up with anything better to descripe the current state instead of the int values.

    I'm thankful for any ideas and suggestions on how to tackle this :-) As always: The simpler, the better! I would like to program it in a way that allows other people to understand it quickly.

    Quote Originally Posted by anda_skoa View Post
    QWidget::update() is a slot, so you can simply connect the button's clicked signal to it.
    But of course that will just result in paintEvent() being called, i.e. refreshing the already displayed drawing.
    Good to know, thanks! But, like you've said, only calling update() is not enough.

    Quote Originally Posted by anda_skoa View Post
    My recommendation would be to use explicit connects instead, see QObject::connect().
    Thank you, I'm going to check on that right now.

    I although attached my current example code to make helping easier for everybody

    Thank you once again, I'm looking forward to further contributions of the forum!
    Max
    Attached Images Attached Images
    Attached Files Attached Files

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Painting within different Widgets and updating them individually

    Quote Originally Posted by The EYE View Post
    The program example in my first post showed exactly this behaviour: update() affected all widgets, no matter from which class they derived from. That's why it was a problem that I'd reset the "paint condition". If update() wouldn't have had an affect on the other widgets, the missing "paint condition" wouldn't have mattered, because Qt wouldn't have called the paintEvent. At least this is the way I see it. Did I get something wrong?
    Usually only the widget you are calling update() on will get a paint scheduled, but there could be internal mechanisms or even parts of the windowing system that trigger additional updates.
    Or to rephrase it differently: calling update() on one widget is not guaranteed to cause a repaint of all others.

    Quote Originally Posted by The EYE View Post
    In the end the five (black) widgets are going to show the following things:
    1. some (blinking) drawings to show the user something (by using a projector in the real world)
    2. a progessbar
    3. instructions on what to do
    4. again some drawings to assist the user in the real world
    5. a picture

    The user has to be able to move through this process step by step. That's why I'm not sure if I can come up with anything better to descripe the current state instead of the int values.
    Hmm, but if they draw different things, maybe they should be different widgets? Each implementing its respective "workflow"

    If some things are the same, e.g. all widgets have four states and advance the state on mouse press, then that part could be split into a small helper class that each of the widgets then uses for state tracking.

    Quote Originally Posted by The EYE View Post
    Good to know, thanks! But, like you've said, only calling update() is not enough.
    Right. Originally you asked about triggering paintEvent(), that is what update() does.
    What do you want to do, what should happen, when the button is clicked?

    Cheers,
    _

  7. #7
    Join Date
    Dec 2015
    Posts
    5
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Painting within different Widgets and updating them individually

    Quote Originally Posted by anda_skoa View Post
    Usually only the widget you are calling update() on will get a paint scheduled, but there could be internal mechanisms or even parts of the windowing system that trigger additional updates.
    Or to rephrase it differently: calling update() on one widget is not guaranteed to cause a repaint of all others.
    Thanks for the explanation! I'll test this behaviour with Linux if I find the time. Maybe Windows is the problem/unknown part here. Anyway, this project is going to run on Windows so I've to work with that.

    Quote Originally Posted by anda_skoa View Post
    Hmm, but if they draw different things, maybe they should be different widgets? Each implementing its respective "workflow"

    If some things are the same, e.g. all widgets have four states and advance the state on mouse press, then that part could be split into a small helper class that each of the widgets then uses for state tracking.
    In the beginning, I thought it would be useful to let them derive from the same class to make the code easier to read (because they have the same properties like backgroundcolor and so on). On second thought (thanks ) this would make the code harder to read because of the complicated if-conditions and so on.

    The helper class sounds very promissing! Great idea! So I could split up the different widgets into different classes and use a helper class to keep track of the current state. This would allow me to manage the behaviour of each widget within "there code-area" instead of (potentially confusing) if-conditions and so on.

    Quote Originally Posted by anda_skoa View Post
    Right. Originally you asked about triggering paintEvent(), that is what update() does.
    What do you want to do, what should happen, when the button is clicked?
    I've got you wrong. You're absolutely right. I ment changing the paint condition (value of vtempButtonPushed) and schedule a paintEvent afterwards.

    After lunch, I'll try to implement QObject::connect().

    Thanks!
    Max

  8. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Painting within different Widgets and updating them individually

    Quote Originally Posted by The EYE View Post
    bsolutely right. I ment changing the paint condition (value of vtempButtonPushed) and schedule a paintEvent afterwards.
    Ah, that should be easy.

    Just add a custom slot, in which you change the state and call update().

    Cheers,
    _

Similar Threads

  1. Updating widgets
    By The 11th plague of Egypt in forum Qt Programming
    Replies: 17
    Last Post: 28th September 2011, 18:41
  2. Painting a WebPage to the FrameBuffer without Widgets
    By DaRabman in forum Qt for Embedded and Mobile
    Replies: 0
    Last Post: 10th August 2011, 15:14
  3. Replies: 3
    Last Post: 29th August 2010, 15:18
  4. QDockWidget::title is painting over other widgets with QSS
    By edisongustavo in forum Qt Programming
    Replies: 0
    Last Post: 16th March 2010, 22:44
  5. Not updating while painting in QMdiArea
    By rippa in forum Qt Programming
    Replies: 18
    Last Post: 14th April 2008, 16:35

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.