1.鼠标放在控件或者提示框本身,提示框都显示
2.鼠标离开,延时500ms消失
3.鼠标移动到另一控件上,显示另一个带三角提示框,上一个提示框立即消失
4.扣掉三角两边的区域,鼠标移入提示框不显示
5.中间可以插入widget(qwidget包含qlabel,qframe等)
#ifndef TRIANGLEDIALOG_H
#define TRIANGLEDIALOG_H
#include<QEvent>
#include <QWidget>
#include <QHBoxLayout>
#include <QVector2D>
#include <QMouseEvent>
class TriangleDialog : public QWidget
{
Q_OBJECT
public:
//小三角显示的起始位置,三角左点距离左边长,三角宽高,矩形宽高,内嵌,响应控件rect,parent
TriangleDialog(int startXtoleft,int Triawidth, int Triaheight,int Rectwidth, int Rectheight,QWidget* widget,QRect ,QWidget *parent = nullptr);
~TriangleDialog();
// 设置小三角起始位置;
void setStartXtoleft(int startXtoleft);
// 设置小三角宽和高;
void setTriangleInfo(int width, int height);
void setRectInfo(int width, int height);
// 设置中间区域widget;
void setCenterWidget(QWidget* widget);
void calculateGeometry(QRect parentRect);
protected:
void paintEvent(QPaintEvent *);
// void enterEvent(QEvent *even);
void leaveEvent(QEvent *even);
void mouseMoveEvent(QMouseEvent *event);
bool pointInTriangle(QVector2D A, QVector2D B, QVector2D C, QVector2D P);
bool pointInRect(QRect parent_Rect, QVector2D P);
signals:
void signal_TriangleDlgshow(int );
private slots:
void Hide();
void onHide();
void onHide(int);
void Show();
private:
// 小三角起始位置;
int m_startX;
int m_startY;
int m_startXtoleft;
// 小三角的宽度;
int m_triangleWidth;
int m_triangleHeight;
int m_RectWidth;
int m_RectHeight;
QRect m_parentRect;
QRect m_rect;
QWidget *m_widget;
QHBoxLayout* hMainLayout;
QTimer *time;
int waitTime;
int margin_left;
int margin_top;
int margin_right;
int margin_bottom;
};
#endif // WIDGET_H
#include "triangleDialog.h"
#include <QHBoxLayout>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include <QTime>
#include <QTimer>
#define SHADOW_WIDTH 8 // 窗口阴影宽度;
#define BORDER_RADIUS 2 // 窗口边角的弧度;
//三角左点距离左边长,三角宽高,矩形宽高,内嵌,响应控件rect,parent
TriangleDialog::TriangleDialog(int startXtoleft,int Triawidth, int Triaheight,int Rectwidth, int Rectheight,QWidget* widget,QRect parentRect,QWidget *parent): QWidget(parent)
{
setWindowFlags(Qt::Widget | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_TranslucentBackground,true);
waitTime=500;
hMainLayout = new QHBoxLayout(this);
margin_left=(Rectwidth-widget->geometry().width())/2;
margin_top=(Rectheight-widget->geometry().height())/2+Triaheight-SHADOW_WIDTH/2;
margin_right=Rectwidth-widget->geometry().width()-margin_left;
margin_bottom=Rectheight-widget->geometry().height()-margin_top;
hMainLayout->setContentsMargins(margin_left, margin_top,margin_right, margin_bottom);
hMainLayout->setAlignment(this,Qt::AlignCenter);
// 设置阴影边框;
auto shadowEffect = new QGraphicsDropShadowEffect(this);
shadowEffect->setOffset(0, 0);
shadowEffect->setColor(Qt::gray);
shadowEffect->setBlurRadius(SHADOW_WIDTH);
this->setGraphicsEffect(shadowEffect);
m_startX=startXtoleft+Triawidth/2;
m_startY=0;
setStartXtoleft(startXtoleft);
setTriangleInfo(Triawidth, Triaheight);
setRectInfo(Rectwidth, Rectheight);
calculateGeometry(parentRect);
m_parentRect=parentRect;
setCenterWidget(widget);
m_widget=widget;
time= new QTimer();
connect(time, SIGNAL(timeout()), this, SLOT(Hide()));
setMouseTracking(true);
// time->start(1000);
}
TriangleDialog::~TriangleDialog()
{
}
// 小三角相对左边位置
void TriangleDialog::setStartXtoleft(int startXtoleft)
{
m_startXtoleft = startXtoleft;
}
// 设置小三角宽高
void TriangleDialog::setTriangleInfo(int width, int height)
{
m_triangleWidth = width;
m_triangleHeight = height;
}
// 设置矩形宽高
void TriangleDialog::setRectInfo(int width, int height)
{
m_RectWidth = width;
m_RectHeight = height;
}
//计算整个widget的Geometry
void TriangleDialog::calculateGeometry(QRect parentRect)
{
int x = parentRect.x()+parentRect.width()/2-m_startXtoleft-m_triangleWidth/2+6;
int y=parentRect.y()+parentRect.height()+12;
int width = m_RectWidth;
int height = m_RectHeight+m_triangleHeight;
this->move(x,y);
this->resize(width, height);
}
//加widget
void TriangleDialog::setCenterWidget(QWidget* widget)
{
hMainLayout->addWidget(widget);
}
bool TriangleDialog::pointInTriangle(QVector2D A, QVector2D B, QVector2D C, QVector2D P)
{
QVector2D v0 = C - A;
QVector2D v1 = B - A;
QVector2D v2 = P - A;
float dot00 = QVector2D::dotProduct(v0, v0);
float dot01 = QVector2D::dotProduct(v0, v1);
float dot02 = QVector2D::dotProduct(v0, v2);
float dot11 = QVector2D::dotProduct(v1, v1);
float dot12 = QVector2D::dotProduct(v1, v2);
float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * inverDeno ;
if (u < 0 || u > 1) // if u out of range, return directly
{
return false;
}
float v = (dot00 * dot12 - dot01 * dot02) * inverDeno ;
if (v < 0 || v > 1) // if v out of range, return directly
{
return false;
}
return u + v <= 1;
}
bool TriangleDialog::pointInRect(QRect parent_Rect, QVector2D P)
{
if(P.x()>parent_Rect.x()
&&P.y()>parent_Rect.y()
&&P.x()<parent_Rect.x()+parent_Rect.width()
&&P.y()<parent_Rect.y()+parent_Rect.height())
{
return true;
}
else
{
return false;
}
}
void TriangleDialog::Hide()
{
hide();
}
void TriangleDialog::onHide()
{
time->start(waitTime);
}
void TriangleDialog::onHide(int close_time)
{
time->start(close_time);
}
void TriangleDialog::Show()
{
time->stop();
show();
emit signal_TriangleDlgshow(0);
}
void TriangleDialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(255, 255, 255));
// 小三角区域;
QPolygon trianglePolygon;
trianglePolygon << QPoint(m_startX , m_startY );
trianglePolygon << QPoint(m_startX + m_triangleWidth / 2, m_startY + m_triangleHeight );
trianglePolygon << QPoint(m_startX - m_triangleWidth / 2, m_startY + m_triangleHeight );
//矩形
QPainterPath drawPath;
drawPath.addRoundedRect(QRect(m_startX - m_startXtoleft-m_triangleWidth / 2, m_startY + m_triangleHeight,\
m_RectWidth, m_RectHeight),\
BORDER_RADIUS, BORDER_RADIUS);
// Rect + Triangle;
drawPath.addPolygon(trianglePolygon);
painter.drawPath(drawPath);
}
void TriangleDialog::mouseMoveEvent(QMouseEvent *event)
{
float P_X = event->x();
float P_Y = event->y();
m_rect=QRect(0,m_triangleHeight,m_RectWidth,m_RectHeight);
if(pointInTriangle(QVector2D(m_startX , m_startY),\
QVector2D(m_startX + m_triangleWidth / 2, m_startY + m_triangleHeight),QVector2D(m_startX - m_triangleWidth / 2, m_startY + m_triangleHeight),QVector2D(P_X,P_Y))
||pointInRect(m_rect, QVector2D(event->x(),event->y())) //
||m_widget->geometry().contains(QPoint(P_X,P_Y)))
{
time->stop();
this->show();
}
else
{
time->start(waitTime);
}
}
//void TriangleDialog::enterEvent(QEvent *even)
//{
// time->stop();
// this->show();
//}
void TriangleDialog::leaveEvent(QEvent *even)
{
time->start(waitTime);
}
使用:
Q_SIGNALS:
void sigSetFileShowtriangleDlg();
void sigSetFileHidetriangleDlg( );
void sigQQShowtriangleDlg();
void sigQQHidetriangleDlg();
private slots:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::UpLoad *ui;
TriangleDialog *setfileDialog;
TriangleDialog *qqDialog;
QQWidget *qqwidget;
int waitTime;
bool mouse_is_press; //鼠标是否按下
QPoint mouse_move_len; //鼠标移动事件中,移动的距离
QPoint mouseStartPoint;
QLabel *setfilelabel;
void UpLoad::InitTitleBar()
{
ui->setfileButton->installEventFilter(this); //安装事件过滤器
ui->qqButton->installEventFilter(this); //安装事件过滤器
setfilelabel=new QLabel("111");
setfilelabel->setWordWrap(true);
setfilelabel->setObjectName("setfilelabel");
setfilelabel->setFixedSize(115,44);
//三角左点距离左边长,三角宽高,矩形宽高,内嵌,响应控件rect,parent
setfileDialog=new TriangleDialog(16,16,8,147,60,setfilelabel,
QRect(ui->setfileButton->geometry().x(),ui->setfileButton->geometry().y(),ui->setfileButton->geometry().width(),ui->setfileButton->geometry().height()),
this);
connect(this, SIGNAL(sigSetFileShowtriangleDlg()), setfileDialog, SLOT(Show()));
connect(this, SIGNAL(sigSetFileHidetriangleDlg()), setfileDialog, SLOT(onHide()));
setfileDialog->hide();
qqwidget = new QQWidget();
qqwidget->setObjectName("QQWidget");
qqwidget->setStyleSheet("QQWidget#QQWidget{background-color:#FFFFFF;border:1px solid #DADADA;}");
qqwidget->setWindowFlags (Qt::FramelessWindowHint| Qt::Popup);//
qqDialog=new TriangleDialog(16,16,8,198,266,qqwidget,
QRect(ui->qqButton->geometry().x(),ui->qqButton->geometry().y(),ui->qqButton->geometry().width(),ui->qqButton->geometry().height()),
this);
connect(this, SIGNAL(sigQQShowtriangleDlg()), qqDialog, SLOT(Show()));
connect(this, SIGNAL(sigQQHidetriangleDlg()), qqDialog, SLOT(onHide()));
connect(qqDialog, SIGNAL(signal_TriangleDlgshow(int )), setfileDialog, SLOT(onHide(int )));
connect(setfileDialog, SIGNAL(signal_TriangleDlgshow(int )), qqDialog, SLOT(onHide(int )));
qqDialog->hide();
}
bool UpLoad::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->setfileButton) {
if(event->type() == QEvent::Enter) {//QEvent::HoverEnter,QEvent::HoverLeave
emit sigSetFileShowtriangleDlg();
return true;
}
if(event->type() == QEvent::Leave)
{
emit sigSetFileHidetriangleDlg();
return true;
}
return QWidget::eventFilter(obj,event);
}
if(obj == ui->qqButton) {
if(event->type() == QEvent::Enter) {//QEvent::HoverEnter,QEvent::HoverLeave
emit sigQQShowtriangleDlg();
return true;
}
if(event->type() == QEvent::Leave)
{
emit sigQQHidetriangleDlg();
return true;
}
return QWidget::eventFilter(obj,event);
}
}