user6083685
user6083685

Reputation:

How to create qt label hover effect?

I must use hover event on Qt label, but I can't found no information about that. I try use something like ui->label->setText("<a>ads</a>") and onLinkHovered but it's not work correct.

I must change text on hover.

Upvotes: 3

Views: 11414

Answers (4)

Adam Sirrelle
Adam Sirrelle

Reputation: 397

I have found that you can also achieve this through the style sheet.

self.label = QtWidgets.QLabel("Toast")
self.label.setStyleSheet("QLabel{color: white;} QLabel:hover {color: blue;}")

Upvotes: 0

Binary Mind
Binary Mind

Reputation: 329

If you want to determine whether mouse hovers over text inside the QLabel you can use

void mouseMoveEvent(QMouseEvent* event);

and check inside it whether mouse cursor is in bounding rectangle of text.

void PressLabel::mouseMoveEvent(QMouseEvent* event) {
    QRect bRect = getTextComponentRectangle();
    m_mouseCoord = event->pos();
    if(bRect.contains(event->pos())) {
        // Mouse pointer over text.
    } else {
        // Mouse pointer outside text.
    }
    QLabel::mouseMoveEvent(event);
}

Turn on mouse tracking for your widget to make mouseMoveEvent occur also when mouse button is not pressed.

setMouseTracking(true);

And finally the function that does the calculation of text bounding rectangle. Code below take into account some unexpected cases, too. I tried it with Qt 5.9.1.

For calculation of effective indent in negative case refer to http://doc.qt.io/archives/qt-4.8/qlabel.html#indent-prop .

QRect PressLabel::getTextComponentRectangle() const {
     if(frameWidth() < 0) {
        throw std::runtime_error("Negative frame width.");
    }
    int effectiveIndent = indent();
    int trueMargin = margin();
    if(effectiveIndent < 0) {
        if(frameWidth() == 0 || margin() > 0) { // (1)
            effectiveIndent = 0;
        } else if(frameWidth() > 0) {
            QFontMetrics fm(font());
            effectiveIndent = fm.width(QChar('x')) / 2;
        }
        if(frameWidth() > 0 && margin() < 0) { // (2)
            trueMargin = 0;
        }
    }

    QFontMetrics fm(font());
    QRect bRect = fm.boundingRect(text());
    bRect.setWidth(fm.width(text()));

    int indentOffset = effectiveIndent + trueMargin + frameWidth();
    int offsetX = 0;
    int offsetY = 0;
    if(alignment() & Qt::AlignHCenter) {
        offsetX = rect().width() / 2 - bRect.width() / 2;
    } else if(alignment() & Qt::AlignRight) {
        offsetX = rect().width() - bRect.width() - indentOffset;
    } else if(alignment() & Qt::AlignJustify) {
        offsetX = trueMargin + frameWidth();
    } else if(alignment() & Qt::AlignLeft) {
        offsetX = indentOffset;
    }
    if(alignment() & Qt::AlignVCenter) {
        offsetY = rect().height() / 2 - bRect.height() / 2;
    } else if(alignment() & Qt::AlignBottom) {
        offsetY = rect().height() - bRect.height() - indentOffset;
    } else if(alignment() & Qt::AlignTop) {
        offsetY = indentOffset;
    }

    bRect.moveTopLeft(rect().topLeft());
    bRect.setX(bRect.x() + offsetX);
    bRect.setWidth(bRect.width() + offsetX);
    bRect.setY(bRect.y() + offsetY);
    bRect.setHeight(bRect.height() + offsetY);

    return bRect;
}

Unexpected cases:

(1) For indent < 0 and margin > 0 effective indent is 0, not width('x')/2 as it is intended to be for negative indent.

(2) For indent < 0 and margin < 0 true margin is 0 and isn't summed to make offset.

Upvotes: 0

Dusteh
Dusteh

Reputation: 1536

The most flexible solution would be to create your own widget which inherits from QLabel. This way, you could override the enterEvent and leaveEvent @Jeremy and @Moe are writing about which are protected. As a part of these methods implementation you could change the text or decoration accordingly. For example:

class CustomLabel : public QLabel
{
    Q_OBJECT
public:
    CustomLabel(QWidget* parent = nullptr) : QLabel(parent){ }

protected:
    void enterEvent(QEvent *ev) override
    {
        setStyleSheet("QLabel { background-color : blue; }");
    }

    void leaveEvent(QEvent *ev) override
    {
        setStyleSheet("QLabel { background-color : green; }");
    }
};

Another approach, but a lot less flexible would be to set the href attribute for the link tag you have specified in label text. This way text would be treated as actual link and you could use the linkHovered signal to connect to. For example:

ui->label->setText("<a href='www.google.com'>link</a>");
connect(ui->label, &QLabel::linkHovered, this, [this](const QString&)
{
    // do smth with the widget/text
});

However, please denote that this way you could only make a modification on the hover event. So if you need to bring the label back to its original state, the first option is the way to go.

Upvotes: 5

Mo Abdul-Hameed
Mo Abdul-Hameed

Reputation: 6110

Make use of enterEvent and leaveEvent of QLabel.

Create a subclass of QLabel like this for example:

class MyLabel : public QLabel
{
public:
    MyLabel();
    MyLabel(char* text, MainWindow* w) : QLabel(text, w) { }

    void enterEvent(QEvent *event);
    void leaveEvent(QEvent *event);
};

and override enterEvent and leaveEvent like this:

void MyLabel::enterEvent(QEvent *event) {

    qDebug() << "Entered!";
    // Change your text here
}

void MyLabel::leaveEvent(QEvent *event) {

    qDebug() << "Left!";
}

You can create instances of this class now like this:

MainWindow w;

MyLabel myLabel("A Test Label", &w);

Upvotes: 0

Related Questions