Search code examples
c++qtmouseeventpaintevent

Show tooltip at mouse position and show legend on top-right corner


The following toy problem show two tabs, each tab contains a QGridLayout, which has a ScrollArea on one of the cells, which in turn contains a customized QLabel (MyLabel). When the user moves his mouse on the customzied QLabel, a tooltip shows up for several seconds.

test.pro

QT += core gui widgets

CONFIG += c++17
CONFIG += debug
QMAKE_CXXFLAGS += -std=c++17

SOURCES += \
    test.cpp

QMAKE_CLEAN += $$TARGET Makefile

HEADERS += \
    mywidget.h

test.cpp

#include "mywidget.h"
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyMainWindow myMainWindow;
    myMainWindow.show();
    return a.exec();
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QDebug>
#include <QWidget>
#include <QMdiArea>
#include <QMainWindow>
#include <QScrollArea>
#include <QLabel>
#include <QGridLayout>
#include <QMouseEvent>
#include <QToolTip>

class MyLabel : public QLabel
{
    Q_OBJECT
public:
    MyLabel(QWidget *parent=nullptr, const QString &name="")
        : QLabel(parent), m_name(name)
    {
        resize(1800, 1200);
        setMouseTracking(true);
    }
private:
    void mouseMoveEvent(QMouseEvent *ev) override {
        QToolTip::showText(
                    ev->globalPosition().toPoint()
                    , m_name + ": " + QString::number(ev->pos().x()) + ", " + QString::number(ev->pos().y())
                );

        QLabel::mouseMoveEvent(ev);
    }
private:
    QString m_name;
};

class MyWidget : public QWidget
{
    Q_OBJECT
public:
    MyWidget(QWidget* parent = nullptr, const QString &name="")
        : QWidget(parent), m_name(name)
    {
        setWindowTitle(name);
        m_gridLayout = new QGridLayout(this);
        this->setLayout(m_gridLayout);

        // layout col 1
        m_gridLayout->addWidget(new QLabel("smaller label", this), 0, 0);

        // layout col 2
        m_scrollArea = new QScrollArea(this);
        MyLabel *label = new MyLabel(this, m_name);
        m_scrollArea->setWidget(label);
        m_gridLayout->addWidget(m_scrollArea, 0, 1);
    }

private:
    QString m_name;
    QGridLayout *m_gridLayout;
    QScrollArea *m_scrollArea;
};

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget* parent = nullptr)
        : QMainWindow(parent)
    {
        m_mdiArea = new QMdiArea(this);
        this->setCentralWidget(m_mdiArea);

        MyWidget *myWidget1 = new MyWidget(this, "widget 1");
        m_mdiArea->addSubWindow(myWidget1);

        MyWidget *myWidget2 = new MyWidget(this, "widget 2");
        m_mdiArea->addSubWindow(myWidget2);

        m_mdiArea->setViewMode(QMdiArea::ViewMode::TabbedView);
    }

private:
    QMdiArea *m_mdiArea;
};

#endif // MYWIDGET_H

Here are two problems that I am struggling with:

  1. How can I show the tooltip without moving my mouse when I toggle between those two tabs by Ctrl+Tab? In my real-world problem, I use the tooltip show information about data at the mouse point.
  2. Is it possible show some legends on the top-right corner of the viewport of the QScollArea, regardless of the positions of the scoll bars? I am trying with paintEvent, but had difficulties get the position adjusting according to scoll bars.

Solution

  • Cursor position can be retrieved by using QCursor::pos(), so both problems can be solved by using QCursor::pos() in paintEvent. I was confused by the fact paintEvent() does not directly provide cursor position, as mouseMoveEvent() does.