操作:
鼠标hover于Btn(or other widget),在指定位置显示想要的widget(或其他控件窗口)
方法:重载以下几个api
void paintEvent(QPaintEvent *); //由于重载QPushbutton,normal, hover, pressed 按钮的状态需要重新设定
void enterEvent(QEvent*event); //鼠标进入的时候发送信号显示 diy widget
void leaveEvent(QEvent*event); //鼠标离开的时候发送信号隐藏 diy widget
实现:
类原型:
//构造的时候需要将normal,hover, pressed的状态的图片,其他多余的为扩展,taskPix为任务图标类似QQ消息右上角的小红点,当然也可以自己画
class MyBtn :public QPushButton {
Q_OBJECT
public:
MyBtn(QWidget *parent, QString Text, QPixmap NorPix, QPixmap HoverTipsPix, QPixmap PressedTaskpix, QPixmap TaskPix);
void init();
void SetTaskCounts(int counts) { TaskCounts = counts; }
void setCurrenPix(QPixmap pix) { CurrenPix = pix; }
QTimer *pTimer; //鼠标进入的时候,需要计时器100ms去将获取全局的鼠标位置发给需要显示的Widget
protected:
void paintEvent(QPaintEvent *);
void enterEvent(QEvent*event);
void leaveEvent(QEvent*event);
bool eventFilter(QObject *obj, QEvent *event); //可能要用到的过滤,
private:
int TaskCounts;
QPixmap TaskPix;
QPixmap NorPix;
QPixmap HoverPix;
QPixmap PressPix;
QPixmap CurrenPix;
QLabel *TipsLbl; //需要显示的wigdet 其中构造的Text是放在这里
QWidget *TipsWgt; //需要显示的widget
QGridLayout *TipsLyt;
public slots:
void slot_showWgt(QPoint);
void slot_updateTasks(int tasks); //随着消息的变动更新 Taskcounts
signals:
void sig_showWgt(QPoint); //发送消息通知要显示的widget
void sig_hideWgt(); //发送消息通知要隐藏的widget
};
//构造这里初始化基本的数据
MyBtn::MyBtn(QWidget *parent, QString Text, QPixmap NormalPix, QPixmap HoverTipsPix, QPixmap PressedTaskpix, QPixmap TasksPix) :
QPushButton(parent)
{
init();
NorPix = NormalPix;
CurrenPix = NormalPix;
HoverPix = HoverTipsPix;
PressPix = PressedTaskpix;
PressPix = NorPix;
TaskPix = TasksPix;
TipsLbl->setText(Text);
}
void MyBtn::init()
{
pTimer = new QTimer(this);
TaskCounts = 0;
TipsWgt = new QWidget;
TipsLbl = new QLabel(TipsWgt);
TipsLyt = new QGridLayout(TipsWgt);
TipsLyt->addWidget(TipsLbl);
TipsWgt->setWindowFlags(Qt::FramelessWindowHint);
TipsWgt->setStyleSheet("background-color: transparent");
TipsWgt->setAutoFillBackground(false);
TipsWgt->setAttribute(Qt::WA_TranslucentBackground);
TipsLbl->setStyleSheet("QLabel{border-image: url(:/SprintPlot/image/menuWhatis.png);color:white;}");
TipsLbl->resize(80, 40);
QPixmap pix(":/SprintPlot/image/menuWhatis.png");
TipsLbl->setFixedSize(pix.size());
TipsLbl->setAlignment(Qt::AlignCenter);
TipsWgt->resize(80, 40);
connect(this, &MyBtn::sig_showWgt, this, &MyBtn::slot_showWgt);
}
//绘画事件,即重点,把需要的效果重新画出来包括数据
void MyBtn::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.drawPixmap(QRect(this->rect().x() + this->width() / 4 - 3, this->rect().y()+10, 24, 24), CurrenPix);
painter.setPen(Qt::white);
if (TaskCounts > 99)
{
painter.drawPixmap(QRect(QPoint(this->x() + 20, 0), QSize(22, 22)), TaskPix);
painter.drawText(QRect(QPoint(this->x() + 22, 2), QSize(18, 18)), Qt::AlignVCenter, QString::number(99) + "+");
}
else if (TaskCounts)
{
painter.drawPixmap(QRect(QPoint(this->x()+ 20, 0), QSize(18, 18)), TaskPix);
painter.drawText(QRect(QPoint(this->x() + 23, 3), QSize(12, 12)), Qt::AlignCenter, QString::number(TaskCounts));
}
else
{
update();
}
}
//鼠标进入事件这里获取鼠标的坐标
void MyBtn::enterEvent(QEvent *event)
{
CurrenPix = HoverPix;
pTimer->stop();
QPoint oPoint = this->mapToGlobal(QPoint(this->x() - 90, 0));
emit sig_showWgt(oPoint);
}
//鼠标离开事件这里获取鼠标的全局坐标,注意需要转换成小部件的坐标的时候需要调整
void MyBtn::leaveEvent(QEvent *event)
{
CurrenPix = NorPix;
pTimer->start(100);
TipsWgt->hide();
}
//事件筛选,根据自己需求自己筛吧
bool MyBtn::eventFilter(QObject *target, QEvent *event)
{
if (target == this&&event->type() == QEvent::Enter)
{
CurrenPix = HoverPix;
}
else if (target == this&&event->type() == QEvent::MouseButtonPress)
{
CurrenPix = PressPix;
}
else if (target == this&&event->type() == QEvent::Leave)
{
CurrenPix = NorPix;
}
else
{
return true;
}
return QPushButton::eventFilter(target, event);
}
//在自定义位置显示自定义的Wgt
void MyBtn::slot_showWgt(QPoint oPoint)
{
TipsWgt->move(oPoint);
TipsWgt->show();
}
//更新Btn上的task数量
void MyBtn::slot_updateTasks(int tasks)
{
TaskCounts = tasks;
}
效果截图:
注意如果要鼠标进入浮窗不消失的话,需要自己实现这个浮窗,重写enterevent()判断全局鼠标位置
然后在确定是不是要隐藏窗口,类似于QQ的资料卡。有问题可以博客私聊回复。