声明:本文仅用于用qt学习todesk界面设计;
如下左图有一排扩展功能的菜单,鼠标滑块会显示带三角形的提示框,本文将用qt实现如右图:
1、布局按钮
直接拖拽出QPushButton,7个,分别设置默认样式和划过样式,如下样式表:
2、实现带三角形的提示框
显然这种带箭头的提示窗口,不是常规窗口,需要用户自己来绘制三角形,这里以QWidget作为基类实现:
triangleDialog.h
#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(QEnterEvent *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
triangleDialog.cpp
#include "triangleDialog.h"
#include "triangleDialog.h"
#include <QHBoxLayout>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include <QTime>
#include <QTimer>
#include <QPainterPath>
#include <QStylePainter>
#include <QStyleOption>
#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();
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 *)
{
QStyleOption opt;
opt.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
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);
}
3、调用带三角的提示框及在提示框内加入widget
mainwindow.h 需要两部分,三角形提示框和重写事件处理部分
mainwindow.cpp 需要两部分:
一部分处理窗口及样式;
另一部分重写事件处理eventFilter;
ui->pushButton_7->installEventFilter(this); //安装事件过滤器
qwidgetOther = new QWidget(this);
qwidgetOther->setObjectName("qwidgetOther");
qwidgetOther->setWindowFlags (Qt::FramelessWindowHint| Qt::Popup);
qwidgetOther->resize(404,531);
DialogOther=new TriangleDialog(16,16,8,404,531,qwidgetOther,
QRect(ui->pushButton_7->geometry().x()+ui->frame->geometry().x(),ui->pushButton_7->geometry().y()+ui->frame->geometry().y(),ui->pushButton_7->geometry().width(),ui->pushButton_7->geometry().height()),
this);
DialogOther->setStyleSheet("QWidget#qwidgetOther{background-image:url(:/resource/otherContent.png);border:0;}"\
"QWidget{border-radius:5px;}");
DialogOther->hide();
4、运行演示