Results 1 to 9 of 9

Thread: Two different methods of using QBrush with QPainter - why is only one working?

  1. #1
    Join Date
    Jun 2011
    Posts
    11
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Two different methods of using QBrush with QPainter - why is only one working?

    Hi everybody,

    I just managed to complete a long untouched work on a widget I want to use in one of my projects. It is a "circular progress bar", simply drawn with QPainter::drawPie().

    pie.png

    During development, I have learned that I cannot assign a pointer to a QBrush to QPainter::setBrush() and then change some values of the brush to use different painting styles (well, actually I can - but in this case, all the area of the ellipse is painted black instead of only the pie itself). Instead, I have to create an all-new QBrush everytime I want to change the drawing style.

    Here is some code to explain the problem:

    Qt Code:
    1. //[... somewhere in the widget's header ...]
    2.  
    3. QPen *_foreGround;
    4. QBrush *_backGround;
    5.  
    6. //[... somewhere in the widget's initialization process ...]
    7.  
    8. _foreGround = new QPen();
    9. _foreGround->setCosmetic(true);
    10. _foreGround->setWidth(3);
    11. _backGround = new QBrush();
    12. _backGround->setColor(QColor(qRgba(0,0,0,0)));
    13.  
    14. //[...]
    15.  
    16. void QtProgressPie::paintEvent(QPaintEvent *e)
    17. {
    18. // recalculate the value according to the conditions of QPainter::drawPie
    19. // step 1: subtract _minimum from _value (so the calculation base is always 0)
    20. // step 2: calculate the percentage of value (value/max * 100)
    21. // step 3: translate it to circular conditions (value/max * [100 * 3.6 * 16]) [...] = _FULLCIRCLE
    22. // step 4: take it times -1 (QPainter::drawPie works counter-clockwise with positive values)
    23.  
    24. int _painterValue = ((_value - _minimum) / double(_maximum - _minimum) * _FULLCIRCLE) * -1;
    25.  
    26. p.begin(this); // Begin drawing on the widget
    27.  
    28. // make sure that the widget appears always as a circle, not as an ellipse
    29. int _squaredSize = qMin(this->width(), this->height());
    30. p.setViewport((this->width() - _squaredSize) / 2,(this->height() - _squaredSize) / 2,
    31. _squaredSize, _squaredSize);
    32. // subtract the width of the pen ("the border width") from the widget's rect() to get the drawable area
    33. int _borderWidth = _foreGround->width();
    34. QRect drawableArea(0 + _borderWidth, 0 + _borderWidth,
    35. this->width() - _borderWidth * 2, this->height() - _borderWidth * 2);
    36.  
    37.  
    38. p.setRenderHint(QPainter::HighQualityAntialiasing, true);
    39. p.setPen(*_foreGround);
    40. //p.setBrush(*_backGround); <--- DOESN'T WORK
    41.  
    42. // draw surrounding circle
    43. // _backGround->setStyle(Qt::NoBrush); <--- DOESN'T WORK
    44. p.setBrush(QBrush(QColor(qRgba(0,0,0,0)),Qt::NoBrush)); // <--- WORKS!
    45. p.drawEllipse(drawableArea);
    46.  
    47.  
    48. // draw pie if value < 0
    49. if (_painterValue < 0)
    50. {
    51. //_backGround->setStyle(Qt::SolidPattern); <--- DOESN'T WORK
    52. p.setBrush(QBrush(QColor(qRgba(0,0,0,0)),Qt::SolidPattern)); // <--- WORKS!
    53. p.drawPie(drawableArea, _OFFSET, _painterValue);
    54. // _OFFSET = 1/4 of _FULLCIRCLE (transition from 3 o'clock (drawPie's base) to 12 o'clock)
    55. }
    56.  
    57. p.end(); // Drawing finished
    To copy to clipboard, switch view to plain text mode 

    So, my question is: why can't I use the "more elegant" solution with the pointer variable?

    Greetings,
    Markus

    EDIT: picture added, futher explanation of what goes wrong when using a pointer.
    Last edited by EMKAH; 15th May 2013 at 00:23.

  2. #2
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    This line:
    Qt Code:
    1. //p.setBrush(*_backGround); <--- DOESN'T WORK
    To copy to clipboard, switch view to plain text mode 
    absolutely does work; that is a fundamental feature of C++ and nothing to do with Qt. Actually, all of the lines you marked work, they just do not do what you expect.

    You need to understand that QPainter::setBrush() takes a copy of the brush, and setPen() a copy of the QPen, you pass it. You can change the QBrush pointed to by your pointer after a call to QPainter::setBrush() but this will have no effect on the painter because the QBrush referenced through your pointer is not the same QBrush instance as the one used by QPainter. The same goes for QPen. QBrush and QPen are value objects and are designed to be be efficiently copied, there's really nothing to be gained from heap allocating them.

  3. #3
    Join Date
    Jun 2011
    Posts
    11
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    Quote Originally Posted by ChrisW67 View Post
    This line:
    Qt Code:
    1. //p.setBrush(*_backGround); <--- DOESN'T WORK
    To copy to clipboard, switch view to plain text mode 
    absolutely does work; that is a fundamental feature of C++ and nothing to do with Qt. Actually, all of the lines you marked work, they just do not do what you expect.
    Yeah, i know (this is what i tried to explain in my EDIT before ;-)).

    You need to understand that QPainter::setBrush() takes a copy of the brush, and setPen() a copy of the QPen, you pass it. You can change the QBrush pointed to by your pointer after a call to QPainter::setBrush() but this will have no effect on the painter because the QBrush referenced through your pointer is not the same QBrush instance as the one used by QPainter. The same goes for QPen. QBrush and QPen are value objects and are designed to be be efficiently copied, there's really nothing to be gained from heap allocating them.
    Thanks, that explains it. After reading your answer, I once again checked the Qt manual and recognized the const ref to QBrush... ;-)
    So, either I have to recall p.setBrush(*_backGround) after messing around with _backGround or just leave anything as it is right now. However, I think, the first solution doesn't make any sense at all as QBrush is copied anyways - so in fact, keeping a pointer to an extra QBrush is in fact a greater "memory pollution" than just creating a new QBrush on the fly when it's needed, am I correct?

    Thanks for your help!
    Markus
    Last edited by EMKAH; 15th May 2013 at 02:07.

  4. #4
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    You can create new QBrush or QPen instances on the fly (as local variables) or you can keep copies as member variables that you adjust before using them in setBrush()/setPen() calls. Your call really.

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    To add to that -- if you keep the brush as a member variable, then setting the brush on the painter with setBrush() does not increase memory use -- you have two "handles" to the brush but in fact only one instance of brush data. This works as long as you don't modify any of the "handles". If you do then a copy takes place so that each brush has its own instance of data. But since you modify the brush to apply the changes right away, you end up with a single instance of data again as the old data is deleted by QBrush. Same works for QPen, of course.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. #6
    Join Date
    Jun 2011
    Posts
    11
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    Thank you both for your valuable answers!

    Greetings,
    Markus

  7. #7
    Join Date
    Jun 2011
    Posts
    11
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    Hello again!

    As I'm advancing with my little widget, i just got another problem, which is also related with widget painting, so i decided to append my new problem right here in order to not flood the forum.

    I have subclassed my ProgressPie widget to create a timer-controlled progress pie. You give it a range and it counts down or up its limit values. I did this by implementing QObject::startTimer() and the timerEvent() method.

    I simply wanted to use my setValue() method from the parent widget which already includes a request to redraw itself after a value change:
    Qt Code:
    1. repaint(this->rect());
    To copy to clipboard, switch view to plain text mode 

    But when I call the function from the timerEvent() subclassed widged, nothing happens - unless i resize the window, which will trigger the resizeEvent (which is also implemented in the parent's code and which contains just the same line of code).

    When i put the line directly into my timerEvent() method of the subclass, the widget will repaint itself properly every time the timerEvent occurs.
    So - why's that?

    This is the whole code of both functions:

    The setValue() method of the parent class:

    Qt Code:
    1. void QtProgressPie::setValue(const int &val)
    2. {
    3. // Sets the given value which is checked against its bounds
    4. if (val != _value)
    5. {
    6. _value = qBound(_minimum, val, _maximum);
    7. repaint(this->rect());
    8. }
    9. }
    To copy to clipboard, switch view to plain text mode 


    The timerEvent() of the subclass:

    Qt Code:
    1. void QtTimedProgressPie::timerEvent(QTimerEvent *e)
    2. {
    3. // Modifies the current value of the timed ProgressPie.
    4. // By calling setValue of QtProgressPie, the widget will also be approprietely redrawn. // <--- No, it will not! :-(
    5. // Also, if the minimum or maximum value is arrived, the timerEvent will kill the timer
    6. // and emit the finished()-signal.
    7.  
    8. if (_countBackwards) // First case: counting towards _minimum
    9. {
    10. this->setValue(--_value); // dec and set value
    11. if (_value == _minimum) // check if value is now equal to the minimum
    12. { // if yes, kill timer and emit signal
    13. _timerIsRunning = false;
    14. killTimer(e->timerId());
    15. emit finished();
    16. }
    17. }
    18. else // Second case: counting towards _maximum
    19. {
    20. this->setValue(++_value); // inc and set value
    21. if (_value == _maximum) // check if value is now equal to the maximum
    22. { // if yes, kill timer and emit signal
    23. _timerIsRunning = false;
    24. killTimer(e->timerId());
    25. emit finished();
    26. }
    27. }
    28. repaint(this->rect()); // <--- this seems to be needed, but why?
    29. }
    To copy to clipboard, switch view to plain text mode 

    EDIT: typo
    Last edited by EMKAH; 19th May 2013 at 03:28.

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    First of all use update() instead of repaint(). Second of all you don't have to pass rect() into the call as by default the widget updates its whole rect. Third of all the call that you mark as needed is not needed.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Jun 2011
    Posts
    11
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: Two different methods of using QBrush with QPainter - why is only one working?

    Thanks for your advice. I adapted the code according to your remarks, but I still need the call inside the timerEvent() method, otherwise the widget won't get updated.


    EDIT: i finally got it. Thie problem was not the update() call but the way I called the setValue()-method.

    I tried to call setValue() with ++_value or --_value. This of course manipulates _value directly before calling the method with the same new _value.

    But my setValue() method begins with a check if the given integer parameter is different to the actual _value (because I want to emit a valueChanged() signal from that method). Of course, this will never be true, because of the direct manipulation of _value with ++ and --.

    Anyway, thanks for you help!
    Last edited by EMKAH; 19th May 2013 at 16:21. Reason: found the solution by myself

  10. The following user says thank you to EMKAH for this useful post:


Similar Threads

  1. QBrush pattern problem
    By ilovethisgame in forum Qt Programming
    Replies: 2
    Last Post: 4th October 2012, 23:07
  2. QPainter.drawImage() not working with resource image file
    By thiagoalencar22 in forum Qt Programming
    Replies: 4
    Last Post: 22nd April 2010, 22:07
  3. matrix for QBrush
    By navi1084 in forum Qt Programming
    Replies: 5
    Last Post: 5th February 2010, 12:27
  4. Is there any API to set QBrush instance as Cosmetic
    By navi1084 in forum Qt Programming
    Replies: 6
    Last Post: 3rd February 2010, 04:47
  5. QBrush pixmap tiling
    By rbp in forum Qt Programming
    Replies: 6
    Last Post: 19th June 2008, 13:54

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.