I have implemented a custom cursor in C++ using the Qt 5.15 toolkit, as shown in this small test program containing three classes:
A mainwindow, a testwidget and a box.
The testwidget and box are both subclasses of QLabel.
The mainwindow contains the testwidget, the testwidget captures mouse events which move the box to follow the mouse.
QtCursorExample.h
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
class CTestWidget;
class CMainWindow;
class CBox : public QLabel
{
Q_OBJECT
public:
CBox(CTestWidget *parent);
void followMouse(void);
void mouseEntered(bool enter) { mouseEnteredFlag=enter;}
private:
bool mouseEnteredFlag;
};
class CTestWidget : public QLabel
{
Q_OBJECT
public:
CTestWidget(CMainWindow *parent);
protected:
void mouseMoveEvent(QMouseEvent *event);
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
private:
CBox *box;
};
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent=0);
private:
CTestWidget *widget;
};
QtCursorExample.cpp
#include <QApplication>
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
#include <QMouseEvent>
#include "QtCursorExample.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
CMainWindow window;
window.show();
return app.exec();
}
CMainWindow::CMainWindow(QWidget *parent) : QMainWindow(parent)
{
widget=new CTestWidget(this);
setCentralWidget(widget);
resize(400,400);
move(100,100);
}
CTestWidget::CTestWidget(CMainWindow *parent) : QLabel(parent)
{
setMouseTracking(true); //receive mouse events even when no buttons are pressed
box=new CBox(this); //box attached to the cursor
setStyleSheet("background-color: yellow;");
setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
setText("THIS IS A TEST");
setMinimumSize(200,200);
setMaximumSize(200,200);
}
void CTestWidget::enterEvent(QEvent *event)
{
box->show();
box->mouseEntered(true);
event->accept();
}
void CTestWidget::leaveEvent(QEvent *event)
{
box->hide();
box->mouseEntered(false);
event->accept();
}
void CTestWidget::mouseMoveEvent(QMouseEvent *event)
{
box->followMouse();
event->accept();
}
CBox::CBox(CTestWidget *parent) : QLabel(parent)
{
mouseEnteredFlag=false;
setWindowFlags(Qt::CustomizeWindowHint|Qt::FramelessWindowHint|Qt::Tool);
setAttribute(Qt::WA_TranslucentBackground); //see through
setFrameShape(QFrame::Box);
setAlignment(Qt::AlignCenter);
setLineWidth(2);
setMinimumSize(15,15);
setMaximumSize(15,15);
}
void CBox::followMouse(void)
{
if(mouseEnteredFlag==true)
{
QPoint globalCursorPos=QCursor::pos();
//centre the box on cursor position
globalCursorPos.setX(globalCursorPos.x()-10/2);
globalCursorPos.setY(globalCursorPos.y()-10/2);
move(globalCursorPos);
}
}
PRO file
TARGET = QtCursorExample
TEMPLATE = app
CONFIG += qt
QT += widgets
SOURCES = QtCursorExample.cpp
HEADERS = QtCursorExample.h
QMAKE_CXXFLAGS += -Wall
However, even when the mouse is not moved, the box is continually redrawn and flickers constantly.
I have also tried setting the cursor to Qt::BlankCursor, but this has no effect, the box flickers constantly.
Any advice?
Edited according to recommendations. I did not erase the previous version.
#include <QLabel>
#include <QMouseEvent>
#include <QGridLayout>
using BaseClass= QWidget;
class CTestWidget : public BaseClass
{
Q_OBJECT
private:
QLabel *box, *pix;
public:
using BaseClass::BaseClass;
CTestWidget(QWidget *parent=nullptr) : BaseClass(parent)
{
setMouseTracking(true);
setFixedSize(200,200);
pix=new QLabel;
pix->setStyleSheet("background-color: yellow;");
pix->setAlignment(Qt::AlignCenter);
pix->setText("THIS IS A TEST");
pix->setAttribute(Qt::WA_TransparentForMouseEvents,true);
box=new QLabel(pix);
box->hide();
box->setAttribute(Qt::WA_TranslucentBackground,true);
box->setAttribute(Qt::WA_TransparentForMouseEvents,true);
box->setFrameShape(QFrame::Box);
box->setLineWidth(2);
box->setFixedSize(15,15);
auto layout=new QGridLayout;
setLayout(layout);
layout->addWidget(pix, 0,0);
}
protected:
void enterEvent(QEnterEvent *event)override{
BaseClass::enterEvent(event);
box->show();
}
void leaveEvent(QEvent *event)override{
BaseClass::leaveEvent(event);
box->hide();
}
void mouseMoveEvent(QMouseEvent *event)override{
BaseClass::mouseMoveEvent(event);
setUpdatesEnabled(false);
box->move(pix->mapFromGlobal(event->globalPos() - box->rect().center()));
setUpdatesEnabled(true);
}
};