Qt实现半透明、无边框、可自由移动、不规则的窗体
预期效果
功能要点
-
窗口无边框 可自由拖动 背景透明度自定义 边框可设置为异形
实现步骤
第1步:新建一个QWidget的子类,这里命名为BaseWidget
第2步:设置关键成员
private: QRect m_areaMovable;//可移动窗口的区域,鼠标只有在该区域按下才能移动窗口 bool m_bPressed;//鼠标按下标志(不分左右键) QPoint m_ptPress;//鼠标按下的初始位置
第3步:实现三个虚函数
(1)头文件里添加以下代码
protected: void mousePressEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e);
(2) cpp文件添加
BaseWidget::BaseWidget(QWidget *parent) : QWidget(parent) { //设置无边框透明 setWindowFlags(Qt::FramelessWindowHint|Qt::Tool);//无边框 this->setStyleSheet(QString("background-color: rgb(0, 255, 0);")); m_bPressed = false; } void BaseWidget::setAreaMovable(const QRect rt) { if(m_areaMovable != rt) { m_areaMovable = rt; } } void BaseWidget::mousePressEvent(QMouseEvent *e) { //鼠标左键 if(e->button() == Qt::LeftButton) { m_ptPress = e->pos(); m_bPressed = m_areaMovable.contains(m_ptPress); setAreaMovable(this->rect()); } } void BaseWidget::mouseMoveEvent(QMouseEvent *e) { if(m_bPressed) { move(pos() + e->pos() - m_ptPress); } } void BaseWidget::mouseReleaseEvent(QMouseEvent *e) { m_bPressed = false; }
在MainWindow.cpp中使用:
bsw = new BaseWidget(this); bsw->resize(100,100); bsw->show();
以上代码可以实现:无边框、透明、可拖动
但是呢,鼠标只有落在左上角区域时才能拖动,于是改进一步:
void BaseWidget::showEvent(QShowEvent *) { setAreaMovable(this->rect()); }
这样就可以实现点击窗体的任何处进行拖动啦
进一步扩展应用
不过可能有人的需求是实现异形窗口,我的demo思路是:新建一个QLabel 子类,然后设置窗口背景透明,添加一个png图片。
异形无边框半透明窗口实现如下:
第1步:在作图软件中制作一张大小合适的png图片
第2步:读取图片并显示到控件上
在构造函数里添加:
QImage img; img.load("arrowhead.png"); this->setPixmap(QPixmap::fromImage(img));
最终效果如下:
在分享代码之前,想先分享总结:
第1个坑:原本我是想把控件设置为悬浮的,于是新建了QDialog子类还设置了setWindowFlags(Qt::Popup),但是这样一来,这个窗口的优先级就凌驾于其他所有窗口以及所有控件之上,意味着,这个不能点击关闭的窗口还拦着我不让我与其他控件 产生交互。
后来使用了Qt::Tool这个flag,情况好转。
第2个坑:在往QLabel子类中设置图片时,使用了
QPicture temp; temp.load("arrowhead.png"); this->setPixmap(temp);
但是出现了报错:QPicturePaintEngine::checkFormat: Incorrect header
我现在不是很懂这是为啥……【擦汗】,但是我找到了可以绕开它达成目的的方法:
QImage img; img.load("arrowhead.png"); this->setPixmap(QPixmap::fromImage(img));
说完两个坑之后,向大家推荐一款免费的录屏软件,可以制作成gif图~网址如下
最后,结尾了,感谢网上那些无私分享技术的人,本次学习参考了以下关键博文:
最后,我的demo代码传送门:
更新:2018-10-08 19:44
设置了“Tool”的flag之后,它的pos()指的是相对于整个屏幕左上角的坐标,而不是相对于父容器的坐标。如果想要知道其相对于父容器的坐标,还得知道父容器相对于整个屏幕的坐标。