How to popup a widget when I hover a label?
-
There is a "volume label" that will pop up a vertical slider when I hover over it to control a media player's volume.
Should I reimplement a new label inheriting "QLabel"?
-
I finally completed it.
.h file#ifndef GCPLAYER_GCVOLLABEL_H_ #define GCPLAYER_GCVOLLABEL_H_ #include <QLabel> #include <QSlider> #include <QWidget> class __GCVolLabel_innerSlider; class __GCVolLabel_innerLabel; class GCVolLabel : public QWidget { Q_OBJECT public: explicit GCVolLabel(QWidget *parent = nullptr); void setPopupFixedSize(const QSize &size); void setPopupFixedSize(const int w, const int h); void setText(const QString &text); protected: virtual void showPopupSlider(); virtual void hidePopupSlider(); private: QPoint getGlobalPos(); private: bool m_isLabelHovered = false; bool m_isSliberHovered = false; __GCVolLabel_innerLabel *m_textLabel = nullptr; __GCVolLabel_innerSlider *m_popupSlider = nullptr; }; class __GCVolLabel_innerLabel : public QLabel { Q_OBJECT public: __GCVolLabel_innerLabel(QWidget *parent = nullptr); protected: void enterEvent(QEnterEvent *ev); void leaveEvent(QEvent *ev); signals: void hoveredIn(); void hoveredOut(); }; class __GCVolLabel_innerSlider : public QSlider { Q_OBJECT public: __GCVolLabel_innerSlider(QWidget *parent = nullptr); protected: void enterEvent(QEnterEvent *ev); void leaveEvent(QEvent *ev); signals: void hoveredIn(); void hoveredOut(); }; #endif // GCPLAYER_GCVOLLABEL_H_
.cpp file
#include <gcplayer/gcvollabel.h> #include <gcplayer/log.h> #include <QBrush> #include <QEvent> #include <QLabel> #include <QPainter> #include <QPen> #include <QSlider> #include <QTimer> GCVolLabel::GCVolLabel(QWidget *parent) : QWidget(parent), m_popupSlider(new __GCVolLabel_innerSlider(this)), m_textLabel(new __GCVolLabel_innerLabel(this)) { m_popupSlider->setWindowFlag(Qt::Popup); setPopupFixedSize(15, 70); m_popupSlider->hide(); connect(m_popupSlider, &__GCVolLabel_innerSlider::hoveredIn, [&] { m_isSliberHovered = true; showPopupSlider(); }); connect(m_popupSlider, &__GCVolLabel_innerSlider::hoveredOut, [&] { m_isSliberHovered = false; hidePopupSlider(); }); connect(m_textLabel, &__GCVolLabel_innerLabel::hoveredIn, [&] { m_isSliberHovered = true; showPopupSlider(); }); connect(m_textLabel, &__GCVolLabel_innerLabel::hoveredOut, [&] { m_isSliberHovered = false; hidePopupSlider(); }); } void GCVolLabel::showPopupSlider() { if (m_isSliberHovered || m_isLabelHovered) { QPoint pos = getGlobalPos(); pos = QPoint(pos.x(), pos.y() - m_popupSlider->height() - 5); m_popupSlider->move(pos); m_popupSlider->show(); } } void GCVolLabel::hidePopupSlider() { // The Most Important Code QTimer::singleShot(600, [&] { if (!m_isSliberHovered && !m_isSliberHovered) { m_popupSlider->hide(); } }); } QPoint GCVolLabel::getGlobalPos() { QPoint pos = mapToGlobal(QPoint(0, 0)); ldebug("GCVolLabel pos: (%d, %d)", pos.x(), pos.y()); return pos; } void GCVolLabel::setPopupFixedSize(const QSize &size) { m_popupSlider->setFixedSize(size); } void GCVolLabel::setPopupFixedSize(const int w, const int h) { m_popupSlider->setFixedSize(w, h); } void GCVolLabel::setText(const QString &text) { m_textLabel->setText(text); } // __GCVolLabel_innerLabel __GCVolLabel_innerLabel::__GCVolLabel_innerLabel(QWidget *parent) : QLabel(parent) {} void __GCVolLabel_innerLabel::enterEvent(QEnterEvent *ev) { emit hoveredIn(); } void __GCVolLabel_innerLabel::leaveEvent(QEvent *ev) { emit hoveredOut(); } // __GCVolLabel_innerSlider __GCVolLabel_innerSlider::__GCVolLabel_innerSlider(QWidget *parent) : QSlider(parent) {} void __GCVolLabel_innerSlider::enterEvent(QEnterEvent *ev) { emit hoveredIn(); } void __GCVolLabel_innerSlider::leaveEvent(QEvent *ev) { emit hoveredOut(); }
-
Hi,
I made a floating widget a while ago, it's a bit rough on the edges, but it could be helpful to your case.
It just needs a parent and a trigger, it'll do the rest on its own.
For a
QLabel
, you could use thelinkActivated
signal, since I believe clicking is a more controllable trigger compared to hovering, which could be triggered by mistake. But if you're determined on relying on mouse hover, you could uselinkHovered
instead.Here's an example:
#include <QApplication> #include <QSlider> #include <QLabel> #include "mfloatwidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); //style the link to make it look like normal text //and provide whatever text for the actual link, it'll be enough to trigger linkActivated QLabel label("<a style=\"color: white; text-decoration:none;\" href=\"someText\">100%</a>"); label.setAlignment(Qt::AlignCenter); MFloatWidget floatingWidget(&label); QSlider slider(Qt::Horizontal); //addWidget is a custom method to add widgets to the floating widget floatingWidget.addWidget(&slider); //clicking the label text will pop up the floating widget which contains the slider label.connect(&label, &QLabel::linkActivated, &floatingWidget, &QWidget::show); label.show(); return a.exec(); }
You can find some explanation about the custom widget on my blog: How to make a floating widget in Qt, and the link to the public repository if this is useful/useable.
-