Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QPushButton geometry issue
Forum Updated to NodeBB v4.3 + New Features

QPushButton geometry issue

Scheduled Pinned Locked Moved General and Desktop
geometryrectpaint
8 Posts 2 Posters 4.5k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Tannz0rz
    wrote on last edited by Tannz0rz
    #1

    I'm creating my own click effect, rather than the default emphasized by the border. It simply fades into a white rect over top of the QPushButton. You can see it in the upper-left in this image:
    http://i.imgur.com/buqYXyn.png

    As you can tell, it doesn't fully cover the button as I was hoping it would and I'm not sure why.

    EDIT: Here is the working code folks. The gentleman in the comments was less than helpful in providing a meaningful solution, but getting a grips with the workings of Qt isn't terribly difficult provided the excellent documentation. Perhaps this will assist others when coming across a similar situation.

    pushbutton.h:

    #ifndef PUSHBUTTON
    #define PUSHBUTTON
    
    #include <QtCore>
    #include <QPushButton>
    #include <QPainter>
    
    class PushButton : public QPushButton
    {
        Q_OBJECT
    
    public:
        explicit PushButton(QString text, QWidget *parent = 0);
    
    protected:
        virtual void paintEvent(QPaintEvent *);
    
    public slots:
        void OnClick();
        void OnTick();
    
    private:
        enum States
        {
            NONE = 0,
            RESET,
            DRAW
        } state = NONE;
    
        QTimer *timer;
    
        float delta = -1.0f;
    };
    
    #endif
    

    pushbutton.cpp:

    #include "pushbutton.h"
    
    PushButton::PushButton(QString text, QWidget *parent) : QPushButton(text, parent)
    {
        timer = new QTimer(this);
    
        QObject::connect(this, SIGNAL(clicked(bool)), this, SLOT(OnClick()));
        QObject::connect(timer, SIGNAL(timeout()), this, SLOT(OnTick()));
    }
    
    void PushButton::paintEvent(QPaintEvent *e)
    {
        QPushButton::paintEvent(e);
    
        if(state == States::NONE)
        {
            return;
        }
    
        QPainter painter(this);
    
        if(state == States::RESET)
        {
            state = States::NONE;
    
            painter.eraseRect(rect());
    
            update();
        }
        else
        {
            painter.fillRect(rect(), QColor(200, 200, 200, 200 * (delta < 1.0f ? delta : 2.0f - delta)));
        }
    }
    
    void PushButton::OnClick()
    {
        state = States::DRAW;
    
        delta = 0.0f;
    
        timer->start(20);
    }
    
    void PushButton::OnTick()
    {
        delta += 0.2f;
    
        if(delta > 2.0f)
        {
            state = States::RESET;
    
            timer->stop();
        }
    
        update();
    }
    
    

    Regards,
    Tannz0rz

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      Hi, welcome to devnet.

      Ok, it's gonna be hard to explain but I'll try...
      There are a couple of fundamental mistakes here:

      ButtonClickEffect inherits from QWidget. This is wrong to start with. It's an effect applied to a widget. It shouldn't be a widget itself.

      Then you cast QWidget* parent to QPushButton with a C cast...ugh, don't do that. If I pass a QLineEdit as a parent this code will crash and burn.

      Then there's a paint event. It's a paint event of the effect widget, not the button widget, so passing button->geometry() to fillRect is wrong, as its a geometry that possibly (and in this case does) span outside the clip rectangle of the widget being painted.

      You're giving your ButtonClickEffect widget a parent, but it doesn't place it in any layout or anything. So it will just have some default size (what you see in the picture). It will not resize to the size of it's parent on its own, and you can't paint outside of the rectangle of that widget (like you try to do).

      This whole approach is not really good. Just install an event filter on the button and hijack its paint event there to do your custom drawing.

      T 1 Reply Last reply
      0
      • Chris KawaC Chris Kawa

        Hi, welcome to devnet.

        Ok, it's gonna be hard to explain but I'll try...
        There are a couple of fundamental mistakes here:

        ButtonClickEffect inherits from QWidget. This is wrong to start with. It's an effect applied to a widget. It shouldn't be a widget itself.

        Then you cast QWidget* parent to QPushButton with a C cast...ugh, don't do that. If I pass a QLineEdit as a parent this code will crash and burn.

        Then there's a paint event. It's a paint event of the effect widget, not the button widget, so passing button->geometry() to fillRect is wrong, as its a geometry that possibly (and in this case does) span outside the clip rectangle of the widget being painted.

        You're giving your ButtonClickEffect widget a parent, but it doesn't place it in any layout or anything. So it will just have some default size (what you see in the picture). It will not resize to the size of it's parent on its own, and you can't paint outside of the rectangle of that widget (like you try to do).

        This whole approach is not really good. Just install an event filter on the button and hijack its paint event there to do your custom drawing.

        T Offline
        T Offline
        Tannz0rz
        wrote on last edited by
        #3

        @Chris-Kawa Thanks. How do you force a paint update in that case? It needs to be updated within the timer.

        1 Reply Last reply
        0
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #4

          You can call either update() or more directly repaint() on it in response to timer event and then do the painting in the event filter..

          T 1 Reply Last reply
          0
          • Chris KawaC Chris Kawa

            You can call either update() or more directly repaint() on it in response to timer event and then do the painting in the event filter..

            T Offline
            T Offline
            Tannz0rz
            wrote on last edited by
            #5

            @Chris-Kawa I've tried the following, but the results are unsavory. It flashes white over top of the button and thereafter the text becomes hidden until the next paintEvent call. The update seems to work, just that it doesn't render as it ought to.

            Header: http://pastebin.com/cW72y2ns
            Source: http://pastebin.com/H7vQgEy6

            Initialization:

            pushButton->installEventFilter(new ButtonClickEffect(pushButton));
            
            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              You're discarding the button default paint event so yes, you will not see any text (or a button) with that code.
              What is the result you're trying to get?

              T 1 Reply Last reply
              0
              • Chris KawaC Chris Kawa

                You're discarding the button default paint event so yes, you will not see any text (or a button) with that code.
                What is the result you're trying to get?

                T Offline
                T Offline
                Tannz0rz
                wrote on last edited by
                #7

                @Chris-Kawa A quick flash of white overlaid on the button. As in my fillRect, I set the alpha to

                200 * (delta < 1.0f ? delta : 2.0f - delta)
                

                So it scales up to 1 from 0 and down to 0 from 1.

                1 Reply Last reply
                0
                • Chris KawaC Offline
                  Chris KawaC Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Well yes, but you're painting that color with alpha over whatever widget is under the button, since the event filter is called before paint event of the button and you return true from it so the button's paint event is never actually called. To see the button painted underneath you need to actually call the paint event of the button manually before you overpaint it with your color.

                  Unrelated comments:

                  You seem to have a very bad habit of just casting types with a C cast to whatever you think you need at the moment. I'm referring to the QWidget *widget = (QWidget *)object; cast in the eventFilter. If I used any non-widget QObject derived type with your class it would compile successfully and crash at runtime. There's a isWidgetType() method on a QObject that you can test with before casting. Also please don't use C style casts. It's just plain evil and you will cause bugs with it. Either to yourself or other people that use your classes. There's a lot safer qobject_cast for QObject derived types that will return nullptr that you can test for if the type can't be cast.

                  Painting in response to a timer with interval of 10ms makes no sense on almost any of user's machines. The typical display is ticking at 60Hz (i.e. little over 16ms) so anything lower than that is just giving Qt more work in filtering out the update requests you are flooding it with. Displays with a higher refresh rate are still very rare and even on them there's not gonna be a noticeable difference if you stick to 60Hz animation.

                  Using == operator on a floating point numbers is on borderline of being a bug. You should practically never do that unless you're actually testing floating number stability, which is like super rare. Use non-strict comparisons (< and >) or just stick to fixed point integers for steps like that.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved