Need to check the right-click event from a QButtonGroup



  • Hi,
    I currently use the following code to generate a buttongroup to place pushbuttons like a grid. This is working well. But I can't figure out how to manage the right click event .

    MyClass::MyClass(QWidget * parentWidget)
    {
    setParent(parentWidget)  ;
    
        QVBoxLayout *layout     = new QVBoxLayout()     ;
        QHBoxLayout *Hlayout    = new QHBoxLayout()     ;
        Glayout    = new QGridLayout()          ;
        Glayout->setSpacing(0)                     ;
        Hlayout->addStretch(1)                 ;
        Hlayout->addLayout(Glayout)            ;
        Hlayout->addStretch(1)                ;
        layout->addLayout(Hlayout)       ;
        layout->addStretch(1)                   ;
    
    Populate(Glayout,Rows,Cols);
    }
    
    void MyClass::Populate(QGridLayout *layout, const int rows, const int cols)
    {
        for ( int i = 0; i < rows; ++ i)
        {
         for ( int j = 0; j < cols; ++j)
         {
          QPushButton* btn = new QPushButton(" ")          ;
          btn->setFixedWidth(20);
          btn->setStyleSheet("background-color:grey;")      ;
          layout->addWidget(btn,i,j)        ;
    
          this->addButton(btn)      ;
         }
        }
    }
    
    void MyClass::buttonClick(QAbstractButton* button)
    {
        int BtnID= abs(this->id(button)) -2 ;
    }
    


  • @doubitchou hi,
    that really dempends on what you want to do with that right click event.

    If you want to differentiate between left/right middle mous button beeing pressed, you will most likly have to Write your own subclass of QPushButton

    But from the code you posted, I believe you simply want the ID of whichever button was pressed.

    That is a lot easier and super simple with c11 Lambda functionality:

    lets use your code:

    void MyClass::Populate(QGridLayout *layout, const int rows, const int cols)
    {
        int id = 0; //<< New 
        for ( int i = 0; i < rows; ++ i)
        {
         for ( int j = 0; j < cols; ++j)
         {
          QPushButton* btn = new QPushButton(" ")          ;
          btn->setFixedWidth(20);
          btn->setStyleSheet("background-color:grey;")      ;
          layout->addWidget(btn,i,j)        ;
    
          this->addButton(btn)      ;
    //New
         connect(btn, &QPushButton::clicked, btn, [=]{buttonClick(id);});
         id++;
         }
        }
    }
    

    and your buttonClick function needs to be adjusted:

    void MyClass::buttonClick(int id)
    {
        int BtnID= id;
    }
    


  • @doubitchou

    Hi,

    Instead of using QPushButton object directly, create a class inherited by QPushButton and re implement mousePressEvent(QMouseEvent *event) there you can get type of event happens .

    event->button();



  • @J.Hilk
    The code I've posted already retrieve the ID of the button. what I'd need is just to define an action (change the color the current button to be exact) for right click event on any button.

    As you and @Venkatesh-V proposedn I'd need to subclassing pushbutton: could you please show me a snippet of that ?



  • @doubitchou

    that should be easy enough:

    #ifndef CBUTTON_H
    #define CBUTTON_H
    #include <QPushButton>
    #include <QMouseEvent>
    #include <QStyle>
    
    class cButton : public QPushButton
    {
        Q_OBJECT
        Q_PROPERTY(bool rightClicked READ wasRightClicked WRITE changeState)
    public:
        explicit cButton(QWidget * parent = 0) :
            QPushButton(parent){    }
        ~cButton(){}
    
        bool wasRightClicked(){return rightClicked;}
    
    public slots:
        void changeState(bool b){
            rightClicked = b;
            style()->unpolish(this);
            style()->polish(this);
        }
    
    signals:
        void rightClicked();
    
    protected:
    virtual void mousePressEvent(QMouseEvent *e)Q_DECL_OVERRIDE{
            if(e->button() == Qt::RightButton){
                   emit rightClicked();
                   changeState(true);
           }else{
                   changeState(false);
           }
            QPushButton::mousePressEvent(e);
        }
    
    private:
    bool rightClicked = false;
    }
    #endif
    

    the change in your code:

    #include "cButton"
    void MyClass::Populate(QGridLayout *layout, const int rows, const int cols)
    {
        for ( int i = 0; i < rows; ++ i)
        {
         for ( int j = 0; j < cols; ++j)
         {
          cButton* btn = new cButton(" ")          ;
          btn->setFixedWidth(20);
          btn->setStyleSheet("QPushButton{background-color:grey;}"
                                                 "QPushButton[rightClicked = true]{background-color:red;}")      ;
          layout->addWidget(btn,i,j)        ;
    
          this->addButton(btn)      ;
         }
        }
    }
    


  • @J.Hilk

    I have issue using :

    explicit MatrixButton(QWidget * parent = 0) : QPushButton(parent){}
    

    error : prototype for 'MatrixButton::MatrixButton()' does not match any in class 'MatrixButton'
    MatrixButton::MatrixButton()
    ^

    and not sure if the renaming of the clicked is correct, but it needed renaming as most have the same name. I think this could be ok :

    #ifndef MATRIXBUTTON_H
    #define MATRIXBUTTON_H
    
    #include <QPushButton>
    #include <QMouseEvent>
    #include <QStyle>
    
    class MatrixButton : public QPushButton
    {
        Q_OBJECT
        Q_PROPERTY(bool rightClicked READ wasRightClicked WRITE changeState)
    
    public:
        explicit MatrixButton(QWidget * parent = 0) : QPushButton(parent){}
        ~MatrixButton(){}
    
        bool wasRightClicked(){return _rightClicked;}
    
    public slots:
        void changeState(bool b)
        {
            _rightClicked = b;
            style()->unpolish(this);
            style()->polish(this);
        }
    
    signals:
        void rightClicked();
    
    protected:
    
        virtual void mousePressEvent(QMouseEvent *e)
        Q_DECL_OVERRIDE
        {
            if(e->button() == Qt::RightButton)
            {
                emit rightClicked();
                changeState(true);
            }
            else
            {
                changeState(false);
            }
            QPushButton::mousePressEvent(e);
        }
    
    private:
        bool _rightClicked = false;
    };
    
    #endif // MATRIXBUTTON_H
    


  • @doubitchou
    you'll need to change

    Q_PROPERTY(bool rightClicked READ wasRightClicked WRITE changeState)
    

    to

    Q_PROPERTY(bool _rightClicked READ wasRightClicked WRITE changeState)
    

    to be comform to your renaming

    this was intended as a header file only, class do you have a MatrixButton.cpp file ? that would explain a double MatrixButton::MatrixButton() definition



  • @J.Hilk

    indeed better, anyway even if this is the same code I use for the default grey button color, nothing happen on right click.

    void GuiMatrix::Populate(QGridLayout *layout, const int rows, const int cols)
    {
        for ( int i = 0; i < rows; ++ i)
        {
         for ( int j = 0; j < cols; ++j)
         {
    //      QPushButton* btn = new QPushButton(" ")                 ;
             MatrixButton *btn= new MatrixButton();
          btn->setFixedWidth(20);
          btn->setStyleSheet("QPushButton{background-color:grey;}"
                             "QPushButton[rightClicked = true]{background-color:red;}")      ;
          layout->addWidget(btn,i,j)                                ;
    
          this->addButton(btn)                              ;
         }
        }
    }
    

    I have also tried :

    btn->setStyleSheet("QPushButton{background-color:grey;}"
                            "QPushButton:pressed{background-color:red;}")      ;
    


  • @doubitchou
    First of, you changed the variable name, so you'll need to change your stylesheet too,

    //from
    btn->setStyleSheet("QPushButton{background-color:grey;}"
                             "QPushButton[rightClicked = true]{background-color:red;}")
    //to
    btn->setStyleSheet("QPushButton{background-color:grey;}"
                             "QPushButton[_rightClicked = true]{background-color:red;}")
    

    just tested it in a small sample project, with this btn construction:

    MatrixButton *btn = new MatrixButton();
        btn->setStyleSheet("QPushButton{background-color:red;}"
                           "QPushButton[_rightClicked = true]{background-color:white;}");
        btn->show();
    

    works as expected. If this still does not work for you, than you probably have a stylesheet in a parent widget overwriting your background-color.



  • @J.Hilk

    I see what you mean, in a way it's working. Until the click event, the white color is done.
    But after the click who change the color, ie :

    void MyClass::buttonClick(QAbstractButton* button)
    {
      button->setStyleSheet("background-color: #ffa500;")  ; 
    }
    

    the white from the right click doesn't appear anymore. even though this is not a parent, and this is done the same way (background-color) . Does your small example change the color on the click event and can put the white color back for the right-click ?



  • @doubitchou
    Yes the example does that. The color is changed back when you click with any Mousebutton but the right one or when your call manually changeState

    button->changeState(false);
    

    with this

    void MyClass::buttonClick(QAbstractButton* button)
    {
    button->setStyleSheet("background-color: #ffa500;") ;
    }

    you overwrite the stylesheet you previously set, and "QPushButton[_rightClicked = true]{background-color:white;}" has no effect any longer because it is no longer appplied to the button.



  • @J.Hilk

    I see. Sorry, I don't really have much knowledge about Stylesheets.

    enlightened by what you said, this is obvious now.
    Anyway it's far from obvious to see how to be able to either change the color by click or by right click ?

    I try to put back the same code you provide, when the click event appears ?



  • @doubitchou

    Well it seems right, I don't know if this is the best implementation but it's working. I have to overwrite that way

    QString ColorString = "QPushButton{background-color: " +   QString("#%1").arg(BtnColorValue, 6, 16, QLatin1Char( '0' ))  + ";} QPushButton[_rightClicked = true]{background-color:white;} ";
    

    It seems a complicated way to build the string but BtnColorValue come from a color list (which is a QList) I have to cycle with



  • @J-Hilk

    Thanks for your precious help, I still don't figure how to manage events with stylesheets as the docs are mostly about visual customization, but I'm sure this can be found somewhere.


Log in to reply