QFrame properties do not work in extended QFrame sub-class



  • Hi, I want to use a QFrame to organize some labels in my application. I creates a MFrame class based on QFrame to enable the QEvent::Hover Events. The Hover enter/move/leave events all work fine. However, the QFrame properties, such as frameShape, frameShadow, and lineWidth do not work. Though those properties show correctly in the designer, they do not show correctly when run the application. In the application, the frame always shows a no-frame plain shape. I attach the code below. Please advise me what I missed. Thanks a lot.

    
    ====mframe.h=====
    
    class MFrame : public QFrame
    {
        Q_OBJECT
        
    public:
        explicit MFrame(QWidget *parent = 0);
        
        void paintEvent(QPaintEvent *);
    
    protected:
        bool event(QEvent *e);
    
    signals:
        void hoverEnter();
        void hoverMove();
        void hoverLeave();
    
    private:
    
    };
    
    
    ===== mframe.cpp=====
    
    MFrame::MFrame(QWidget *parent) :
        QFrame(parent)
    {
       setAttribute(Qt::WA_Hover);
    }
    
    bool MFrame::event(QEvent *e) {
        if (e->type() == QEvent::HoverEnter)
            emit hoverEnter();
        else if (e->type() == QEvent::HoverMove)
            emit hoverMove();
        else if (e->type() == QEvent::HoverLeave)
            emit hoverLeave();
        else {
            return false;
        }
        return true;
    }
    
    void MFrame::paintEvent(QPaintEvent *e)
    {
        QFrame::paintEvent(e);
    }
    
    
    =====in mainwidown.cpp=====
    
    ...
    connect(ui->frame, SIGNAL(hoverEnter()), this, SLOT(handleHoverEnter()));
    connect(ui->frame, SIGNAL(hoverMove()), this, SLOT(handleHoverMove()));
    connect(ui->frame, SIGNAL(hoverLeave()), this, SLOT(handleHoverLeave()));
    ....
    
    void MainWindow::handleHoverLeave()
    {
        if (m_hovered == 0)
            return;
    
        qDebug() << "hoverLeave";
        ui->frame->setStyleSheet("");
        ui->label->hide();
        m_hovered = 0;
    }
    
    void MainWindow::handleHoverMove()
    {
        if (m_hovered == 1)
            return;
    
        qDebug() << "hoverMove";
        m_hovered = 1;
        QString sty = "background-color: #00ff00;";
        ui->frame->setStyleSheet(sty);
        ui->label->show();
    }
    
    void MainWindow::handleHoverEnter()
    {
        if (m_hovered == 1)
            return;
    
        qDebug() << "hoverEnter";
        m_hovered = 1;
        QString sty = "background-color: #00ff00;";
        ui->frame->setStyleSheet(sty);
        ui->label->show();
    }
    
    

  • Qt Champions 2016

    hi
    I think you paint is not called as its normally
    protected and yours are placed in public.
    However Since you don't call
    QFrame::event(e);
    in MFrame::event(QEvent *e)

    you are eating the paint events that the parent frame would get.

    There is no need for custom paint. ( unless u need to add extra painting)

    bool MFrame::event(QEvent *e) {
        if (e->type() == QEvent::HoverEnter)
            emit hoverEnter();
        else if (e->type() == QEvent::HoverMove)
            emit hoverMove();
        else if (e->type() == QEvent::HoverLeave)
            emit hoverLeave();
        else {
             QFrame::event(e); <<<< let parent handle paint
            return false;
        }
      
        return true;
    
    }
    

  • Moderators

    @mrjj There's no overloading on access specifiers in c++ so it doesn't matter if it's public, protected, or even private.

    @stuartx Nevertheless it's a good practice to put overridekeyword on your virtual method overrides. It will save you from wasted time debugging typos. Another unrelated thing is you should not return true from your event like that. It prevents correct passing hover events between parents and children. It doesn't matter that you emit a custom signal, you should still return false and let Qt handle it, i.e.

    bool MFrame::event(QEvent* e) {
        if (e->type() == QEvent::HoverEnter)
            emit hoverEnter();
        else if (e->type() == QEvent::HoverMove)
            emit hoverMove();
        else if (e->type() == QEvent::HoverLeave)
            emit hoverLeave();
        
        return QFrame::event(e);
    }
    

    Back to the point. The code you shown doesn't have any obvious problems related to painting. Do you promote your widget in the designer? What shape and shadow value do you set? Is that all the stylesheets you use? Some (like border) can interact with the frame properties and override/disable them.


  • Qt Champions 2016

    Hi
    I know, was badly written.
    What I meant is that it seems he eats all paints events
    so his paint is never called. Nor his or parent's.
    as I show in the modified code.

    I tried the code and with QFrame::event(e);
    and promoted widget it starts drawing.

    Before nothing was shown so I assume his
    MFrame::event(QEvent* e) was to blame.
    (it has no QFrame::event(e);)

    Was i wrong?


  • Moderators

    @mrjj Seems the OP modified his post. I haven't seen the first version, so what you said might have very well be the issue.


  • Qt Champions 2016

    well the first version is
    ...
    else if (e->type() == QEvent::HoverLeave)
    emit hoverLeave();
    else {
    return false; << here is the bad part, correct?

    Ok. I was just suddenly confused. Thank you.



  • @Chris Kawa and @mrjj: thanks for the response.

    Based on your advice, I removed the paintEvent(QPaintEvent *) from the Frame class; I couldn't add override keyword before event() since my compiler is not c++11 capable; I return QFrame::event(e) in the overloaded function:

    bool MFrame::event(QEvent* e) {
    ....
    return QFrame::event(e);
    }

    But the frame shape is still not drawn.

    I promoted the QFrame to MFrame in the designer. In the designer I set frameShape=Box, frameShadow=raised, and the lineWidth=4. I only used the stylesheet in the following way:

    in hoverEnter:
    QString sty = "background-color: #00ff00;";
    ui->frame->setStyleSheet(sty);

    in hoverLeave:
    ui->frame->setStyleSheet("");

    Please let me know if you need more information from me. In addition, I edited my OP once, only changed a typo in title.

    Thanks.



  • Hi Guys, It works. I forget to remove
    ...
    else {
    return false;
    }

    in bool MFrame::event(QEvent* e).

    The function "bool MFrame::event(QEvent* e)" returns QFrame::event(e) is the fix.

    Thanks a lot.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.