新增无边框方案项目

master
feiyangqingyun 2021-07-27 15:35:23 +08:00
parent a4c35ec100
commit 47daf5e186
39 changed files with 3487 additions and 4 deletions

BIN
0snap/frameless.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -1,6 +1,8 @@
TEMPLATE = subdirs TEMPLATE = subdirs
#定义了ordered表示子项目按照添加的顺序来编译 #定义了ordered表示子项目按照添加的顺序来编译
CONFIG += ordered CONFIG += ordered
#挨个添加子项目
SUBDIRS += lightbutton #高亮按钮控件 SUBDIRS += lightbutton #高亮按钮控件
SUBDIRS += movewidget #通用控件移动类 SUBDIRS += movewidget #通用控件移动类
SUBDIRS += flatui #模仿flatui类 SUBDIRS += flatui #模仿flatui类
@ -35,7 +37,9 @@ SUBDIRS += imageswitch #图片开关控件
SUBDIRS += netserver #网络中转服务器 SUBDIRS += netserver #网络中转服务器
SUBDIRS += base64 #图片文字base64互换 SUBDIRS += base64 #图片文字base64互换
SUBDIRS += smoothcurve #平滑曲线 SUBDIRS += smoothcurve #平滑曲线
SUBDIRS += frameless #无边框方案支持winlinuxmac等
#限定windows系统加载下面的项目
win32 { win32 {
SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核 SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核
SUBDIRS += vlcdemo #视频流播放vlc内核 SUBDIRS += vlcdemo #视频流播放vlc内核
@ -46,8 +50,10 @@ SUBDIRS += miniblink #miniblink示例
#如果你电脑对应的Qt版本有webkit或者webengine组件可以自行打开 #如果你电脑对应的Qt版本有webkit或者webengine组件可以自行打开
#SUBDIRS += echartgauge #echart仪表盘含交互支持webkit及webengine #SUBDIRS += echartgauge #echart仪表盘含交互支持webkit及webengine
lessThan(QT_MAJOR_VERSION, 4) { #这个项目依赖QtDesigner模块,一般在arm上默认没有这个模块需要自行编译
#SUBDIRS += designer #QtDesigner4源码 #所以arm上如果没有QtDesigner模块不要加载下面这个子项目
lessThan(QT_MAJOR_VERSION, 5) {
SUBDIRS += designer #QtDesigner4源码
} }
#qwt项目需要等官方适配了qwt组件才能适配 #qwt项目需要等官方适配了qwt组件才能适配

View File

@ -2,7 +2,7 @@
1. **可以选择打开QWidgetDemo.pro一次性编译所有的也可以进入到目录下打开pro进行编译。** 1. **可以选择打开QWidgetDemo.pro一次性编译所有的也可以进入到目录下打开pro进行编译。**
2. **如果发现有些子项目没有加载请打开QWidgetDemo.pro仔细看里面的注释。** 2. **如果发现有些子项目没有加载请打开QWidgetDemo.pro仔细看里面的注释。**
3. **编译好的可执行文件在源码同级目录下的bin目录。** 3. **编译好的可执行文件在源码同级目录下的bin目录。**
4. **亲测Qt4.6到Qt6.1所有版本亲测win、linux、mac、uos等系统。** 4. **亲测Qt4.6到Qt6.2所有版本亲测win、linux、mac、uos等系统。**
| 编号 | 文件夹 | 描述 | | 编号 | 文件夹 | 描述 |
| ------ | ------ | ------ | | ------ | ------ | ------ |
@ -49,6 +49,7 @@
| 41 | miniblink | miniblink示例 | | 41 | miniblink | miniblink示例 |
| 42 | base64 | 图片文字base64互换 | | 42 | base64 | 图片文字base64互换 |
| 43 | smoothcurve | 平滑曲线 | | 43 | smoothcurve | 平滑曲线 |
| 44 | frameless | 地表最强最简单无边框方案 |
### 二、学习群 ### 二、学习群
1. **Qt交流大会群 853086607(雨田哥)** 1. **Qt交流大会群 853086607(雨田哥)**
@ -99,4 +100,5 @@
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/designer.png) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/designer.png)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/miniblink.jpg) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/miniblink.jpg)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/base64.png) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/base64.png)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/smoothcurve.gif) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/smoothcurve.gif)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/frameless.gif)

56
core_common/appinit.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "appinit.h"
#include "qmutex.h"
#include "qapplication.h"
#include "qevent.h"
#include "qwidget.h"
QScopedPointer<AppInit> AppInit::self;
AppInit *AppInit::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new AppInit);
}
}
return self.data();
}
AppInit::AppInit(QObject *parent) : QObject(parent)
{
}
bool AppInit::eventFilter(QObject *watched, QEvent *event)
{
QWidget *w = (QWidget *)watched;
if (!w->property("canMove").toBool()) {
return QObject::eventFilter(watched, event);
}
static QPoint mousePoint;
static bool mousePressed = false;
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->type() == QEvent::MouseButtonPress) {
if (mouseEvent->button() == Qt::LeftButton) {
mousePressed = true;
mousePoint = mouseEvent->globalPos() - w->pos();
}
} else if (mouseEvent->type() == QEvent::MouseButtonRelease) {
mousePressed = false;
} else if (mouseEvent->type() == QEvent::MouseMove) {
if (mousePressed) {
w->move(mouseEvent->globalPos() - mousePoint);
return true;
}
}
return QObject::eventFilter(watched, event);
}
void AppInit::start()
{
qApp->installEventFilter(this);
}

23
core_common/appinit.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef APPINIT_H
#define APPINIT_H
#include <QObject>
class AppInit : public QObject
{
Q_OBJECT
public:
static AppInit *Instance();
explicit AppInit(QObject *parent = 0);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
static QScopedPointer<AppInit> self;
public slots:
void start();
};
#endif // APPINIT_H

5
core_common/common.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>image/fontawesome-webfont.ttf</file>
</qresource>
</RCC>

View File

@ -0,0 +1,34 @@
#指定编译产生的文件分门别类放到对应目录
MOC_DIR = temp/moc
RCC_DIR = temp/rcc
UI_DIR = temp/ui
OBJECTS_DIR = temp/obj
#指定编译生成的可执行文件放到源码上一级目录下的bin目录
!android {
!wasm {
DESTDIR = $$PWD/../bin
}}
#把所有警告都关掉眼不见为净
CONFIG += warn_off
#开启大资源支持
CONFIG += resources_big
#开启后会将打印信息用控制台输出
#CONFIG += console
#引入全志H3芯片依赖
include ($$PWD/h3.pri)
HEADERS += \
$$PWD/appinit.h \
$$PWD/iconhelper.h \
$$PWD/quihelper.h
SOURCES += \
$$PWD/appinit.cpp \
$$PWD/iconhelper.cpp \
$$PWD/quihelper.cpp
RESOURCES += \
$$PWD/common.qrc

6
core_common/h3.pri Normal file
View File

@ -0,0 +1,6 @@
unix:!macx {
contains(DEFINES, arma7) {
INCLUDEPATH += /usr/local/openssl-1.0.2m-h3-gcc-4.9.2/include
LIBS += -L/usr/local/openssl-1.0.2m-h3-gcc-4.9.2/lib -lssl -lcrypto
LIBS += -L/usr/local/h3_rootfsv -lXdmcp
}}

351
core_common/iconhelper.cpp Normal file
View File

@ -0,0 +1,351 @@
#include "iconhelper.h"
IconHelper *IconHelper::iconFontAliBaBa = 0;
IconHelper *IconHelper::iconFontAwesome = 0;
void IconHelper::initFont()
{
static bool isInit = false;
if (!isInit) {
isInit = true;
if (iconFontAliBaBa == 0) {
iconFontAliBaBa = new IconHelper(":/image/iconfont.ttf", "iconfont");
}
if (iconFontAwesome == 0) {
iconFontAwesome = new IconHelper(":/image/fontawesome-webfont.ttf", "FontAwesome");
}
}
}
void IconHelper::setIcon(QLabel *lab, int icon, quint32 size)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setIcon1(lab, icon, size);
} else if (icon > 0xf000) {
iconFontAwesome->setIcon1(lab, icon, size);
}
}
void IconHelper::setIcon(QAbstractButton *btn, int icon, quint32 size)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setIcon1(btn, icon, size);
} else if (icon > 0xf000) {
iconFontAwesome->setIcon1(btn, icon, size);
}
}
void IconHelper::setPixmap(QAbstractButton *btn, const QColor &color, int icon, quint32 size,
quint32 width, quint32 height, int flags)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setPixmap1(btn, color, icon, size, width, height, flags);
} else if (icon > 0xf000) {
iconFontAwesome->setPixmap1(btn, color, icon, size, width, height, flags);
}
}
QPixmap IconHelper::getPixmap(const QColor &color, int icon, quint32 size,
quint32 width, quint32 height, int flags)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
QPixmap pix;
if (icon > 0xe000 && icon < 0xf000) {
pix = iconFontAliBaBa->getPixmap1(color, icon, size, width, height, flags);
} else if (icon > 0xf000) {
pix = iconFontAwesome->getPixmap1(color, icon, size, width, height, flags);
}
return pix;
}
void IconHelper::setStyle(QWidget *widget, QList<QPushButton *> btns,
QList<int> icons, const IconHelper::StyleColor &styleColor)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
int icon = icons.first();
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setStyle1(widget, btns, icons, styleColor);
} else if (icon > 0xf000) {
iconFontAwesome->setStyle1(widget, btns, icons, styleColor);
}
}
void IconHelper::setStyle(QWidget *widget, QList<QToolButton *> btns,
QList<int> icons, const IconHelper::StyleColor &styleColor)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
int icon = icons.first();
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setStyle1(widget, btns, icons, styleColor);
} else if (icon > 0xf000) {
iconFontAwesome->setStyle1(widget, btns, icons, styleColor);
}
}
void IconHelper::setStyle(QWidget *widget, QList<QAbstractButton *> btns,
QList<int> icons, const IconHelper::StyleColor &styleColor)
{
initFont();
//自动根据不同的字体的值选择对应的类,fontawesome 0xf开头 iconfont 0xe开头
int icon = icons.first();
if (icon > 0xe000 && icon < 0xf000) {
iconFontAliBaBa->setStyle1(widget, btns, icons, styleColor);
} else if (icon > 0xf000) {
iconFontAwesome->setStyle1(widget, btns, icons, styleColor);
}
}
IconHelper::IconHelper(const QString &fontFile, const QString &fontName, QObject *parent) : QObject(parent)
{
//判断图形字体是否存在,不存在则加入
QFontDatabase fontDb;
if (!fontDb.families().contains(fontName)) {
int fontId = fontDb.addApplicationFont(fontFile);
QStringList listName = fontDb.applicationFontFamilies(fontId);
if (listName.count() == 0) {
qDebug() << QString("load %1 error").arg(fontName);
}
}
if (fontDb.families().contains(fontName)) {
iconFont = QFont(fontName);
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))
iconFont.setHintingPreference(QFont::PreferNoHinting);
#endif
}
}
bool IconHelper::eventFilter(QObject *watched, QEvent *event)
{
//根据不同的
if (watched->inherits("QAbstractButton")) {
QAbstractButton *btn = (QAbstractButton *)watched;
int index = btns.indexOf(btn);
if (index >= 0) {
//不同的事件设置不同的图标,同时区分选中的和没有选中的
if (btn->isChecked()) {
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if (mouseEvent->button() == Qt::LeftButton) {
btn->setIcon(QIcon(pixChecked.at(index)));
}
} else if (event->type() == QEvent::Enter) {
btn->setIcon(QIcon(pixChecked.at(index)));
} else if (event->type() == QEvent::Leave) {
btn->setIcon(QIcon(pixChecked.at(index)));
}
} else {
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if (mouseEvent->button() == Qt::LeftButton) {
btn->setIcon(QIcon(pixPressed.at(index)));
}
} else if (event->type() == QEvent::Enter) {
btn->setIcon(QIcon(pixHover.at(index)));
} else if (event->type() == QEvent::Leave) {
btn->setIcon(QIcon(pixNormal.at(index)));
}
}
}
}
return QObject::eventFilter(watched, event);
}
void IconHelper::toggled(bool checked)
{
//选中和不选中设置不同的图标
QAbstractButton *btn = (QAbstractButton *)sender();
int index = btns.indexOf(btn);
if (checked) {
btn->setIcon(QIcon(pixChecked.at(index)));
} else {
btn->setIcon(QIcon(pixNormal.at(index)));
}
}
void IconHelper::setIcon1(QLabel *lab, int icon, quint32 size)
{
iconFont.setPixelSize(size);
lab->setFont(iconFont);
lab->setText((QChar)icon);
}
void IconHelper::setIcon1(QAbstractButton *btn, int icon, quint32 size)
{
iconFont.setPixelSize(size);
btn->setFont(iconFont);
btn->setText((QChar)icon);
}
void IconHelper::setPixmap1(QAbstractButton *btn, const QColor &color, int icon, quint32 size,
quint32 width, quint32 height, int flags)
{
btn->setIcon(getPixmap1(color, icon, size, width, height, flags));
}
QPixmap IconHelper::getPixmap1(const QColor &color, int icon, quint32 size,
quint32 width, quint32 height, int flags)
{
//主动绘制图形字体到图片
QPixmap pix(width, height);
pix.fill(Qt::transparent);
QPainter painter;
painter.begin(&pix);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.setPen(color);
iconFont.setPixelSize(size);
painter.setFont(iconFont);
painter.drawText(pix.rect(), flags, (QChar)icon);
painter.end();
return pix;
}
void IconHelper::setStyle1(QWidget *widget, QList<QPushButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
QList<QAbstractButton *> list;
foreach (QPushButton *btn, btns) {
list << btn;
}
setStyle(widget, list, icons, styleColor);
}
void IconHelper::setStyle1(QWidget *widget, QList<QToolButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
QList<QAbstractButton *> list;
foreach (QToolButton *btn, btns) {
list << btn;
}
setStyle(widget, list, icons, styleColor);
}
void IconHelper::setStyle1(QWidget *widget, QList<QAbstractButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
int btnCount = btns.count();
int iconCount = icons.count();
if (btnCount <= 0 || iconCount <= 0 || btnCount != iconCount) {
return;
}
QString position = styleColor.position;
quint32 iconSize = styleColor.iconSize;
quint32 iconWidth = styleColor.iconWidth;
quint32 iconHeight = styleColor.iconHeight;
quint32 borderWidth = styleColor.borderWidth;
//根据不同的位置计算边框
QString strBorder;
if (position == "top") {
strBorder = QString("border-width:%1px 0px 0px 0px;padding-top:%1px;padding-bottom:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "right") {
strBorder = QString("border-width:0px %1px 0px 0px;padding-right:%1px;padding-left:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "bottom") {
strBorder = QString("border-width:0px 0px %1px 0px;padding-bottom:%1px;padding-top:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "left") {
strBorder = QString("border-width:0px 0px 0px %1px;padding-left:%1px;padding-right:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
}
//如果图标是左侧显示则需要让没有选中的按钮左侧也有加深的边框,颜色为背景颜色
QStringList qss;
if (styleColor.textBesideIcon) {
qss << QString("QWidget[flag=\"%1\"] QAbstractButton{border-style:solid;border-radius:0px;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.normalBgColor).arg(styleColor.normalTextColor).arg(styleColor.normalBgColor);
} else {
qss << QString("QWidget[flag=\"%1\"] QAbstractButton{border-style:none;border-radius:0px;padding:5px;color:%2;background:%3;}")
.arg(position).arg(styleColor.normalTextColor).arg(styleColor.normalBgColor);
}
//悬停+按下+选中
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:hover{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.hoverTextColor).arg(styleColor.hoverBgColor);
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:pressed{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.pressedTextColor).arg(styleColor.pressedBgColor);
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:checked{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.checkedTextColor).arg(styleColor.checkedBgColor);
//窗体背景颜色+按钮背景颜色
qss << QString("QWidget#%1{background:%2;}")
.arg(widget->objectName()).arg(styleColor.normalBgColor);
qss << QString("QWidget>QAbstractButton{border-width:0px;background-color:%1;color:%2;}")
.arg(styleColor.normalBgColor).arg(styleColor.normalTextColor);
qss << QString("QWidget>QAbstractButton:hover{background-color:%1;color:%2;}")
.arg(styleColor.hoverBgColor).arg(styleColor.hoverTextColor);
qss << QString("QWidget>QAbstractButton:pressed{background-color:%1;color:%2;}")
.arg(styleColor.pressedBgColor).arg(styleColor.pressedTextColor);
qss << QString("QWidget>QAbstractButton:checked{background-color:%1;color:%2;}")
.arg(styleColor.checkedBgColor).arg(styleColor.checkedTextColor);
//设置样式表
widget->setStyleSheet(qss.join(""));
//可能会重复调用设置所以先要移除上一次的
for (int i = 0; i < btnCount; i++) {
for (int j = 0; j < this->btns.count(); j++) {
if (this->btns.at(j) == btns.at(i)) {
disconnect(btns.at(i), SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
this->btns.at(j)->removeEventFilter(this);
this->btns.removeAt(j);
this->pixNormal.removeAt(j);
this->pixHover.removeAt(j);
this->pixPressed.removeAt(j);
this->pixChecked.removeAt(j);
break;
}
}
}
//存储对应按钮对象,方便鼠标移上去的时候切换图片
int checkedIndex = -1;
for (int i = 0; i < btnCount; i++) {
int icon = icons.at(i);
QPixmap pixNormal = getPixmap1(styleColor.normalTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixHover = getPixmap1(styleColor.hoverTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixPressed = getPixmap1(styleColor.pressedTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixChecked = getPixmap1(styleColor.checkedTextColor, icon, iconSize, iconWidth, iconHeight);
//记住最后选中的按钮
QAbstractButton *btn = btns.at(i);
if (btn->isChecked()) {
checkedIndex = i;
}
btn->setIcon(QIcon(pixNormal));
btn->setIconSize(QSize(iconWidth, iconHeight));
btn->installEventFilter(this);
connect(btn, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
this->btns << btn;
this->pixNormal << pixNormal;
this->pixHover << pixHover;
this->pixPressed << pixPressed;
this->pixChecked << pixChecked;
}
//主动触发一下选中的按钮
if (checkedIndex >= 0) {
QMetaObject::invokeMethod(btns.at(checkedIndex), "toggled", Q_ARG(bool, true));
}
}

148
core_common/iconhelper.h Normal file
View File

@ -0,0 +1,148 @@
#ifndef ICONHELPER_H
#define ICONHELPER_H
#include <QtGui>
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
#include <QtWidgets>
#endif
/**
* :feiyangqingyun(QQ:517216493) 2016-11-23
* 1.
* 2. QLabel+QAbstractButton
* 3.
* 4.
* 5. ,+++
*/
#ifdef quc
class Q_DECL_EXPORT IconHelper : public QObject
#else
class IconHelper : public QObject
#endif
{
Q_OBJECT
public:
//样式颜色结构体
struct StyleColor {
QString position; //位置 left right top bottom
bool textBesideIcon; //文字在图标左侧
quint32 iconSize; //图标字体尺寸
quint32 iconWidth; //图标图片宽度
quint32 iconHeight; //图标图片高度
quint32 borderWidth; //边框宽度
QString borderColor; //边框颜色
QString normalBgColor; //正常背景颜色
QString normalTextColor; //正常文字颜色
QString hoverBgColor; //悬停背景颜色
QString hoverTextColor; //悬停文字颜色
QString pressedBgColor; //按下背景颜色
QString pressedTextColor; //按下文字颜色
QString checkedBgColor; //选中背景颜色
QString checkedTextColor; //选中文字颜色
StyleColor() {
position = "left";
textBesideIcon = false;
iconSize = 12;
iconWidth = 15;
iconHeight = 15;
borderWidth = 3;
borderColor = "#029FEA";
normalBgColor = "#292F38";
normalTextColor = "#54626F";
hoverBgColor = "#40444D";
hoverTextColor = "#FDFDFD";
pressedBgColor = "#404244";
pressedTextColor = "#FDFDFD";
checkedBgColor = "#44494F";
checkedTextColor = "#FDFDFD";
}
//设置常规颜色 普通状态+加深状态
void setColor(const QString &normalBgColor,
const QString &normalTextColor,
const QString &darkBgColor,
const QString &darkTextColor) {
this->normalBgColor = normalBgColor;
this->normalTextColor = normalTextColor;
this->hoverBgColor = darkBgColor;
this->hoverTextColor = darkTextColor;
this->pressedBgColor = darkBgColor;
this->pressedTextColor = darkTextColor;
this->checkedBgColor = darkBgColor;
this->checkedTextColor = darkTextColor;
}
};
//阿里巴巴图形字体类
static IconHelper *iconFontAliBaBa;
//FontAwesome图形字体类
static IconHelper *iconFontAwesome;
//初始化图形字体
static void initFont();
static void setIcon(QLabel *lab, int icon, quint32 size = 12);
static void setIcon(QAbstractButton *btn, int icon, quint32 size = 12);
static void setPixmap(QAbstractButton *btn, const QColor &color,
int icon, quint32 size = 12,
quint32 width = 15, quint32 height = 15,
int flags = Qt::AlignCenter);
static QPixmap getPixmap(const QColor &color, int icon, quint32 size = 12,
quint32 width = 15, quint32 height = 15,
int flags = Qt::AlignCenter);
static void setStyle(QWidget *widget, QList<QPushButton *> btns, QList<int> icons, const StyleColor &styleColor);
static void setStyle(QWidget *widget, QList<QToolButton *> btns, QList<int> icons, const StyleColor &styleColor);
static void setStyle(QWidget *widget, QList<QAbstractButton *> btns, QList<int> icons, const StyleColor &styleColor);
//默认构造函数,传入字体文件+字体名称
explicit IconHelper(const QString &fontFile, const QString &fontName, QObject *parent = 0);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
QFont iconFont; //图形字体
QList<QAbstractButton *> btns; //按钮队列
QList<QPixmap> pixNormal; //正常图片队列
QList<QPixmap> pixHover; //悬停图片队列
QList<QPixmap> pixPressed; //按下图片队列
QList<QPixmap> pixChecked; //选中图片队列
private slots:
//按钮选中状态切换处理
void toggled(bool checked);
public:
//设置图形字体到标签
void setIcon1(QLabel *lab, int icon, quint32 size = 12);
//设置图形字体到按钮
void setIcon1(QAbstractButton *btn, int icon, quint32 size = 12);
//设置图形字体到图标
void setPixmap1(QAbstractButton *btn, const QColor &color,
int icon, quint32 size = 12,
quint32 width = 15, quint32 height = 15,
int flags = Qt::AlignCenter);
//获取指定图形字体,可以指定文字大小,图片宽高,文字对齐
QPixmap getPixmap1(const QColor &color, int icon, quint32 size = 12,
quint32 width = 15, quint32 height = 15,
int flags = Qt::AlignCenter);
//指定导航面板样式,带图标和效果切换+悬停颜色+按下颜色+选中颜色
void setStyle1(QWidget *widget, QList<QPushButton *> btns, QList<int> icons, const StyleColor &styleColor);
void setStyle1(QWidget *widget, QList<QToolButton *> btns, QList<int> icons, const StyleColor &styleColor);
void setStyle1(QWidget *widget, QList<QAbstractButton *> btns, QList<int> icons, const StyleColor &styleColor);
};
#endif // ICONHELPER_H

Binary file not shown.

374
core_common/quihelper.cpp Normal file
View File

@ -0,0 +1,374 @@
#include "quihelper.h"
int QUIHelper::getScreenIndex()
{
//需要对多个屏幕进行处理
int screenIndex = 0;
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
int screenCount = qApp->screens().count();
#else
int screenCount = qApp->desktop()->screenCount();
#endif
if (screenCount > 1) {
//找到当前鼠标所在屏幕
QPoint pos = QCursor::pos();
for (int i = 0; i < screenCount; ++i) {
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
if (qApp->screens().at(i)->geometry().contains(pos)) {
#else
if (qApp->desktop()->screenGeometry(i).contains(pos)) {
#endif
screenIndex = i;
break;
}
}
}
return screenIndex;
}
QRect QUIHelper::getScreenRect(bool available)
{
QRect rect;
int screenIndex = QUIHelper::getScreenIndex();
if (available) {
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
rect = qApp->screens().at(screenIndex)->availableGeometry();
#else
rect = qApp->desktop()->availableGeometry(screenIndex);
#endif
} else {
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
rect = qApp->screens().at(screenIndex)->geometry();
#else
rect = qApp->desktop()->screenGeometry(screenIndex);
#endif
}
return rect;
}
int QUIHelper::deskWidth()
{
return getScreenRect().width();
}
int QUIHelper::deskHeight()
{
return getScreenRect().height();
}
QWidget *QUIHelper::centerBaseForm = 0;
void QUIHelper::setFormInCenter(QWidget *form)
{
int formWidth = form->width();
int formHeight = form->height();
//如果=0表示采用系统桌面屏幕为参照
QRect rect;
if (centerBaseForm == 0) {
rect = getScreenRect();
} else {
rect = centerBaseForm->geometry();
}
int deskWidth = rect.width();
int deskHeight = rect.height();
QPoint movePoint(deskWidth / 2 - formWidth / 2 + rect.x(), deskHeight / 2 - formHeight / 2 + rect.y());
form->move(movePoint);
}
QString QUIHelper::appName()
{
//没有必要每次都获取,只有当变量为空时才去获取一次
static QString name;
if (name.isEmpty()) {
name = qApp->applicationFilePath();
//下面的方法主要为了过滤安卓的路径 lib程序名_armeabi-v7a
QStringList list = name.split("/");
name = list.at(list.count() - 1).split(".").at(0);
}
return name;
}
QString QUIHelper::appPath()
{
#ifdef Q_OS_ANDROID
//return QString("/sdcard/Android/%1").arg(appName());
return QString("/storage/emulated/0/%1").arg(appName());
#else
return qApp->applicationDirPath();
#endif
}
QString QUIHelper::getUuid()
{
QString uuid = QUuid::createUuid().toString();
uuid.replace("{", "");
uuid.replace("}", "");
return uuid;
}
void QUIHelper::initRand()
{
//初始化随机数种子
QTime t = QTime::currentTime();
srand(t.msec() + t.second() * 1000);
}
void QUIHelper::newDir(const QString &dirName)
{
QString strDir = dirName;
//如果路径中包含斜杠字符则说明是绝对路径
//linux系统路径字符带有 / windows系统 路径字符带有 :/
if (!strDir.startsWith("/") && !strDir.contains(":/")) {
strDir = QString("%1/%2").arg(QUIHelper::appPath()).arg(strDir);
}
QDir dir(strDir);
if (!dir.exists()) {
dir.mkpath(strDir);
}
}
void QUIHelper::sleep(int msec)
{
if (msec > 0) {
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
QTime endTime = QTime::currentTime().addMSecs(msec);
while (QTime::currentTime() < endTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
#else
QThread::msleep(msec);
#endif
}
}
void QUIHelper::setStyle()
{
//打印下所有内置风格的名字
qDebug() << "Qt内置的样式" << QStyleFactory::keys();
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
qApp->setStyle(QStyleFactory::create("Fusion"));
#else
qApp->setStyle(QStyleFactory::create("Cleanlooks"));
#endif
//qApp->setPalette(QPalette("#FFFFFF"));
}
void QUIHelper::setFont(int fontSize)
{
QFont font;
font.setFamily("MicroSoft Yahei");
#ifdef Q_OS_ANDROID
font.setPixelSize(15);
#elif __arm__
font.setPixelSize(25);
#else
font.setPixelSize(fontSize);
#endif
#ifndef rk3399
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qApp->setFont(font);
#endif
#endif
}
void QUIHelper::setCode(bool utf8)
{
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("gbk");
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
//如果想要控制台打印信息中文正常就注释掉这个设置
if (utf8) {
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
}
#endif
}
void QUIHelper::setTranslator(const QString &qmFile)
{
QTranslator *translator = new QTranslator(qApp);
translator->load(qmFile);
qApp->installTranslator(translator);
}
int QUIHelper::showMessageBox(const QString &info, int type, int closeSec, bool exec)
{
int result = 0;
if (type == 0) {
showMessageBoxInfo(info, closeSec, exec);
} else if (type == 1) {
showMessageBoxError(info, closeSec, exec);
} else if (type == 2) {
result = showMessageBoxQuestion(info);
}
return result;
}
void QUIHelper::showMessageBoxInfo(const QString &info, int closeSec, bool exec)
{
QMessageBox box(QMessageBox::Information, "提示", info);
box.setStandardButtons(QMessageBox::Yes);
box.setButtonText(QMessageBox::Yes, QString("确 定"));
box.exec();
//QMessageBox::information(0, "提示", info, QMessageBox::Yes);
}
void QUIHelper::showMessageBoxError(const QString &info, int closeSec, bool exec)
{
QMessageBox box(QMessageBox::Critical, "错误", info);
box.setStandardButtons(QMessageBox::Yes);
box.setButtonText(QMessageBox::Yes, QString("确 定"));
box.exec();
//QMessageBox::critical(0, "错误", info, QMessageBox::Yes);
}
int QUIHelper::showMessageBoxQuestion(const QString &info)
{
QMessageBox box(QMessageBox::Question, "询问", info);
box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
box.setButtonText(QMessageBox::Yes, QString("确 定"));
box.setButtonText(QMessageBox::No, QString("取 消"));
return box.exec();
//return QMessageBox::question(0, "询问", info, QMessageBox::Yes | QMessageBox::No);
}
QString QUIHelper::getXorEncryptDecrypt(const QString &value, char key)
{
//矫正范围外的数据
if (key < 0 || key >= 127) {
key = 127;
}
QString result = value;
int count = result.count();
for (int i = 0; i < count; i++) {
result[i] = QChar(result.at(i).toLatin1() ^ key);
}
return result;
}
uchar QUIHelper::getOrCode(const QByteArray &data)
{
int len = data.length();
uchar result = 0;
for (int i = 0; i < len; i++) {
result ^= data.at(i);
}
return result;
}
uchar QUIHelper::getCheckCode(const QByteArray &data)
{
int len = data.length();
uchar temp = 0;
for (uchar i = 0; i < len; i++) {
temp += data.at(i);
}
return temp % 256;
}
void QUIHelper::initTableView(QTableView *tableView, int rowHeight, bool headVisible, bool edit, bool stretchLast)
{
//取消自动换行
tableView->setWordWrap(false);
//超出文本不显示省略号
tableView->setTextElideMode(Qt::ElideNone);
//奇数偶数行颜色交替
tableView->setAlternatingRowColors(false);
//垂直表头是否可见
tableView->verticalHeader()->setVisible(headVisible);
//选中一行表头是否加粗
tableView->horizontalHeader()->setHighlightSections(false);
//最后一行拉伸填充
tableView->horizontalHeader()->setStretchLastSection(stretchLast);
//行标题最小宽度尺寸
tableView->horizontalHeader()->setMinimumSectionSize(0);
//行标题最小高度,等同于和默认行高一致
tableView->horizontalHeader()->setFixedHeight(rowHeight);
//默认行高
tableView->verticalHeader()->setDefaultSectionSize(rowHeight);
//选中时一行整体选中
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
//只允许选择单个
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
//表头不可单击
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
tableView->horizontalHeader()->setSectionsClickable(false);
#else
tableView->horizontalHeader()->setClickable(false);
#endif
//鼠标按下即进入编辑模式
if (edit) {
tableView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked);
} else {
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
}
void QUIHelper::openFile(const QString &fileName, const QString &msg)
{
#ifdef __arm__
return;
#endif
if (fileName.isEmpty()) {
return;
}
if (QUIHelper::showMessageBoxQuestion(msg + "成功!确定现在就打开吗?") == QMessageBox::Yes) {
QString url = QString("file:///%1").arg(fileName);
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
}
}
bool QUIHelper::checkIniFile(const QString &iniFile)
{
//如果配置文件大小为0,则以初始值继续运行,并生成配置文件
QFile file(iniFile);
if (file.size() == 0) {
return false;
}
//如果配置文件不完整,则以初始值继续运行,并生成配置文件
if (file.open(QFile::ReadOnly)) {
bool ok = true;
while (!file.atEnd()) {
QString line = file.readLine();
line.replace("\r", "");
line.replace("\n", "");
QStringList list = line.split("=");
if (list.count() == 2) {
if (list.at(1) == "") {
qDebug() << "ini node no value" << list.at(0);
ok = false;
break;
}
}
}
if (!ok) {
return false;
}
} else {
return false;
}
return true;
}

65
core_common/quihelper.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef QUIHELPER2_H
#define QUIHELPER2_H
#include "head.h"
class QUIHelper
{
public:
//获取当前鼠标所在屏幕索引+尺寸
static int getScreenIndex();
static QRect getScreenRect(bool available = true);
//获取桌面宽度高度+居中显示
static int deskWidth();
static int deskHeight();
//居中显示窗体
//定义标志位指定是以桌面为参照还是主程序界面为参照
static QWidget *centerBaseForm;
static void setFormInCenter(QWidget *form);
//程序文件名称+当前所在路径
static QString appName();
static QString appPath();
//获取uuid+初始化随机数种子+新建目录+延时
static QString getUuid();
static void initRand();
static void newDir(const QString &dirName);
static void sleep(int msec);
//设置样式+字体+编码+居中+翻译
static void setStyle();
static void setFont(int fontSize = 12);
static void setCode(bool utf8 = true);
static void setTranslator(const QString &qmFile = ":/image/qt_zh_CN.qm");
//弹出框
static int showMessageBox(const QString &info, int type = 0, int closeSec = 0, bool exec = false);
//弹出消息框
static void showMessageBoxInfo(const QString &info, int closeSec = 0, bool exec = false);
//弹出错误框
static void showMessageBoxError(const QString &info, int closeSec = 0, bool exec = false);
//弹出询问框
static int showMessageBoxQuestion(const QString &info);
//异或加密-只支持字符,如果是中文需要将其转换base64编码
static QString getXorEncryptDecrypt(const QString &value, char key);
//异或校验
static uchar getOrCode(const QByteArray &data);
//计算校验码
static uchar getCheckCode(const QByteArray &data);
//初始化表格
static void initTableView(QTableView *tableView, int rowHeight = 25,
bool headVisible = false, bool edit = false,
bool stretchLast = true);
//打开文件带提示框
static void openFile(const QString &fileName, const QString &msg);
//检查ini配置文件
static bool checkIniFile(const QString &iniFile);
};
#endif // QUIHELPER2_H

View File

@ -0,0 +1,9 @@
HEADERS += \
$$PWD/framelessdialog.h \
$$PWD/framelessmainwindow.h \
$$PWD/framelesswidget.h
SOURCES += \
$$PWD/framelessdialog.cpp \
$$PWD/framelessmainwindow.cpp \
$$PWD/framelesswidget.cpp

View File

@ -0,0 +1,370 @@
#include "framelessdialog.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#pragma comment (lib,"user32.lib")
#endif
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
FramelessDialog::FramelessDialog(QWidget *parent) : QDialog(parent)
{
padding = 8;
moveEnable = true;
resizeEnable = true;
mousePressed = false;
mousePoint = QPoint(0, 0);
mouseRect = QRect(0, 0, 0, 0);
for (int i = 0; i < 8; ++i) {
pressedArea << false;
pressedRect << QRect(0, 0, 0, 0);
}
isMin = false;
flags = this->windowFlags();
titleBar = 0;
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
this->setAttribute(Qt::WA_TranslucentBackground);
#endif
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
//安装事件过滤器识别拖动
this->installEventFilter(this);
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
//设置以后会产生标题栏需要在下面拦截消息重新去掉
#ifdef Q_OS_WIN
HWND hwnd = (HWND)this->winId();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
#endif
}
void FramelessDialog::showEvent(QShowEvent *event)
{
//解决有时候窗体重新显示的时候假死不刷新的BUG
setAttribute(Qt::WA_Mapped);
QDialog::showEvent(event);
}
void FramelessDialog::doWindowStateChange(QEvent *event)
{
//非最大化才能移动和拖动大小
if (windowState() == Qt::WindowNoState) {
moveEnable = true;
resizeEnable = true;
} else {
moveEnable = false;
resizeEnable = false;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
emit windowStateChange(!moveEnable);
//解决mac系统上无边框最小化失效的BUG
#ifdef Q_OS_MACOS
if (windowState() & Qt::WindowMinimized) {
isMin = true;
} else {
if (isMin) {
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
this->setVisible(true);
isMin = false;
}
}
#endif
}
void FramelessDialog::doResizeEvent(QEvent *event)
{
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
#ifndef Q_OS_WIN
if (event->type() == QEvent::Resize) {
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
int width = this->width();
int height = this->height();
//左侧描点区域
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
//右侧描点区域
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
//上侧描点区域
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
//下侧描点区域
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
//左上角描点区域
pressedRect[4] = QRect(0, 0, padding, padding);
//右上角描点区域
pressedRect[5] = QRect(width - padding, 0, padding, padding);
//左下角描点区域
pressedRect[6] = QRect(0, height - padding, padding, padding);
//右下角描点区域
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
} else if (event->type() == QEvent::HoverMove) {
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
QHoverEvent *hoverEvent = (QHoverEvent *)event;
QPoint point = hoverEvent->pos();
if (resizeEnable) {
if (pressedRect.at(0).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(1).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(2).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(3).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(4).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else if (pressedRect.at(5).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(6).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(7).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else {
this->setCursor(Qt::ArrowCursor);
}
}
//根据当前鼠标位置,计算XY轴移动了多少
int offsetX = point.x() - mousePoint.x();
int offsetY = point.y() - mousePoint.y();
//根据按下处的位置判断是否是移动控件还是拉伸控件
if (moveEnable && mousePressed) {
this->move(this->x() + offsetX, this->y() + offsetY);
}
if (resizeEnable) {
int rectX = mouseRect.x();
int rectY = mouseRect.y();
int rectW = mouseRect.width();
int rectH = mouseRect.height();
if (pressedArea.at(0)) {
int resizeW = this->width() - offsetX;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
}
} else if (pressedArea.at(1)) {
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
} else if (pressedArea.at(2)) {
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
}
} else if (pressedArea.at(3)) {
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
} else if (pressedArea.at(4)) {
int resizeW = this->width() - offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(5)) {
int resizeW = rectW + offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(6)) {
int resizeW = this->width() - offsetX;
int resizeH = rectH + offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
} else if (pressedArea.at(7)) {
int resizeW = rectW + offsetX;
int resizeH = rectH + offsetY;
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
//记住鼠标按下的坐标+窗体区域
QMouseEvent *mouseEvent = (QMouseEvent *)event;
mousePoint = mouseEvent->pos();
mouseRect = this->geometry();
//判断按下的手柄的区域位置
if (pressedRect.at(0).contains(mousePoint)) {
pressedArea[0] = true;
} else if (pressedRect.at(1).contains(mousePoint)) {
pressedArea[1] = true;
} else if (pressedRect.at(2).contains(mousePoint)) {
pressedArea[2] = true;
} else if (pressedRect.at(3).contains(mousePoint)) {
pressedArea[3] = true;
} else if (pressedRect.at(4).contains(mousePoint)) {
pressedArea[4] = true;
} else if (pressedRect.at(5).contains(mousePoint)) {
pressedArea[5] = true;
} else if (pressedRect.at(6).contains(mousePoint)) {
pressedArea[6] = true;
} else if (pressedRect.at(7).contains(mousePoint)) {
pressedArea[7] = true;
} else {
mousePressed = true;
}
} else if (event->type() == QEvent::MouseMove) {
//改成用HoverMove识别
} else if (event->type() == QEvent::MouseButtonRelease) {
//恢复所有
this->setCursor(Qt::ArrowCursor);
mousePressed = false;
for (int i = 0; i < 8; ++i) {
pressedArea[i] = false;
}
}
#endif
}
bool FramelessDialog::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this) {
if (event->type() == QEvent::WindowStateChange) {
doWindowStateChange(event);
} else {
doResizeEvent(event);
}
} else if (watched == titleBar) {
//双击标题栏发出双击信号给主界面
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
#ifndef Q_OS_WIN
if (event->type() == QEvent::MouseButtonDblClick) {
emit titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
emit titleDblClick();
}
#endif
}
return QDialog::eventFilter(watched, event);
}
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#else
bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
{
if (eventType == "windows_generic_MSG") {
#ifdef Q_OS_WIN
MSG *msg = static_cast<MSG *>(message);
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
//不同的消息类型和参数进行不同的处理
if (msg->message == WM_NCCALCSIZE) {
*result = 0;
return true;
} else if (msg->message == WM_NCHITTEST) {
//计算鼠标对应的屏幕坐标
long x = LOWORD(msg->lParam);
long y = HIWORD(msg->lParam);
QPoint pos = mapFromGlobal(QPoint(x, y));
//判断当前鼠标位置在哪个区域
bool left = pos.x() < padding;
bool right = pos.x() > width() - padding;
bool top = pos.y() < padding;
bool bottom = pos.y() > height() - padding;
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
*result = 0;
if (resizeEnable) {
if (left && top) {
*result = HTTOPLEFT;
} else if (left && bottom) {
*result = HTBOTTOMLEFT;
} else if (right && top) {
*result = HTTOPRIGHT;
} else if (right && bottom) {
*result = HTBOTTOMRIGHT;
} else if (left) {
*result = HTLEFT;
} else if (right) {
*result = HTRIGHT;
} else if (top) {
*result = HTTOP;
} else if (bottom) {
*result = HTBOTTOM;
}
}
//先处理掉拉伸
if (0 != *result) {
return true;
}
//识别标题栏拖动产生半屏全屏效果
if (titleBar != 0 && titleBar->rect().contains(pos)) {
QWidget *child = titleBar->childAt(pos);
if (!child) {
*result = HTCAPTION;
return true;
}
}
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
//系统休眠的时候自动最小化可以规避程序可能出现的问题
this->showMinimized();
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
//休眠唤醒后自动打开
this->showNormal();
}
#endif
} else if (eventType == "NSEvent") {
#ifdef Q_OS_MACOS
#endif
} else if (eventType == "xcb_generic_event_t") {
#ifdef Q_OS_LINUX
#endif
}
return false;
}
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool FramelessDialog::winEvent(MSG *message, long *result)
{
return nativeEvent("windows_generic_MSG", message, result);
}
#endif
#endif
void FramelessDialog::setPadding(int padding)
{
this->padding = padding;
}
void FramelessDialog::setMoveEnable(bool moveEnable)
{
this->moveEnable = moveEnable;
}
void FramelessDialog::setResizeEnable(bool resizeEnable)
{
this->resizeEnable = resizeEnable;
}
void FramelessDialog::setTitleBar(QWidget *titleBar)
{
this->titleBar = titleBar;
this->titleBar->installEventFilter(this);
}

View File

@ -0,0 +1,73 @@
#ifndef FRAMELESSDIALOG_H
#define FRAMELESSDIALOG_H
#include <QDialog>
class FramelessDialog : public QDialog
{
Q_OBJECT
public:
explicit FramelessDialog(QWidget *parent = 0);
protected:
//窗体显示的时候触发
void showEvent(QShowEvent *event);
//事件过滤器识别拖动拉伸等
void doWindowStateChange(QEvent *event);
void doResizeEvent(QEvent *event);
bool eventFilter(QObject *watched, QEvent *event);
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
#else
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
//Qt4的写法
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool winEvent(MSG *message, long *result);
#endif
#endif
private:
//边距+可移动+可拉伸
int padding;
bool moveEnable;
bool resizeEnable;
//标题栏控件
QWidget *titleBar;
//鼠标是否按下+按下坐标+按下时窗体区域
bool mousePressed;
QPoint mousePoint;
QRect mouseRect;
//鼠标是否按下某个区域+按下区域的大小
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
QList<bool> pressedArea;
QList<QRect> pressedRect;
//记录是否最小化
bool isMin;
//存储窗体默认的属性
Qt::WindowFlags flags;
public:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
signals:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSDIALOG_H

View File

@ -0,0 +1,368 @@
#include "framelessmainwindow.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#pragma comment (lib,"user32.lib")
#endif
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
FramelessMainWindow::FramelessMainWindow(QWidget *parent) : QMainWindow(parent)
{
padding = 8;
moveEnable = true;
resizeEnable = true;
mousePressed = false;
mousePoint = QPoint(0, 0);
mouseRect = QRect(0, 0, 0, 0);
for (int i = 0; i < 8; ++i) {
pressedArea << false;
pressedRect << QRect(0, 0, 0, 0);
}
isMin = false;
flags = this->windowFlags();
titleBar = 0;
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
this->setAttribute(Qt::WA_TranslucentBackground);
#endif
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
//安装事件过滤器识别拖动
this->installEventFilter(this);
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
//设置以后会产生标题栏,需要在下面拦截消息WM_NCCALCSIZE重新去掉
#ifdef Q_OS_WIN
HWND hwnd = (HWND)this->winId();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
#endif
}
void FramelessMainWindow::showEvent(QShowEvent *event)
{
//解决有时候窗体重新显示的时候假死不刷新的BUG
setAttribute(Qt::WA_Mapped);
QMainWindow::showEvent(event);
}
void FramelessMainWindow::doWindowStateChange(QEvent *event)
{
//非最大化才能移动和拖动大小
if (windowState() == Qt::WindowNoState) {
moveEnable = true;
resizeEnable = true;
} else {
moveEnable = false;
resizeEnable = false;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
emit windowStateChange(!moveEnable);
//解决mac系统上无边框最小化失效的BUG
#ifdef Q_OS_MACOS
if (windowState() & Qt::WindowMinimized) {
isMin = true;
} else {
if (isMin) {
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
this->setVisible(true);
isMin = false;
}
}
#endif
}
void FramelessMainWindow::doResizeEvent(QEvent *event)
{
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
#ifndef Q_OS_WIN
if (event->type() == QEvent::Resize) {
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
int width = this->width();
int height = this->height();
//左侧描点区域
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
//右侧描点区域
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
//上侧描点区域
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
//下侧描点区域
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
//左上角描点区域
pressedRect[4] = QRect(0, 0, padding, padding);
//右上角描点区域
pressedRect[5] = QRect(width - padding, 0, padding, padding);
//左下角描点区域
pressedRect[6] = QRect(0, height - padding, padding, padding);
//右下角描点区域
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
} else if (event->type() == QEvent::HoverMove) {
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
QHoverEvent *hoverEvent = (QHoverEvent *)event;
QPoint point = hoverEvent->pos();
if (resizeEnable) {
if (pressedRect.at(0).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(1).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(2).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(3).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(4).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else if (pressedRect.at(5).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(6).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(7).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else {
this->setCursor(Qt::ArrowCursor);
}
}
//根据当前鼠标位置,计算XY轴移动了多少
int offsetX = point.x() - mousePoint.x();
int offsetY = point.y() - mousePoint.y();
//根据按下处的位置判断是否是移动控件还是拉伸控件
if (moveEnable && mousePressed) {
this->move(this->x() + offsetX, this->y() + offsetY);
}
if (resizeEnable) {
int rectX = mouseRect.x();
int rectY = mouseRect.y();
int rectW = mouseRect.width();
int rectH = mouseRect.height();
if (pressedArea.at(0)) {
int resizeW = this->width() - offsetX;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
}
} else if (pressedArea.at(1)) {
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
} else if (pressedArea.at(2)) {
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
}
} else if (pressedArea.at(3)) {
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
} else if (pressedArea.at(4)) {
int resizeW = this->width() - offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(5)) {
int resizeW = rectW + offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(6)) {
int resizeW = this->width() - offsetX;
int resizeH = rectH + offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
} else if (pressedArea.at(7)) {
int resizeW = rectW + offsetX;
int resizeH = rectH + offsetY;
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
//记住鼠标按下的坐标+窗体区域
QMouseEvent *mouseEvent = (QMouseEvent *)event;
mousePoint = mouseEvent->pos();
mouseRect = this->geometry();
//判断按下的手柄的区域位置
if (pressedRect.at(0).contains(mousePoint)) {
pressedArea[0] = true;
} else if (pressedRect.at(1).contains(mousePoint)) {
pressedArea[1] = true;
} else if (pressedRect.at(2).contains(mousePoint)) {
pressedArea[2] = true;
} else if (pressedRect.at(3).contains(mousePoint)) {
pressedArea[3] = true;
} else if (pressedRect.at(4).contains(mousePoint)) {
pressedArea[4] = true;
} else if (pressedRect.at(5).contains(mousePoint)) {
pressedArea[5] = true;
} else if (pressedRect.at(6).contains(mousePoint)) {
pressedArea[6] = true;
} else if (pressedRect.at(7).contains(mousePoint)) {
pressedArea[7] = true;
} else {
mousePressed = true;
}
} else if (event->type() == QEvent::MouseMove) {
//改成用HoverMove识别
} else if (event->type() == QEvent::MouseButtonRelease) {
//恢复所有
this->setCursor(Qt::ArrowCursor);
mousePressed = false;
for (int i = 0; i < 8; ++i) {
pressedArea[i] = false;
}
}
#endif
}
bool FramelessMainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this) {
if (event->type() == QEvent::WindowStateChange) {
doWindowStateChange(event);
} else {
doResizeEvent(event);
}
} else if (watched == titleBar) {
//双击标题栏发出双击信号给主界面
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
#ifndef Q_OS_WIN
if (event->type() == QEvent::MouseButtonDblClick) {
emit titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
emit titleDblClick();
}
#endif
}
return QMainWindow::eventFilter(watched, event);
}
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#else
bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
{
if (eventType == "windows_generic_MSG") {
#ifdef Q_OS_WIN
MSG *msg = static_cast<MSG *>(message);
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
//不同的消息类型和参数进行不同的处理
if (msg->message == WM_NCCALCSIZE) {
*result = 0;
return true;
} else if (msg->message == WM_NCHITTEST) {
//计算鼠标对应的屏幕坐标
long x = LOWORD(msg->lParam);
long y = HIWORD(msg->lParam);
QPoint pos = mapFromGlobal(QPoint(x, y));
//判断当前鼠标位置在哪个区域
bool left = pos.x() < padding;
bool right = pos.x() > width() - padding;
bool top = pos.y() < padding;
bool bottom = pos.y() > height() - padding;
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
*result = 0;
if (resizeEnable) {
if (left && top) {
*result = HTTOPLEFT;
} else if (left && bottom) {
*result = HTBOTTOMLEFT;
} else if (right && top) {
*result = HTTOPRIGHT;
} else if (right && bottom) {
*result = HTBOTTOMRIGHT;
} else if (left) {
*result = HTLEFT;
} else if (right) {
*result = HTRIGHT;
} else if (top) {
*result = HTTOP;
} else if (bottom) {
*result = HTBOTTOM;
}
}
//先处理掉拉伸
if (0 != *result) {
return true;
}
//识别标题栏拖动产生半屏全屏效果
if (titleBar != 0 && titleBar->rect().contains(pos)) {
QWidget *child = titleBar->childAt(pos);
if (!child) {
*result = HTCAPTION;
return true;
}
}
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
//系统休眠的时候自动最小化可以规避程序可能出现的问题
this->showMinimized();
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
//休眠唤醒后自动打开
this->showNormal();
}
#endif
} else if (eventType == "NSEvent") {
#ifdef Q_OS_MACOS
#endif
} else if (eventType == "xcb_generic_event_t") {
#ifdef Q_OS_LINUX
#endif
}
return false;
}
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool FramelessMainWindow::winEvent(MSG *message, long *result)
{
return nativeEvent("windows_generic_MSG", message, result);
}
#endif
#endif
void FramelessMainWindow::setPadding(int padding)
{
this->padding = padding;
}
void FramelessMainWindow::setMoveEnable(bool moveEnable)
{
this->moveEnable = moveEnable;
}
void FramelessMainWindow::setResizeEnable(bool resizeEnable)
{
this->resizeEnable = resizeEnable;
}
void FramelessMainWindow::setTitleBar(QWidget *titleBar)
{
this->titleBar = titleBar;
this->titleBar->installEventFilter(this);
}

View File

@ -0,0 +1,73 @@
#ifndef FRAMELESSMAINWINDOW_H
#define FRAMELESSMAINWINDOW_H
#include <QMainWindow>
class FramelessMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit FramelessMainWindow(QWidget *parent = 0);
protected:
//窗体显示的时候触发
void showEvent(QShowEvent *event);
//事件过滤器识别拖动拉伸等
void doWindowStateChange(QEvent *event);
void doResizeEvent(QEvent *event);
bool eventFilter(QObject *watched, QEvent *event);
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
#else
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
//Qt4的写法
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool winEvent(MSG *message, long *result);
#endif
#endif
private:
//边距+可移动+可拉伸
int padding;
bool moveEnable;
bool resizeEnable;
//标题栏控件
QWidget *titleBar;
//鼠标是否按下+按下坐标+按下时窗体区域
bool mousePressed;
QPoint mousePoint;
QRect mouseRect;
//鼠标是否按下某个区域+按下区域的大小
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
QList<bool> pressedArea;
QList<QRect> pressedRect;
//记录是否最小化
bool isMin;
//存储窗体默认的属性
Qt::WindowFlags flags;
public:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
signals:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSMAINWINDOW_H

View File

@ -0,0 +1,370 @@
#include "framelesswidget.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#pragma comment (lib,"user32.lib")
#endif
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent)
{
padding = 8;
moveEnable = true;
resizeEnable = true;
mousePressed = false;
mousePoint = QPoint(0, 0);
mouseRect = QRect(0, 0, 0, 0);
for (int i = 0; i < 8; ++i) {
pressedArea << false;
pressedRect << QRect(0, 0, 0, 0);
}
isMin = false;
flags = this->windowFlags();
titleBar = 0;
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
this->setAttribute(Qt::WA_TranslucentBackground);
#endif
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
//安装事件过滤器识别拖动
this->installEventFilter(this);
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
//设置以后会产生标题栏需要在下面拦截消息重新去掉
#ifdef Q_OS_WIN
HWND hwnd = (HWND)this->winId();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
#endif
}
void FramelessWidget::showEvent(QShowEvent *event)
{
//解决有时候窗体重新显示的时候假死不刷新的BUG
setAttribute(Qt::WA_Mapped);
QWidget::showEvent(event);
}
void FramelessWidget::doWindowStateChange(QEvent *event)
{
//非最大化才能移动和拖动大小
if (windowState() == Qt::WindowNoState) {
moveEnable = true;
resizeEnable = true;
} else {
moveEnable = false;
resizeEnable = false;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
emit windowStateChange(!moveEnable);
//解决mac系统上无边框最小化失效的BUG
#ifdef Q_OS_MACOS
if (windowState() & Qt::WindowMinimized) {
isMin = true;
} else {
if (isMin) {
//设置无边框属性
this->setWindowFlags(flags | Qt::FramelessWindowHint);
this->setVisible(true);
isMin = false;
}
}
#endif
}
void FramelessWidget::doResizeEvent(QEvent *event)
{
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
#ifndef Q_OS_WIN
if (event->type() == QEvent::Resize) {
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
int width = this->width();
int height = this->height();
//左侧描点区域
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
//右侧描点区域
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
//上侧描点区域
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
//下侧描点区域
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
//左上角描点区域
pressedRect[4] = QRect(0, 0, padding, padding);
//右上角描点区域
pressedRect[5] = QRect(width - padding, 0, padding, padding);
//左下角描点区域
pressedRect[6] = QRect(0, height - padding, padding, padding);
//右下角描点区域
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
} else if (event->type() == QEvent::HoverMove) {
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
QHoverEvent *hoverEvent = (QHoverEvent *)event;
QPoint point = hoverEvent->pos();
if (resizeEnable) {
if (pressedRect.at(0).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(1).contains(point)) {
this->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(2).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(3).contains(point)) {
this->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(4).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else if (pressedRect.at(5).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(6).contains(point)) {
this->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(7).contains(point)) {
this->setCursor(Qt::SizeFDiagCursor);
} else {
this->setCursor(Qt::ArrowCursor);
}
}
//根据当前鼠标位置,计算XY轴移动了多少
int offsetX = point.x() - mousePoint.x();
int offsetY = point.y() - mousePoint.y();
//根据按下处的位置判断是否是移动控件还是拉伸控件
if (moveEnable && mousePressed) {
this->move(this->x() + offsetX, this->y() + offsetY);
}
if (resizeEnable) {
int rectX = mouseRect.x();
int rectY = mouseRect.y();
int rectW = mouseRect.width();
int rectH = mouseRect.height();
if (pressedArea.at(0)) {
int resizeW = this->width() - offsetX;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
}
} else if (pressedArea.at(1)) {
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
} else if (pressedArea.at(2)) {
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
}
} else if (pressedArea.at(3)) {
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
} else if (pressedArea.at(4)) {
int resizeW = this->width() - offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(5)) {
int resizeW = rectW + offsetX;
int resizeH = this->height() - offsetY;
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(6)) {
int resizeW = this->width() - offsetX;
int resizeH = rectH + offsetY;
if (this->minimumWidth() <= resizeW) {
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
}
if (this->minimumHeight() <= resizeH) {
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
} else if (pressedArea.at(7)) {
int resizeW = rectW + offsetX;
int resizeH = rectH + offsetY;
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
//记住鼠标按下的坐标+窗体区域
QMouseEvent *mouseEvent = (QMouseEvent *)event;
mousePoint = mouseEvent->pos();
mouseRect = this->geometry();
//判断按下的手柄的区域位置
if (pressedRect.at(0).contains(mousePoint)) {
pressedArea[0] = true;
} else if (pressedRect.at(1).contains(mousePoint)) {
pressedArea[1] = true;
} else if (pressedRect.at(2).contains(mousePoint)) {
pressedArea[2] = true;
} else if (pressedRect.at(3).contains(mousePoint)) {
pressedArea[3] = true;
} else if (pressedRect.at(4).contains(mousePoint)) {
pressedArea[4] = true;
} else if (pressedRect.at(5).contains(mousePoint)) {
pressedArea[5] = true;
} else if (pressedRect.at(6).contains(mousePoint)) {
pressedArea[6] = true;
} else if (pressedRect.at(7).contains(mousePoint)) {
pressedArea[7] = true;
} else {
mousePressed = true;
}
} else if (event->type() == QEvent::MouseMove) {
//改成用HoverMove识别
} else if (event->type() == QEvent::MouseButtonRelease) {
//恢复所有
this->setCursor(Qt::ArrowCursor);
mousePressed = false;
for (int i = 0; i < 8; ++i) {
pressedArea[i] = false;
}
}
#endif
}
bool FramelessWidget::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this) {
if (event->type() == QEvent::WindowStateChange) {
doWindowStateChange(event);
} else {
doResizeEvent(event);
}
} else if (watched == titleBar) {
//双击标题栏发出双击信号给主界面
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
#ifndef Q_OS_WIN
if (event->type() == QEvent::MouseButtonDblClick) {
emit titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
emit titleDblClick();
}
#endif
}
return QWidget::eventFilter(watched, event);
}
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#else
bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
{
if (eventType == "windows_generic_MSG") {
#ifdef Q_OS_WIN
MSG *msg = static_cast<MSG *>(message);
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
//不同的消息类型和参数进行不同的处理
if (msg->message == WM_NCCALCSIZE) {
*result = 0;
return true;
} else if (msg->message == WM_NCHITTEST) {
//计算鼠标对应的屏幕坐标
long x = LOWORD(msg->lParam);
long y = HIWORD(msg->lParam);
QPoint pos = mapFromGlobal(QPoint(x, y));
//判断当前鼠标位置在哪个区域
bool left = pos.x() < padding;
bool right = pos.x() > width() - padding;
bool top = pos.y() < padding;
bool bottom = pos.y() > height() - padding;
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
*result = 0;
if (resizeEnable) {
if (left && top) {
*result = HTTOPLEFT;
} else if (left && bottom) {
*result = HTBOTTOMLEFT;
} else if (right && top) {
*result = HTTOPRIGHT;
} else if (right && bottom) {
*result = HTBOTTOMRIGHT;
} else if (left) {
*result = HTLEFT;
} else if (right) {
*result = HTRIGHT;
} else if (top) {
*result = HTTOP;
} else if (bottom) {
*result = HTBOTTOM;
}
}
//先处理掉拉伸
if (0 != *result) {
return true;
}
//识别标题栏拖动产生半屏全屏效果
if (titleBar != 0 && titleBar->rect().contains(pos)) {
QWidget *child = titleBar->childAt(pos);
if (!child) {
*result = HTCAPTION;
return true;
}
}
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
//系统休眠的时候自动最小化可以规避程序可能出现的问题
this->showMinimized();
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
//休眠唤醒后自动打开
this->showNormal();
}
#endif
} else if (eventType == "NSEvent") {
#ifdef Q_OS_MACOS
#endif
} else if (eventType == "xcb_generic_event_t") {
#ifdef Q_OS_LINUX
#endif
}
return false;
}
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool FramelessWidget::winEvent(MSG *message, long *result)
{
return nativeEvent("windows_generic_MSG", message, result);
}
#endif
#endif
void FramelessWidget::setPadding(int padding)
{
this->padding = padding;
}
void FramelessWidget::setMoveEnable(bool moveEnable)
{
this->moveEnable = moveEnable;
}
void FramelessWidget::setResizeEnable(bool resizeEnable)
{
this->resizeEnable = resizeEnable;
}
void FramelessWidget::setTitleBar(QWidget *titleBar)
{
this->titleBar = titleBar;
this->titleBar->installEventFilter(this);
}

View File

@ -0,0 +1,73 @@
#ifndef FRAMELESSWIDGET_H
#define FRAMELESSWIDGET_H
#include <QWidget>
class FramelessWidget : public QWidget
{
Q_OBJECT
public:
explicit FramelessWidget(QWidget *parent = 0);
protected:
//窗体显示的时候触发
void showEvent(QShowEvent *event);
//事件过滤器识别拖动拉伸等
void doWindowStateChange(QEvent *event);
void doResizeEvent(QEvent *event);
bool eventFilter(QObject *watched, QEvent *event);
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
#else
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
//Qt4的写法
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_WIN
bool winEvent(MSG *message, long *result);
#endif
#endif
private:
//边距+可移动+可拉伸
int padding;
bool moveEnable;
bool resizeEnable;
//标题栏控件
QWidget *titleBar;
//鼠标是否按下+按下坐标+按下时窗体区域
bool mousePressed;
QPoint mousePoint;
QRect mouseRect;
//鼠标是否按下某个区域+按下区域的大小
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
QList<bool> pressedArea;
QList<QRect> pressedRect;
//记录是否最小化
bool isMin;
//存储窗体默认的属性
Qt::WindowFlags flags;
public:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
signals:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSWIDGET_H

69
frameless/form/dialog.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "dialog.h"
#include "ui_dialog.h"
#include "head.h"
Dialog::Dialog(QWidget *parent) : FramelessDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
this->initForm();
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::initForm()
{
//设置标题栏控件
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
this->setWindowTitle(ui->labTitle->text());
this->setTitleBar(ui->labTitle);
//关联信号
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
//设置样式表
QStringList list;
list << "#titleBar{background:#BBBBBB;}";
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
this->setStyleSheet(list.join(""));
}
void Dialog::titleDblClick()
{
on_btnMenu_Max_clicked();
}
void Dialog::windowStateChange(bool max)
{
ui->btnMenu_Max->setText(max ? "还原" : "最大");
}
void Dialog::on_btnMenu_Min_clicked()
{
#ifdef Q_OS_MACOS
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
#endif
this->showMinimized();
}
void Dialog::on_btnMenu_Max_clicked()
{
if (this->isMaximized()) {
this->showNormal();
ui->btnMenu_Max->setText("最大");
} else {
this->showMaximized();
ui->btnMenu_Max->setText("还原");
}
}
void Dialog::on_btnMenu_Close_clicked()
{
this->close();
}

32
frameless/form/dialog.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef DIALOG_H
#define DIALOG_H
#include "framelessdialog.h"
namespace Ui {
class Dialog;
}
class Dialog : public FramelessDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
private slots:
void initForm();
void titleDblClick();
void windowStateChange(bool max);
private slots:
void on_btnMenu_Min_clicked();
void on_btnMenu_Max_clicked();
void on_btnMenu_Close_clicked();
};
#endif // DIALOG_H

215
frameless/form/dialog.ui Normal file
View File

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="titleBar" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labTitle">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMenu" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>28</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnMenu_Min">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>最小化</string>
</property>
<property name="text">
<string>最小</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Max">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>最大</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Close">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>关闭</string>
</property>
<property name="text">
<string>关闭</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMain" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

14
frameless/form/form.pri Normal file
View File

@ -0,0 +1,14 @@
FORMS += \
$$PWD/dialog.ui \
$$PWD/mainwindow.ui \
$$PWD/widget.ui
HEADERS += \
$$PWD/dialog.h \
$$PWD/mainwindow.h \
$$PWD/widget.h
SOURCES += \
$$PWD/dialog.cpp \
$$PWD/mainwindow.cpp \
$$PWD/widget.cpp

View File

@ -0,0 +1,68 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "head.h"
MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->initForm();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initForm()
{
//设置标题栏控件
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
this->setWindowTitle(ui->labTitle->text());
this->setTitleBar(ui->labTitle);
//关联信号
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
//设置样式表
QStringList list;
list << "#titleBar{background:#BBBBBB;}";
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
this->setStyleSheet(list.join(""));
}
void MainWindow::titleDblClick()
{
on_btnMenu_Max_clicked();
}
void MainWindow::windowStateChange(bool max)
{
ui->btnMenu_Max->setText(max ? "还原" : "最大");
}
void MainWindow::on_btnMenu_Min_clicked()
{
#ifdef Q_OS_MACOS
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
#endif
this->showMinimized();
}
void MainWindow::on_btnMenu_Max_clicked()
{
if (this->isMaximized()) {
this->showNormal();
ui->btnMenu_Max->setText("最大");
} else {
this->showMaximized();
ui->btnMenu_Max->setText("还原");
}
}
void MainWindow::on_btnMenu_Close_clicked()
{
this->close();
}

View File

@ -0,0 +1,32 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "framelessmainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public FramelessMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void initForm();
void titleDblClick();
void windowStateChange(bool max);
private slots:
void on_btnMenu_Min_clicked();
void on_btnMenu_Max_clicked();
void on_btnMenu_Close_clicked();
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="titleBar" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labTitle">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMenu" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>28</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnMenu_Min">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>最小化</string>
</property>
<property name="text">
<string>最小</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Max">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>最大</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Close">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>关闭</string>
</property>
<property name="text">
<string>关闭</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMain" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

68
frameless/form/widget.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "widget.h"
#include "ui_widget.h"
#include "head.h"
Widget::Widget(QWidget *parent) : FramelessWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
this->initForm();
}
Widget::~Widget()
{
delete ui;
}
void Widget::initForm()
{
//设置标题栏控件
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
this->setWindowTitle(ui->labTitle->text());
this->setTitleBar(ui->labTitle);
//关联信号
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
//设置样式表
QStringList list;
list << "#titleBar{background:#BBBBBB;}";
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
this->setStyleSheet(list.join(""));
}
void Widget::titleDblClick()
{
on_btnMenu_Max_clicked();
}
void Widget::windowStateChange(bool max)
{
ui->btnMenu_Max->setText(max ? "还原" : "最大");
}
void Widget::on_btnMenu_Min_clicked()
{
#ifdef Q_OS_MACOS
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
#endif
this->showMinimized();
}
void Widget::on_btnMenu_Max_clicked()
{
if (this->isMaximized()) {
this->showNormal();
ui->btnMenu_Max->setText("最大");
} else {
this->showMaximized();
ui->btnMenu_Max->setText("还原");
}
}
void Widget::on_btnMenu_Close_clicked()
{
this->close();
}

32
frameless/form/widget.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef WIDGET_H
#define WIDGET_H
#include "framelesswidget.h"
namespace Ui {
class Widget;
}
class Widget : public FramelessWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
private slots:
void initForm();
void titleDblClick();
void windowStateChange(bool max);
private slots:
void on_btnMenu_Min_clicked();
void on_btnMenu_Max_clicked();
void on_btnMenu_Close_clicked();
};
#endif // WIDGET_H

215
frameless/form/widget.ui Normal file
View File

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="titleBar" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labTitle">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMenu" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>28</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnMenu_Min">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>最小化</string>
</property>
<property name="text">
<string>最小</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Max">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>最大</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMenu_Close">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>关闭</string>
</property>
<property name="text">
<string>关闭</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetMain" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

21
frameless/frameless.pro Normal file
View File

@ -0,0 +1,21 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = frameless
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
HEADERS += head.h
SOURCES += main.cpp
INCLUDEPATH += $$PWD
INCLUDEPATH += $$PWD/form
include ($$PWD/form/form.pri)
INCLUDEPATH += $$PWD/../core_frameless
include ($$PWD/../core_frameless/core_frameless.pri)
INCLUDEPATH += $$PWD/../core_common
include ($$PWD/../core_common/core_common.pri)

15
frameless/head.h Normal file
View File

@ -0,0 +1,15 @@
#include <QtCore>
#include <QtGui>
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
#include <QtWidgets>
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtCore5Compat>
#endif
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
#define DATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
#pragma execution_character_set("utf-8")

29
frameless/main.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "quihelper.h"
#include "mainwindow.h"
#include "widget.h"
#include "dialog.h"
int main(int argc, char *argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
#endif
QApplication a(argc, argv);
QUIHelper::setStyle();
QUIHelper::setFont(15);
QUIHelper::setCode();
MainWindow w;
//Widget w;
//Dialog w;
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
w.resize(800, 600);
#else
w.resize(800, 550);
#endif
QUIHelper::setFormInCenter(&w);
w.show();
return a.exec();
}

50
frameless/readme.md Normal file
View File

@ -0,0 +1,50 @@
### 一 前言
不知道各位程序员有没有遇到过这样一种困惑好不容易在开源网站找到了类似的想要的项目代码结果down下来一编译我勒个去几百个错误根本没法用熟悉的人还好可以直接阅读代码进行修改有些只要做小改动就能正常编译有些可能需要大刀阔斧可是对于绝大部分的初学者来说绝对是噩梦连把代码看下去的勇气都没有我们没有任何权利和理由去责怪开原作者只是期望各位能够在项目开源的同时将开源项目完善好、测试好最起码要把项目中依赖的遗漏的文件一起打包好或者作出必要的说明比如对应的开发编译版本要求以来的文件去哪里下载。很多优秀的项目就毁在这个地方没人完善和维护可能因为没有耐心也没有持续的收入来源所以干的没劲作者甚至转行送外卖了。只有解决了这个痛点才能使得对应的开源项目持续发光发热。
本人自从学习Qt开发以来开源过至少上百个项目大部分早期开源的目前不在开源主页有空会全部整理好重新发布我要是说在国内Qt界开源的项目数量和质量排第十的话没人敢说排第一、第二、第三...到第九。关于无边框界面方案网上也有不少的优秀的开源的例子99%都存在以下几个问题针对以上问题解决这些痛点借助自己刚好有多个操作系统、几十个Qt版本的开发测试环境特意完善了这个无边框类。
- 无法正常编译,缺少文件,作者真粗心,自己都没测试过。
- 只限定了部分特定的版本才能编译。
- 只解决了单个问题,比如无边框拖动,没有系统特性拉到左侧右侧半屏、顶部最大化。
- 代码赶鸭子上架,复制粘贴的一坨坨,毫无章法。
- 代码就是给作者自己用的,放上去就是给个参考,管他那么多。
- 往左侧拉动抖动的厉害。
- mac系统上不能最小化。
- 不能同时支持win、linux、mac三种主流操作系统。
### 二 功能特点
1. 同时支持Qt4-Qt6亲测Qt4.7到Qt6.2以及后续版本。
2. 同时支持mingw、msvc、gcc等。
3. 同时支持windows、linux、mac。
4. 同时支持QMainWindow、QWidget、QDialog。
5. 使用方法极其简单,只需要将继承类修改即可。
6. 自动识别双击标题栏响应。
7. 无边框拉伸在windows下不抖动。
8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。
9. 解决mac系统上无边框最小化最大化失效的BUG。
10. 解决系统休眠后再次启动程序懵逼的BUG。
11. 解决有时候窗体重新显示的时候假死不刷新的BUG。
12. 轻量级1个代码文件核心代码行数不到300行。
13. 注释详细,示例完美,非常适合阅读和学习。
14. 开源开箱即用保证任意Qt版本可正常编译运行无需任何调整。
### 三 效果图
#### 1 windows
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/frameless/snap/win.gif)
#### 2 ubuntu
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/frameless/snap/ubuntu.gif)
#### 3 uos
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/frameless/snap/uos.gif)
#### 4 kylin
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/frameless/snap/kylin.gif)
#### 5 mac
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/frameless/snap/mac.gif)
### 四 特别说明
1. 点赞、评论、留言、转发、发代码。
2. 国内站点:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)
3. 国际站点:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)

BIN
frameless/snap/kylin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

BIN
frameless/snap/mac.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

BIN
frameless/snap/ubuntu.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 KiB

BIN
frameless/snap/uos.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
frameless/snap/win.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB