彻底改版2.0

This commit is contained in:
feiyangqingyun
2021-11-17 16:41:30 +08:00
parent a7f4347959
commit ebfd531a91
2622 changed files with 8915 additions and 7263 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
widget/0snap/gifwidget.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
widget/0snap/maskwidget.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
widget/0snap/movewidget.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,174 @@
#pragma execution_character_set("utf-8")
#include "colorwidget.h"
#include "qmutex.h"
#include "qgridlayout.h"
#include "qlabel.h"
#include "qlineedit.h"
#include "qapplication.h"
#include "qtimer.h"
#include "qevent.h"
#include "qdebug.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
#include "qscreen.h"
#define deskGeometry qApp->primaryScreen()->geometry()
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
#else
#include "qdesktopwidget.h"
#define deskGeometry qApp->desktop()->geometry()
#define deskGeometry2 qApp->desktop()->availableGeometry()
#endif
ColorWidget *ColorWidget::instance = 0;
ColorWidget *ColorWidget::Instance()
{
if (!instance) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (!instance) {
instance = new ColorWidget;
}
}
return instance;
}
ColorWidget::ColorWidget(QWidget *parent) : QWidget(parent)
{
gridLayout = new QGridLayout(this);
gridLayout->setSpacing(6);
gridLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout = new QVBoxLayout();
verticalLayout->setSpacing(0);
labColor = new QLabel(this);
labColor->setText("+");
labColor->setStyleSheet("background-color: rgb(255, 107, 107);color: rgb(250, 250, 250);");
labColor->setAlignment(Qt::AlignCenter);
QFont font;
font.setPixelSize(35);
font.setBold(true);
labColor->setFont(font);
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(labColor->sizePolicy().hasHeightForWidth());
labColor->setSizePolicy(sizePolicy);
labColor->setMinimumSize(QSize(80, 70));
labColor->setMaximumSize(QSize(80, 70));
labColor->setCursor(QCursor(Qt::CrossCursor));
labColor->setFrameShape(QFrame::StyledPanel);
labColor->setFrameShadow(QFrame::Sunken);
verticalLayout->addWidget(labColor);
label = new QLabel(this);
label->setMinimumSize(QSize(0, 18));
label->setStyleSheet("background-color: rgb(0, 0, 0);color: rgb(200, 200, 200);");
label->setAlignment(Qt::AlignCenter);
verticalLayout->addWidget(label);
gridLayout->addLayout(verticalLayout, 0, 0, 3, 1);
labWeb = new QLabel(this);
gridLayout->addWidget(labWeb, 0, 1, 1, 1);
txtWeb = new QLineEdit(this);
gridLayout->addWidget(txtWeb, 0, 2, 1, 1);
labRgb = new QLabel(this);
gridLayout->addWidget(labRgb, 1, 1, 1, 1);
txtRgb = new QLineEdit(this);
gridLayout->addWidget(txtRgb, 1, 2, 1, 1);
labPoint = new QLabel(this);
gridLayout->addWidget(labPoint, 2, 1, 1, 1);
txtPoint = new QLineEdit(this);
gridLayout->addWidget(txtPoint, 2, 2, 1, 1);
label->setText("当前颜色");
labWeb->setText("web值:");
labRgb->setText("rgb值:");
labPoint->setText("坐标值:");
this->setLayout(gridLayout);
this->setWindowTitle("屏幕拾色器");
this->setFixedSize(300, 108);
cp = QApplication::clipboard();
pressed = false;
timer = new QTimer(this);
timer->setInterval(100);
connect(timer, SIGNAL(timeout()), this, SLOT(showColorValue()));
timer->start();
}
ColorWidget::~ColorWidget()
{
}
void ColorWidget::mousePressEvent(QMouseEvent *e)
{
if (labColor->rect().contains(e->pos())) {
pressed = true;
}
}
void ColorWidget::mouseReleaseEvent(QMouseEvent *)
{
pressed = false;
}
void ColorWidget::showColorValue()
{
if (!pressed) {
return;
}
int x = QCursor::pos().x();
int y = QCursor::pos().y();
txtPoint->setText(tr("x:%1 y:%2").arg(x).arg(y));
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
QScreen *screen = qApp->primaryScreen();
QPixmap pixmap = screen->grabWindow(0, x, y, 2, 2);
#else
QPixmap pixmap = QPixmap::grabWindow(qApp->desktop()->winId(), x, y, 2, 2);
#endif
int red, green, blue;
QString strDecimalValue, strHex;
if (pixmap.isNull()) {
return;
}
QImage image = pixmap.toImage();
if (image.valid(0, 0)) {
QColor color = image.pixel(0, 0);
red = color.red();
green = color.green();
blue = color.blue();
QString strRed = tr("%1").arg(red & 0xFF, 2, 16, QChar('0'));
QString strGreen = tr("%1").arg(green & 0xFF, 2, 16, QChar('0'));
QString strBlue = tr("%1").arg(blue & 0xFF, 2, 16, QChar('0'));
strDecimalValue = tr("%1, %2, %3").arg(red).arg(green).arg(blue);
strHex = tr("#%1%2%3").arg(strRed.toUpper()).arg(strGreen.toUpper()).arg(strBlue.toUpper());
}
//根据背景色自动计算合适的前景色
QColor color(red, green, blue);
double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
QColor textColor = gray > 0.5 ? Qt::black : Qt::white;
QString str = tr("background:rgb(%1);color:%2").arg(strDecimalValue).arg(textColor.name());
labColor->setStyleSheet(str);
txtRgb->setText(strDecimalValue);
txtWeb->setText(strHex);
}

View File

@@ -0,0 +1,58 @@
#ifndef COLORWIDGET_H
#define COLORWIDGET_H
/**
* 屏幕拾色器 作者:feiyangqingyun(QQ:517216493) 2016-11-11
* 1. 鼠标按下实时采集鼠标处的颜色。
* 2. 实时显示颜色值。
* 3. 支持16进制格式和rgb格式。
* 4. 实时显示预览颜色。
* 5. 根据背景色自动计算合适的前景色。
*/
#include <QWidget>
class QGridLayout;
class QVBoxLayout;
class QLabel;
class QLineEdit;
#ifdef quc
class Q_DECL_EXPORT ColorWidget : public QWidget
#else
class ColorWidget : public QWidget
#endif
{
Q_OBJECT
public:
static ColorWidget *Instance();
explicit ColorWidget(QWidget *parent = 0);
~ColorWidget();
protected:
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
private:
static ColorWidget *instance;
QClipboard *cp;
bool pressed;
QTimer *timer;
QGridLayout *gridLayout;
QVBoxLayout *verticalLayout;
QLabel *labColor;
QLabel *label;
QLabel *labWeb;
QLineEdit *txtWeb;
QLabel *labRgb;
QLineEdit *txtRgb;
QLabel *labPoint;
QLineEdit *txtPoint;
private Q_SLOTS:
void showColorValue();
};
#endif // COLORWIDGET_H

View File

@@ -0,0 +1,17 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = colorwidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmcolorwidget.cpp
SOURCES += colorwidget.cpp
HEADERS += colorwidget.h
HEADERS += frmcolorwidget.h
FORMS += frmcolorwidget.ui

View File

@@ -0,0 +1,18 @@
#include "frmcolorwidget.h"
#include "ui_frmcolorwidget.h"
#include "colorwidget.h"
frmColorWidget::frmColorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmColorWidget)
{
ui->setupUi(this);
}
frmColorWidget::~frmColorWidget()
{
delete ui;
}
void frmColorWidget::on_pushButton_clicked()
{
ColorWidget::Instance()->show();
}

View File

@@ -0,0 +1,25 @@
#ifndef FRMCOLORWIDGET_H
#define FRMCOLORWIDGET_H
#include <QWidget>
namespace Ui {
class frmColorWidget;
}
class frmColorWidget : public QWidget
{
Q_OBJECT
public:
explicit frmColorWidget(QWidget *parent = 0);
~frmColorWidget();
private slots:
void on_pushButton_clicked();
private:
Ui::frmColorWidget *ui;
};
#endif // FRMCOLORWIDGET_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmColorWidget</class>
<widget class="QWidget" name="frmColorWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>92</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>弹出</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmcolorwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmColorWidget w;
w.setWindowTitle("屏幕拾色器");
w.show();
return a.exec();
}

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,373 @@
#include "framelessdialog.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#include "windowsx.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) {
//计算鼠标对应的屏幕坐标
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(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,96 @@
#ifndef FRAMELESSDIALOG_H
#define FRAMELESSDIALOG_H
/**
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
* 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版本可正常编译运行无需任何调整。
*/
#include <QDialog>
#ifdef quc
class Q_DECL_EXPORT FramelessDialog : public QDialog
#else
class FramelessDialog : public QDialog
#endif
{
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 Q_SLOTS:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
Q_SIGNALS:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSDIALOG_H

View File

@@ -0,0 +1,371 @@
#include "framelessmainwindow.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#include "windowsx.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) {
//计算鼠标对应的屏幕坐标
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(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,96 @@
#ifndef FRAMELESSMAINWINDOW_H
#define FRAMELESSMAINWINDOW_H
/**
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
* 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版本可正常编译运行无需任何调整。
*/
#include <QMainWindow>
#ifdef quc
class Q_DECL_EXPORT FramelessMainWindow : public QMainWindow
#else
class FramelessMainWindow : public QMainWindow
#endif
{
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 Q_SLOTS:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
Q_SIGNALS:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSMAINWINDOW_H

View File

@@ -0,0 +1,373 @@
#include "framelesswidget.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#include "windows.h"
#include "windowsx.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) {
//计算鼠标对应的屏幕坐标
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(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,96 @@
#ifndef FRAMELESSWIDGET_H
#define FRAMELESSWIDGET_H
/**
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
* 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版本可正常编译运行无需任何调整。
*/
#include <QWidget>
#ifdef quc
class Q_DECL_EXPORT FramelessWidget : public QWidget
#else
class FramelessWidget : public QWidget
#endif
{
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 Q_SLOTS:
//设置边距+可拖动+可拉伸
void setPadding(int padding);
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//设置标题栏控件
void setTitleBar(QWidget *titleBar);
Q_SIGNALS:
void titleDblClick();
void windowStateChange(bool max);
};
#endif // FRAMELESSWIDGET_H

View File

@@ -0,0 +1,69 @@
#include "dialog.h"
#include "ui_dialog.h"
#pragma execution_character_set("utf-8")
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();
}

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

View File

@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="FramelessDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</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>
<customwidgets>
<customwidget>
<class>FramelessDialog</class>
<extends>QWidget</extends>
<header>framelessdialog.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

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"
#pragma execution_character_set("utf-8")
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,233 @@
<?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>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>207</width>
<height>59</height>
</rect>
</property>
<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>
<customwidgets>
<customwidget>
<class>FramelessMainWindow</class>
<extends>QWidget</extends>
<header>framelessmainwindow.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,68 @@
#include "widget.h"
#include "ui_widget.h"
#pragma execution_character_set("utf-8")
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();
}

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

View File

@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="FramelessWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</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>
<customwidgets>
<customwidget>
<class>FramelessWidget</class>
<extends>QWidget</extends>
<header>framelesswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,23 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = framelesswidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmframelesswidget.cpp
SOURCES += framelesswidget2.cpp
HEADERS += frmframelesswidget.h
HEADERS += framelesswidget2.h
FORMS += frmframelesswidget.ui
INCLUDEPATH += $$PWD/framelesscore
INCLUDEPATH += $$PWD/framelessform
include ($$PWD/framelesscore/framelesscore.pri)
include ($$PWD/framelessform/framelessform.pri)

View File

@@ -0,0 +1,226 @@
#include "framelesswidget2.h"
#include "qevent.h"
#include "qdebug.h"
FramelessWidget2::FramelessWidget2(QObject *parent) : QObject(parent)
{
padding = 8;
moveEnable = true;
resizeEnable = true;
widget = 0;
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);
}
//如果父类是窗体则直接设置
if (parent->isWidgetType()) {
setWidget((QWidget *)parent);
}
}
bool FramelessWidget2::eventFilter(QObject *watched, QEvent *event)
{
if (widget != 0 && watched == widget) {
if (event->type() == QEvent::WindowStateChange) {
//解决mac系统上无边框最小化失效的BUG
#ifdef Q_OS_MACOS
if (widget->windowState() & Qt::WindowMinimized) {
isMin = true;
} else {
if (isMin) {
//设置无边框属性
widget->setWindowFlags(flags | Qt::FramelessWindowHint);
widget->setVisible(true);
isMin = false;
}
}
#endif
} else if (event->type() == QEvent::Resize) {
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
int width = widget->width();
int height = widget->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)) {
widget->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(1).contains(point)) {
widget->setCursor(Qt::SizeHorCursor);
} else if (pressedRect.at(2).contains(point)) {
widget->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(3).contains(point)) {
widget->setCursor(Qt::SizeVerCursor);
} else if (pressedRect.at(4).contains(point)) {
widget->setCursor(Qt::SizeFDiagCursor);
} else if (pressedRect.at(5).contains(point)) {
widget->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(6).contains(point)) {
widget->setCursor(Qt::SizeBDiagCursor);
} else if (pressedRect.at(7).contains(point)) {
widget->setCursor(Qt::SizeFDiagCursor);
} else {
widget->setCursor(Qt::ArrowCursor);
}
}
//根据当前鼠标位置,计算XY轴移动了多少
int offsetX = point.x() - mousePoint.x();
int offsetY = point.y() - mousePoint.y();
//根据按下处的位置判断是否是移动控件还是拉伸控件
if (moveEnable && mousePressed) {
widget->move(widget->x() + offsetX, widget->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 = widget->width() - offsetX;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, rectY, resizeW, rectH);
}
} else if (pressedArea.at(1)) {
widget->setGeometry(rectX, rectY, rectW + offsetX, rectH);
} else if (pressedArea.at(2)) {
int resizeH = widget->height() - offsetY;
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(rectX, widget->y() + offsetY, rectW, resizeH);
}
} else if (pressedArea.at(3)) {
widget->setGeometry(rectX, rectY, rectW, rectH + offsetY);
} else if (pressedArea.at(4)) {
int resizeW = widget->width() - offsetX;
int resizeH = widget->height() - offsetY;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
}
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(5)) {
int resizeW = rectW + offsetX;
int resizeH = widget->height() - offsetY;
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
}
} else if (pressedArea.at(6)) {
int resizeW = widget->width() - offsetX;
int resizeH = rectH + offsetY;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
}
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
}
} else if (pressedArea.at(7)) {
int resizeW = rectW + offsetX;
int resizeH = rectH + offsetY;
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
//记住鼠标按下的坐标+窗体区域
QMouseEvent *mouseEvent = (QMouseEvent *)event;
mousePoint = mouseEvent->pos();
mouseRect = widget->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) {
//恢复所有
widget->setCursor(Qt::ArrowCursor);
mousePressed = false;
for (int i = 0; i < 8; ++i) {
pressedArea[i] = false;
}
}
}
return QObject::eventFilter(watched, event);
}
void FramelessWidget2::setPadding(int padding)
{
this->padding = padding;
}
void FramelessWidget2::setMoveEnable(bool moveEnable)
{
this->moveEnable = moveEnable;
}
void FramelessWidget2::setResizeEnable(bool resizeEnable)
{
this->resizeEnable = resizeEnable;
}
void FramelessWidget2::setMousePressed(bool mousePressed)
{
this->mousePressed = mousePressed;
}
void FramelessWidget2::setWidget(QWidget *widget)
{
if (this->widget == 0) {
this->widget = widget;
//设置鼠标追踪为真
this->widget->setMouseTracking(true);
//绑定事件过滤器
this->widget->installEventFilter(this);
//设置悬停为真,必须设置这个,不然当父窗体里边还有子窗体全部遮挡了识别不到MouseMove,需要识别HoverMove
this->widget->setAttribute(Qt::WA_Hover, true);
isMin = false;
flags = widget->windowFlags();
}
}

View File

@@ -0,0 +1,66 @@
#ifndef FRAMELESSWIDGET2_H
#define FRAMELESSWIDGET2_H
/**
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2019-10-03
* 1. 可以指定需要无边框的widget。
* 2. 边框四周八个方位都可以自由拉伸。
* 3. 可设置对应位置的边距,以便识别更大区域。
* 4. 可设置是否允许拖动。
* 5. 可设置是否允许拉伸。
*/
#include <QWidget>
#ifdef quc
class Q_DECL_EXPORT FramelessWidget2 : public QObject
#else
class FramelessWidget2 : public QObject
#endif
{
Q_OBJECT
public:
explicit FramelessWidget2(QObject *parent = 0);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
//边距+可移动+可拉伸
int padding;
bool moveEnable;
bool resizeEnable;
//无边框窗体
QWidget *widget;
//鼠标是否按下+按下坐标+按下时窗体区域
bool mousePressed;
QPoint mousePoint;
QRect mouseRect;
//鼠标是否按下某个区域+按下区域的大小
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
QList<bool> pressedArea;
QList<QRect> pressedRect;
//记录是否最小化
bool isMin;
//存储窗体默认的属性
Qt::WindowFlags flags;
public Q_SLOTS:
//设置边距
void setPadding(int padding);
//设置是否可拖动+拉伸
void setMoveEnable(bool moveEnable);
void setResizeEnable(bool resizeEnable);
//修复部分控件不能自动识别 MouseButtonRelease 的BUG
void setMousePressed(bool mousePressed);
//设置要无边框的窗体
void setWidget(QWidget *widget);
};
#endif // FRAMELESSWIDGET2_H

View File

@@ -0,0 +1,110 @@
#pragma execution_character_set("utf-8")
#include "frmframelesswidget.h"
#include "ui_frmframelesswidget.h"
#include "qpushbutton.h"
#include "qcheckbox.h"
#include "qdebug.h"
#include "framelesswidget2.h"
#ifndef Q_CC_MSVC
#include "framelessform/dialog.h"
#include "framelessform/widget.h"
#include "framelessform/mainwindow.h"
#endif
frmFramelessWidget::frmFramelessWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmFramelessWidget)
{
ui->setupUi(this);
this->initForm();
}
frmFramelessWidget::~frmFramelessWidget()
{
delete ui;
}
void frmFramelessWidget::initForm()
{
widget = 0;
frameless = 0;
connect(ui->btnDialog, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
connect(ui->btnWidget, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
connect(ui->btnMainWindow, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
}
void frmFramelessWidget::initWidget(QWidget *w)
{
//设置无边框属性
w->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
//w->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
w->setWindowTitle("自由拉伸无边框窗体");
w->setMinimumSize(200, 120);
w->resize(480, 320);
//设置下背景颜色区别看
QPalette palette = w->palette();
palette.setBrush(QPalette::Window, QColor(162, 121, 197));
w->setPalette(palette);
QPushButton *btn = new QPushButton(w);
btn->setText("关闭");
btn->setGeometry(10, 10, 130, 25);
connect(btn, SIGNAL(clicked(bool)), w, SLOT(close()));
QCheckBox *cboxMove = new QCheckBox(w);
cboxMove->setText("可移动");
cboxMove->setChecked(true);
cboxMove->setGeometry(10, 40, 70, 25);
connect(cboxMove, SIGNAL(stateChanged(int)), this, SLOT(stateChanged1(int)));
QCheckBox *cboxResize = new QCheckBox(w);
cboxResize->setText("可拉伸");
cboxResize->setChecked(true);
cboxResize->setGeometry(80, 40, 70, 25);
connect(cboxResize, SIGNAL(stateChanged(int)), this, SLOT(stateChanged2(int)));
}
void frmFramelessWidget::on_pushButton_clicked()
{
if (widget == 0) {
widget = new QWidget;
this->initWidget(widget);
frameless = new FramelessWidget2(widget);
frameless->setWidget(widget);
}
widget->show();
}
void frmFramelessWidget::stateChanged1(int arg1)
{
if (frameless != 0) {
frameless->setMoveEnable(arg1 != 0);
}
}
void frmFramelessWidget::stateChanged2(int arg1)
{
if (frameless != 0) {
frameless->setResizeEnable(arg1 != 0);
}
}
void frmFramelessWidget::buttonClicked()
{
#ifndef Q_CC_MSVC
QString objName = sender()->objectName();
if (objName == "btnDialog") {
Dialog dialog;
dialog.exec();
} else if (objName == "btnWidget") {
Widget *widget = new Widget;
widget->show();
} else if (objName == "btnMainWindow") {
MainWindow *window = new MainWindow;
window->show();
}
#endif
}

View File

@@ -0,0 +1,33 @@
#ifndef FRMFRAMELESSWIDGET_H
#define FRMFRAMELESSWIDGET_H
#include <QWidget>
class FramelessWidget2;
namespace Ui {
class frmFramelessWidget;
}
class frmFramelessWidget : public QWidget
{
Q_OBJECT
public:
explicit frmFramelessWidget(QWidget *parent = 0);
~frmFramelessWidget();
private:
Ui::frmFramelessWidget *ui;
QWidget *widget;
FramelessWidget2 *frameless;
private slots:
void initForm();
void initWidget(QWidget *w);
void on_pushButton_clicked();
void stateChanged1(int arg1);
void stateChanged2(int arg1);
void buttonClicked();
};
#endif // FRMFRAMELESSWIDGET_H

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmFramelessWidget</class>
<widget class="QWidget" name="frmFramelessWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>491</width>
<height>30</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>弹出</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDialog">
<property name="text">
<string>Dialog</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnWidget">
<property name="text">
<string>Widget</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMainWindow">
<property name="text">
<string>MainWindow</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,35 @@
#pragma execution_character_set("utf-8")
#include "frmframelesswidget.h"
#include <QApplication>
#include <QTextCodec>
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);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmFramelessWidget w;
w.setWindowTitle("无边框窗体");
w.resize(800, 600);
w.show();
return a.exec();
}

View File

@@ -0,0 +1,20 @@
#include "frmgifwidget.h"
#include "ui_frmgifwidget.h"
#include "gifwidget.h"
frmGifWidget::frmGifWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmGifWidget)
{
ui->setupUi(this);
}
frmGifWidget::~frmGifWidget()
{
delete ui;
}
void frmGifWidget::on_pushButton_clicked()
{
//设置截图窗口置顶显示
GifWidget::Instance()->setWindowFlags(GifWidget::Instance()->windowFlags() | Qt::WindowStaysOnTopHint);
GifWidget::Instance()->show();
}

View File

@@ -0,0 +1,25 @@
#ifndef FRMGIFWIDGET_H
#define FRMGIFWIDGET_H
#include <QWidget>
namespace Ui {
class frmGifWidget;
}
class frmGifWidget : public QWidget
{
Q_OBJECT
public:
explicit frmGifWidget(QWidget *parent = 0);
~frmGifWidget();
private slots:
void on_pushButton_clicked();
private:
Ui::frmGifWidget *ui;
};
#endif // FRMGIFWIDGET_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmGifWidget</class>
<widget class="QWidget" name="frmGifWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>92</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>弹出</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

795
widget/gifwidget/gif.h Normal file
View File

@@ -0,0 +1,795 @@
//
// gif.h
// by Charlie Tangora
// Public domain.
// Email me : ctangora -at- gmail -dot- com
//
// This file offers a simple, very limited way to create animated GIFs directly in code.
//
// Those looking for particular cleverness are likely to be disappointed; it's pretty
// much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg
// dithering. (It does at least use delta encoding - only the changed portions of each
// frame are saved.)
//
// So resulting files are often quite large. The hope is that it will be handy nonetheless
// as a quick and easily-integrated way for programs to spit out animations.
//
// Only RGBA8 is currently supported as an input format. (The alpha is ignored.)
//
// USAGE:
// Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header.
// Pass subsequent frames to GifWriteFrame().
// Finally, call GifEnd() to close the file handle and free memory.
//
#ifndef __gif_h__
#define __gif_h__
#include <stdio.h> // for FILE*
#include <string.h> // for memcpy and bzero
#ifdef _MSC_VER
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h> // for integer typedefs
#endif
// Define these macros to hook into a custom memory allocator.
// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
// and any temp memory allocated by a function will be freed before it exits.
// MALLOC and FREE are used only by GifBegin and GifEnd respectively (to allocate a buffer the size of the image, which
// is used to find changed pixels for delta-encoding.)
#ifndef GIF_TEMP_MALLOC
#include <stdlib.h>
#define GIF_TEMP_MALLOC malloc
#endif
#ifndef GIF_TEMP_FREE
#include <stdlib.h>
#define GIF_TEMP_FREE free
#endif
#ifndef GIF_MALLOC
#include <stdlib.h>
#define GIF_MALLOC malloc
#endif
#ifndef GIF_FREE
#include <stdlib.h>
#define GIF_FREE free
#endif
class Gif
{
public:
int kGifTransIndex;
struct GifPalette {
int bitDepth;
uint8_t r[256];
uint8_t g[256];
uint8_t b[256];
// k-d tree over RGB space, organized in heap fashion
// i.e. left child of node i is node i*2, right child is node i*2+1
// nodes 256-511 are implicitly the leaves, containing a color
uint8_t treeSplitElt[255];
uint8_t treeSplit[255];
};
// max, min, and abs functions
int GifIMax(int l, int r) {
return l > r ? l : r;
}
int GifIMin(int l, int r) {
return l < r ? l : r;
}
int GifIAbs(int i) {
return i < 0 ? -i : i;
}
// walks the k-d tree to pick the palette entry for a desired color.
// Takes as in/out parameters the current best color and its error -
// only changes them if it finds a better color in its subtree.
// this is the major hotspot in the code at the moment.
void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int &bestInd, int &bestDiff, int treeRoot = 1) {
// base case, reached the bottom of the tree
if (treeRoot > (1 << pPal->bitDepth) - 1) {
int ind = treeRoot - (1 << pPal->bitDepth);
if (ind == kGifTransIndex) {
return;
}
// check whether this color is better than the current winner
int r_err = r - ((int32_t)pPal->r[ind]);
int g_err = g - ((int32_t)pPal->g[ind]);
int b_err = b - ((int32_t)pPal->b[ind]);
int diff = GifIAbs(r_err) + GifIAbs(g_err) + GifIAbs(b_err);
if (diff < bestDiff) {
bestInd = ind;
bestDiff = diff;
}
return;
}
// take the appropriate color (r, g, or b) for this node of the k-d tree
int comps[3];
comps[0] = r;
comps[1] = g;
comps[2] = b;
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
int splitPos = pPal->treeSplit[treeRoot];
if (splitPos > splitComp) {
// check the left subtree
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2);
if (bestDiff > splitPos - splitComp) {
// cannot prove there's not a better value in the right subtree, check that too
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1);
}
} else {
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1);
if (bestDiff > splitComp - splitPos) {
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2);
}
}
}
void GifSwapPixels(uint8_t *image, int pixA, int pixB) {
uint8_t rA = image[pixA * 4];
uint8_t gA = image[pixA * 4 + 1];
uint8_t bA = image[pixA * 4 + 2];
uint8_t aA = image[pixA * 4 + 3];
uint8_t rB = image[pixB * 4];
uint8_t gB = image[pixB * 4 + 1];
uint8_t bB = image[pixB * 4 + 2];
uint8_t aB = image[pixA * 4 + 3];
image[pixA * 4] = rB;
image[pixA * 4 + 1] = gB;
image[pixA * 4 + 2] = bB;
image[pixA * 4 + 3] = aB;
image[pixB * 4] = rA;
image[pixB * 4 + 1] = gA;
image[pixB * 4 + 2] = bA;
image[pixB * 4 + 3] = aA;
}
// just the partition operation from quicksort
int GifPartition(uint8_t *image, const int left, const int right, const int elt, int pivotIndex) {
const int pivotValue = image[(pivotIndex) * 4 + elt];
GifSwapPixels(image, pivotIndex, right - 1);
int storeIndex = left;
bool split = 0;
for (int ii = left; ii < right - 1; ++ii) {
int arrayVal = image[ii * 4 + elt];
if (arrayVal < pivotValue) {
GifSwapPixels(image, ii, storeIndex);
++storeIndex;
} else if (arrayVal == pivotValue) {
if (split) {
GifSwapPixels(image, ii, storeIndex);
++storeIndex;
}
split = !split;
}
}
GifSwapPixels(image, storeIndex, right - 1);
return storeIndex;
}
// Perform an incomplete sort, finding all elements above and below the desired median
void GifPartitionByMedian(uint8_t *image, int left, int right, int com, int neededCenter) {
if (left < right - 1) {
int pivotIndex = left + (right - left) / 2;
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
// Only "sort" the section of the array that contains the median
if (pivotIndex > neededCenter) {
GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
}
if (pivotIndex < neededCenter) {
GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter);
}
}
}
// Builds a palette by creating a balanced k-d tree of all pixels in the image
void GifSplitPalette(uint8_t *image,
int numPixels, int firstElt,
int lastElt, int splitElt,
int splitDist, int treeNode,
bool buildForDither, GifPalette *pal) {
if (lastElt <= firstElt || numPixels == 0) {
return;
}
// base case, bottom of the tree
if (lastElt == firstElt + 1) {
if (buildForDither) {
// Dithering needs at least one color as dark as anything
// in the image and at least one brightest color -
// otherwise it builds up error and produces strange artifacts
if (firstElt == 1) {
// special case: the darkest color in the image
uint32_t r = 255, g = 255, b = 255;
for (int ii = 0; ii < numPixels; ++ii) {
r = (uint32_t)GifIMin((int32_t)r, image[ii * 4 + 0]);
g = (uint32_t)GifIMin((int32_t)g, image[ii * 4 + 1]);
b = (uint32_t)GifIMin((int32_t)b, image[ii * 4 + 2]);
}
pal->r[firstElt] = (uint8_t)r;
pal->g[firstElt] = (uint8_t)g;
pal->b[firstElt] = (uint8_t)b;
return;
}
if (firstElt == (1 << pal->bitDepth) - 1) {
// special case: the lightest color in the image
uint32_t r = 0, g = 0, b = 0;
for (int ii = 0; ii < numPixels; ++ii) {
r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]);
g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]);
b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]);
}
pal->r[firstElt] = (uint8_t)r;
pal->g[firstElt] = (uint8_t)g;
pal->b[firstElt] = (uint8_t)b;
return;
}
}
// otherwise, take the average of all colors in this subcube
uint64_t r = 0, g = 0, b = 0;
for (int ii = 0; ii < numPixels; ++ii) {
r += image[ii * 4 + 0];
g += image[ii * 4 + 1];
b += image[ii * 4 + 2];
}
r += (uint64_t)numPixels / 2; // round to nearest
g += (uint64_t)numPixels / 2;
b += (uint64_t)numPixels / 2;
r /= (uint64_t)numPixels;
g /= (uint64_t)numPixels;
b /= (uint64_t)numPixels;
pal->r[firstElt] = (uint8_t)r;
pal->g[firstElt] = (uint8_t)g;
pal->b[firstElt] = (uint8_t)b;
return;
}
// Find the axis with the largest range
int minR = 255, maxR = 0;
int minG = 255, maxG = 0;
int minB = 255, maxB = 0;
for (int ii = 0; ii < numPixels; ++ii) {
int r = image[ii * 4 + 0];
int g = image[ii * 4 + 1];
int b = image[ii * 4 + 2];
if (r > maxR) {
maxR = r;
}
if (r < minR) {
minR = r;
}
if (g > maxG) {
maxG = g;
}
if (g < minG) {
minG = g;
}
if (b > maxB) {
maxB = b;
}
if (b < minB) {
minB = b;
}
}
int rRange = maxR - minR;
int gRange = maxG - minG;
int bRange = maxB - minB;
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
int splitCom = 1;
if (bRange > gRange) {
splitCom = 2;
}
if (rRange > bRange && rRange > gRange) {
splitCom = 0;
}
int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt);
int subPixelsB = numPixels - subPixelsA;
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
pal->treeSplitElt[treeNode] = (uint8_t)splitCom;
pal->treeSplit[treeNode] = image[subPixelsA * 4 + splitCom];
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt - splitDist, splitDist / 2, treeNode * 2, buildForDither, pal);
GifSplitPalette(image + subPixelsA * 4, subPixelsB, splitElt, lastElt, splitElt + splitDist, splitDist / 2, treeNode * 2 + 1, buildForDither, pal);
}
// Finds all pixels that have changed from the previous image and
// moves them to the fromt of th buffer.
// This allows us to build a palette optimized for the colors of the
// changed pixels only.
int GifPickChangedPixels(const uint8_t *lastFrame, uint8_t *frame, int numPixels) {
int numChanged = 0;
uint8_t *writeIter = frame;
for (int ii = 0; ii < numPixels; ++ii) {
if (lastFrame[0] != frame[0] ||
lastFrame[1] != frame[1] ||
lastFrame[2] != frame[2]) {
writeIter[0] = frame[0];
writeIter[1] = frame[1];
writeIter[2] = frame[2];
++numChanged;
writeIter += 4;
}
lastFrame += 4;
frame += 4;
}
return numChanged;
}
// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom.
// This is known as the "modified median split" technique
void GifMakePalette(const uint8_t *lastFrame,
const uint8_t *nextFrame,
uint32_t width, uint32_t height,
int bitDepth, bool buildForDither,
GifPalette *pPal) {
pPal->bitDepth = bitDepth;
// SplitPalette is destructive (it sorts the pixels by color) so
// we must create a copy of the image for it to destroy
size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t));
uint8_t *destroyableImage = (uint8_t *)GIF_TEMP_MALLOC(imageSize);
memcpy(destroyableImage, nextFrame, imageSize);
int numPixels = (int)(width * height);
if (lastFrame) {
numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
}
const int lastElt = 1 << bitDepth;
const int splitElt = lastElt / 2;
const int splitDist = splitElt / 2;
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
GIF_TEMP_FREE(destroyableImage);
// add the bottom node for the transparency index
pPal->treeSplit[1 << (bitDepth - 1)] = 0;
pPal->treeSplitElt[1 << (bitDepth - 1)] = 0;
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
}
// Implements Floyd-Steinberg dithering, writes palette value to alpha
void GifDitherImage(const uint8_t *lastFrame, const uint8_t *nextFrame,
uint8_t *outFrame, uint32_t width,
uint32_t height, GifPalette *pPal) {
int numPixels = (int)(width * height);
// quantPixels initially holds color*256 for all pixels
// The extra 8 bits of precision allow for sub-single-color error values
// to be propagated
int32_t *quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4);
for (int ii = 0; ii < numPixels * 4; ++ii) {
uint8_t pix = nextFrame[ii];
int32_t pix16 = int32_t(pix) * 256;
quantPixels[ii] = pix16;
}
for (uint32_t yy = 0; yy < height; ++yy) {
for (uint32_t xx = 0; xx < width; ++xx) {
int32_t *nextPix = quantPixels + 4 * (yy * width + xx);
const uint8_t *lastPix = lastFrame ? lastFrame + 4 * (yy * width + xx) : NULL;
// Compute the colors we want (rounding to nearest)
int32_t rr = (nextPix[0] + 127) / 256;
int32_t gg = (nextPix[1] + 127) / 256;
int32_t bb = (nextPix[2] + 127) / 256;
// if it happens that we want the color from last frame, then just write out
// a transparent pixel
if (lastFrame &&
lastPix[0] == rr &&
lastPix[1] == gg &&
lastPix[2] == bb) {
nextPix[0] = rr;
nextPix[1] = gg;
nextPix[2] = bb;
nextPix[3] = kGifTransIndex;
continue;
}
int32_t bestDiff = 1000000;
int32_t bestInd = kGifTransIndex;
// Search the palete
GifGetClosestPaletteColor(pPal, rr, gg, bb, bestInd, bestDiff);
// Write the result to the temp buffer
int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256;
int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256;
int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256;
nextPix[0] = pPal->r[bestInd];
nextPix[1] = pPal->g[bestInd];
nextPix[2] = pPal->b[bestInd];
nextPix[3] = bestInd;
// Propagate the error to the four adjacent locations
// that we haven't touched yet
int quantloc_7 = (int)(yy * width + xx + 1);
int quantloc_3 = (int)(yy * width + width + xx - 1);
int quantloc_5 = (int)(yy * width + width + xx);
int quantloc_1 = (int)(yy * width + width + xx + 1);
if (quantloc_7 < numPixels) {
int32_t *pix7 = quantPixels + 4 * quantloc_7;
pix7[0] += GifIMax(-pix7[0], r_err * 7 / 16);
pix7[1] += GifIMax(-pix7[1], g_err * 7 / 16);
pix7[2] += GifIMax(-pix7[2], b_err * 7 / 16);
}
if (quantloc_3 < numPixels) {
int32_t *pix3 = quantPixels + 4 * quantloc_3;
pix3[0] += GifIMax(-pix3[0], r_err * 3 / 16);
pix3[1] += GifIMax(-pix3[1], g_err * 3 / 16);
pix3[2] += GifIMax(-pix3[2], b_err * 3 / 16);
}
if (quantloc_5 < numPixels) {
int32_t *pix5 = quantPixels + 4 * quantloc_5;
pix5[0] += GifIMax(-pix5[0], r_err * 5 / 16);
pix5[1] += GifIMax(-pix5[1], g_err * 5 / 16);
pix5[2] += GifIMax(-pix5[2], b_err * 5 / 16);
}
if (quantloc_1 < numPixels) {
int32_t *pix1 = quantPixels + 4 * quantloc_1;
pix1[0] += GifIMax(-pix1[0], r_err / 16);
pix1[1] += GifIMax(-pix1[1], g_err / 16);
pix1[2] += GifIMax(-pix1[2], b_err / 16);
}
}
}
// Copy the palettized result to the output buffer
for (int ii = 0; ii < numPixels * 4; ++ii) {
outFrame[ii] = (uint8_t)quantPixels[ii];
}
GIF_TEMP_FREE(quantPixels);
}
// Picks palette colors for the image using simple thresholding, no dithering
void GifThresholdImage(const uint8_t *lastFrame, const uint8_t *nextFrame,
uint8_t *outFrame, uint32_t width, uint32_t height,
GifPalette *pPal) {
uint32_t numPixels = width * height;
for (uint32_t ii = 0; ii < numPixels; ++ii) {
// if a previous color is available, and it matches the current color,
// set the pixel to transparent
if (lastFrame &&
lastFrame[0] == nextFrame[0] &&
lastFrame[1] == nextFrame[1] &&
lastFrame[2] == nextFrame[2]) {
outFrame[0] = lastFrame[0];
outFrame[1] = lastFrame[1];
outFrame[2] = lastFrame[2];
outFrame[3] = kGifTransIndex;
} else {
// palettize the pixel
int32_t bestDiff = 1000000;
int32_t bestInd = 1;
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], bestInd, bestDiff);
// Write the resulting color to the output buffer
outFrame[0] = pPal->r[bestInd];
outFrame[1] = pPal->g[bestInd];
outFrame[2] = pPal->b[bestInd];
outFrame[3] = (uint8_t)bestInd;
}
if (lastFrame) {
lastFrame += 4;
}
outFrame += 4;
nextFrame += 4;
}
}
// Simple structure to write out the LZW-compressed portion of the image
// one bit at a time
struct GifBitStatus {
uint8_t bitIndex; // how many bits in the partial byte written so far
uint8_t byte; // current partial byte
uint32_t chunkIndex;
uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
};
// insert a single bit
void GifWriteBit(GifBitStatus &stat, uint32_t bit) {
bit = bit & 1;
bit = bit << stat.bitIndex;
stat.byte |= bit;
++stat.bitIndex;
if (stat.bitIndex > 7) {
// move the newly-finished byte to the chunk buffer
stat.chunk[stat.chunkIndex++] = stat.byte;
// and start a new byte
stat.bitIndex = 0;
stat.byte = 0;
}
}
// write all bytes so far to the file
void GifWriteChunk(FILE *f, GifBitStatus &stat) {
fputc((int)stat.chunkIndex, f);
fwrite(stat.chunk, 1, stat.chunkIndex, f);
stat.bitIndex = 0;
stat.byte = 0;
stat.chunkIndex = 0;
}
void GifWriteCode(FILE *f, GifBitStatus &stat, uint32_t code, uint32_t length) {
for (uint32_t ii = 0; ii < length; ++ii) {
GifWriteBit(stat, code);
code = code >> 1;
if (stat.chunkIndex == 255) {
GifWriteChunk(f, stat);
}
}
}
// The LZW dictionary is a 256-ary tree constructed as the file is encoded,
// this is one node
struct GifLzwNode {
uint16_t m_next[256];
};
// write a 256-color (8-bit) image palette to the file
void GifWritePalette(const GifPalette *pPal, FILE *f) {
fputc(0, f); // first color: transparency
fputc(0, f);
fputc(0, f);
for (int ii = 1; ii < (1 << pPal->bitDepth); ++ii) {
uint32_t r = pPal->r[ii];
uint32_t g = pPal->g[ii];
uint32_t b = pPal->b[ii];
fputc((int)r, f);
fputc((int)g, f);
fputc((int)b, f);
}
}
// write the image header, LZW-compress and write out the image
void GifWriteLzwImage(FILE *f, uint8_t *image, uint32_t left,
uint32_t top, uint32_t width,
uint32_t height, uint32_t delay,
GifPalette *pPal) {
// graphics control extension
fputc(0x21, f);
fputc(0xf9, f);
fputc(0x04, f);
fputc(0x05, f); // leave prev frame in place, this frame has transparency
fputc(delay & 0xff, f);
fputc((delay >> 8) & 0xff, f);
fputc(kGifTransIndex, f); // transparent color index
fputc(0, f);
fputc(0x2c, f); // image descriptor block
fputc(left & 0xff, f); // corner of image in canvas space
fputc((left >> 8) & 0xff, f);
fputc(top & 0xff, f);
fputc((top >> 8) & 0xff, f);
fputc(width & 0xff, f); // width and height of image
fputc((width >> 8) & 0xff, f);
fputc(height & 0xff, f);
fputc((height >> 8) & 0xff, f);
//fputc(0, f); // no local color table, no transparency
//fputc(0x80, f); // no local color table, but transparency
fputc(0x80 + pPal->bitDepth - 1, f); // local color table present, 2 ^ bitDepth entries
GifWritePalette(pPal, f);
const int minCodeSize = pPal->bitDepth;
const uint32_t clearCode = 1 << pPal->bitDepth;
fputc(minCodeSize, f); // min code size 8 bits
GifLzwNode *codetree = (GifLzwNode *)GIF_TEMP_MALLOC(sizeof(GifLzwNode) * 4096);
memset(codetree, 0, sizeof(GifLzwNode) * 4096);
int32_t curCode = -1;
uint32_t codeSize = (uint32_t)minCodeSize + 1;
uint32_t maxCode = clearCode + 1;
GifBitStatus stat;
stat.byte = 0;
stat.bitIndex = 0;
stat.chunkIndex = 0;
GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary
for (uint32_t yy = 0; yy < height; ++yy) {
for (uint32_t xx = 0; xx < width; ++xx) {
uint8_t nextValue = image[(yy * width + xx) * 4 + 3];
// "loser mode" - no compression, every single code is followed immediately by a clear
//WriteCode( f, stat, nextValue, codeSize );
//WriteCode( f, stat, 256, codeSize );
if (curCode < 0) {
// first value in a new run
curCode = nextValue;
} else if (codetree[curCode].m_next[nextValue]) {
// current run already in the dictionary
curCode = codetree[curCode].m_next[nextValue];
} else {
// finish the current run, write a code
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
// insert the new run into the dictionary
codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode;
if (maxCode >= (1ul << codeSize)) {
// dictionary entry count has broken a size barrier,
// we need more bits for codes
codeSize++;
}
if (maxCode == 4095) {
// the dictionary is full, clear it out and begin anew
GifWriteCode(f, stat, clearCode, codeSize); // clear tree
memset(codetree, 0, sizeof(GifLzwNode) * 4096);
codeSize = (uint32_t)(minCodeSize + 1);
maxCode = clearCode + 1;
}
curCode = nextValue;
}
}
}
// compression footer
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
GifWriteCode(f, stat, clearCode, codeSize);
GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1);
// write out the last partial chunk
while (stat.bitIndex) {
GifWriteBit(stat, 0);
}
if (stat.chunkIndex) {
GifWriteChunk(f, stat);
}
fputc(0, f); // image block terminator
GIF_TEMP_FREE(codetree);
}
struct GifWriter {
FILE *f;
uint8_t *oldImage;
bool firstFrame;
};
// Creates a gif file.
// The input GIFWriter is assumed to be uninitialized.
// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value.
bool GifBegin(GifWriter *writer, const char *filename,
uint32_t width, uint32_t height,
uint32_t delay, int32_t bitDepth = 8,
bool dither = false) {
(void)bitDepth;
(void)dither; // Mute "Unused argument" warnings
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
writer->f = 0;
fopen_s(&writer->f, filename, "wb");
#else
writer->f = fopen(filename, "wb");
#endif
if (!writer->f) {
return false;
}
writer->firstFrame = true;
// allocate
writer->oldImage = (uint8_t *)GIF_MALLOC(width * height * 4);
fputs("GIF89a", writer->f);
// screen descriptor
fputc(width & 0xff, writer->f);
fputc((width >> 8) & 0xff, writer->f);
fputc(height & 0xff, writer->f);
fputc((height >> 8) & 0xff, writer->f);
fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries
fputc(0, writer->f); // background color
fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989)
// now the "global" palette (really just a dummy palette)
// color 0: black
fputc(0, writer->f);
fputc(0, writer->f);
fputc(0, writer->f);
// color 1: also black
fputc(0, writer->f);
fputc(0, writer->f);
fputc(0, writer->f);
if (delay != 0) {
// animation header
fputc(0x21, writer->f); // extension
fputc(0xff, writer->f); // application specific
fputc(11, writer->f); // length 11
fputs("NETSCAPE2.0", writer->f); // yes, really
fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data
fputc(1, writer->f); // JUST BECAUSE
fputc(0, writer->f); // loop infinitely (byte 0)
fputc(0, writer->f); // loop infinitely (byte 1)
fputc(0, writer->f); // block terminator
}
return true;
}
// Writes out a new frame to a GIF in progress.
// The GIFWriter should have been created by GIFBegin.
// AFAIK, it is legal to use different bit depths for different frames of an image -
// this may be handy to save bits in animations that don't change much.
bool GifWriteFrame(GifWriter *writer, const uint8_t *image,
uint32_t width, uint32_t height,
uint32_t delay, int bitDepth = 8, bool dither = false) {
if (!writer->f) {
return false;
}
const uint8_t *oldImage = writer->firstFrame ? NULL : writer->oldImage;
writer->firstFrame = false;
GifPalette pal;
GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
if (dither) {
GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal);
} else {
GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal);
}
GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);
return true;
}
// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF.
// Many if not most viewers will still display a GIF properly if the EOF code is missing,
// but it's still a good idea to write it out.
bool GifEnd(GifWriter *writer) {
if (!writer->f) {
return false;
}
fputc(0x3b, writer->f); // end of file
fclose(writer->f);
GIF_FREE(writer->oldImage);
writer->f = NULL;
writer->oldImage = NULL;
return true;
}
};
#endif

View File

@@ -0,0 +1,382 @@
#pragma execution_character_set("utf-8")
#include "gifwidget.h"
#include "qmutex.h"
#include "qlabel.h"
#include "qlineedit.h"
#include "qpushbutton.h"
#include "qlayout.h"
#include "qpainter.h"
#include "qevent.h"
#include "qstyle.h"
#include "qpixmap.h"
#include "qtimer.h"
#include "qdatetime.h"
#include "qapplication.h"
#include "qdesktopservices.h"
#include "qfiledialog.h"
#include "qurl.h"
#include "qtextcodec.h"
#include "qdebug.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
#include "qscreen.h"
#define deskGeometry qApp->primaryScreen()->geometry()
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
#else
#include "qdesktopwidget.h"
#define deskGeometry qApp->desktop()->geometry()
#define deskGeometry2 qApp->desktop()->availableGeometry()
#endif
QScopedPointer<GifWidget> GifWidget::self;
GifWidget *GifWidget::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new GifWidget);
}
}
return self.data();
}
GifWidget::GifWidget(QWidget *parent) : QDialog(parent)
{
this->initControl();
this->initForm();
}
bool GifWidget::eventFilter(QObject *watched, QEvent *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() - this->pos();
return true;
}
} else if (mouseEvent->type() == QEvent::MouseButtonRelease) {
mousePressed = false;
return true;
} else if (mouseEvent->type() == QEvent::MouseMove) {
if (mousePressed) {
this->move(mouseEvent->globalPos() - mousePoint);
return true;
}
}
return QWidget::eventFilter(watched, event);
}
void GifWidget::resizeEvent(QResizeEvent *e)
{
//拉动右下角改变大小自动赋值
txtWidth->setText(QString::number(widgetMain->width()));
txtHeight->setText(QString::number(widgetMain->height()));
QDialog::resizeEvent(e);
}
void GifWidget::paintEvent(QPaintEvent *)
{
int width = txtWidth->text().toInt();
int height = txtHeight->text().toInt();
rectGif = QRect(borderWidth, widgetTop->height(), width - (borderWidth * 2), height);
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setBrush(bgColor);
painter.drawRoundedRect(this->rect(), 5, 5);
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.fillRect(rectGif, Qt::SolidPattern);
}
int GifWidget::getBorderWidth() const
{
return this->borderWidth;
}
QColor GifWidget::getBgColor() const
{
return this->bgColor;
}
void GifWidget::initControl()
{
this->setObjectName("GifWidget");
this->resize(800, 600);
this->setSizeGripEnabled(true);
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName("verticalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0);
widgetTop = new QWidget(this);
widgetTop->setObjectName("widgetTop");
widgetTop->setMinimumSize(QSize(0, 35));
widgetTop->setMaximumSize(QSize(16777215, 35));
QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop);
layoutTop->setSpacing(0);
layoutTop->setContentsMargins(11, 11, 11, 11);
layoutTop->setObjectName("layoutTop");
layoutTop->setContentsMargins(0, 0, 0, 0);
QPushButton *btnIcon = new QPushButton(widgetTop);
btnIcon->setObjectName("btnIcon");
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(btnIcon->sizePolicy().hasHeightForWidth());
btnIcon->setSizePolicy(sizePolicy);
btnIcon->setMinimumSize(QSize(35, 0));
btnIcon->setFlat(true);
layoutTop->addWidget(btnIcon);
QLabel *labTitle = new QLabel(widgetTop);
labTitle->setObjectName("labTitle");
layoutTop->addWidget(labTitle);
QSpacerItem *horizontalSpacer = new QSpacerItem(87, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
layoutTop->addItem(horizontalSpacer);
QPushButton *btnClose = new QPushButton(widgetTop);
btnClose->setObjectName("btnClose");
sizePolicy.setHeightForWidth(btnClose->sizePolicy().hasHeightForWidth());
btnClose->setSizePolicy(sizePolicy);
btnClose->setMinimumSize(QSize(35, 0));
btnClose->setFocusPolicy(Qt::NoFocus);
btnClose->setFlat(true);
layoutTop->addWidget(btnClose);
verticalLayout->addWidget(widgetTop);
widgetMain = new QWidget(this);
widgetMain->setObjectName("widgetMain");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(widgetMain->sizePolicy().hasHeightForWidth());
widgetMain->setSizePolicy(sizePolicy1);
verticalLayout->addWidget(widgetMain);
widgetBottom = new QWidget(this);
widgetBottom->setObjectName("widgetBottom");
widgetBottom->setMinimumSize(QSize(0, 45));
widgetBottom->setMaximumSize(QSize(16777215, 45));
QHBoxLayout *layoutBottom = new QHBoxLayout(widgetBottom);
layoutBottom->setSpacing(6);
layoutBottom->setContentsMargins(11, 11, 11, 11);
layoutBottom->setObjectName("layoutBottom");
layoutBottom->setContentsMargins(9, 9, -1, -1);
QLabel *labFps = new QLabel(widgetBottom);
labFps->setObjectName("labFps");
layoutBottom->addWidget(labFps);
txtFps = new QLineEdit(widgetBottom);
txtFps->setObjectName("txtFps");
txtFps->setMaximumSize(QSize(50, 16777215));
txtFps->setAlignment(Qt::AlignCenter);
layoutBottom->addWidget(txtFps);
QLabel *labWidth = new QLabel(widgetBottom);
labWidth->setObjectName("labWidth");
layoutBottom->addWidget(labWidth);
txtWidth = new QLineEdit(widgetBottom);
txtWidth->setObjectName("txtWidth");
txtWidth->setEnabled(true);
txtWidth->setMaximumSize(QSize(50, 16777215));
txtWidth->setAlignment(Qt::AlignCenter);
layoutBottom->addWidget(txtWidth);
QLabel *labHeight = new QLabel(widgetBottom);
labHeight->setObjectName("labHeight");
layoutBottom->addWidget(labHeight);
txtHeight = new QLineEdit(widgetBottom);
txtHeight->setObjectName("txtHeight");
txtHeight->setEnabled(true);
txtHeight->setMaximumSize(QSize(50, 16777215));
txtHeight->setAlignment(Qt::AlignCenter);
layoutBottom->addWidget(txtHeight);
labStatus = new QLabel(widgetBottom);
labStatus->setObjectName("labStatus");
QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Preferred);
sizePolicy2.setHorizontalStretch(0);
sizePolicy2.setVerticalStretch(0);
sizePolicy2.setHeightForWidth(labStatus->sizePolicy().hasHeightForWidth());
labStatus->setSizePolicy(sizePolicy2);
labStatus->setAlignment(Qt::AlignCenter);
layoutBottom->addWidget(labStatus);
btnStart = new QPushButton(widgetBottom);
btnStart->setObjectName("btnStart");
sizePolicy.setHeightForWidth(btnStart->sizePolicy().hasHeightForWidth());
btnStart->setSizePolicy(sizePolicy);
layoutBottom->addWidget(btnStart);
verticalLayout->addWidget(widgetBottom);
labTitle->setText("GIF录屏工具(QQ:517216493)");
labFps->setText("帧率");
labWidth->setText("宽度");
labHeight->setText("高度");
btnStart->setText("开始");
this->setWindowTitle(labTitle->text());
btnIcon->setIcon(style()->standardIcon(QStyle::SP_ComputerIcon));
btnClose->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
connect(btnClose, SIGNAL(clicked(bool)), this, SLOT(closeAll()));
connect(btnStart, SIGNAL(clicked(bool)), this, SLOT(record()));
connect(txtWidth, SIGNAL(editingFinished()), this, SLOT(resizeForm()));
connect(txtHeight, SIGNAL(editingFinished()), this, SLOT(resizeForm()));
}
void GifWidget::initForm()
{
borderWidth = 3;
bgColor = QColor(34, 163, 169);
fps = 10;
txtFps->setText(QString::number(fps));
gifWriter = 0;
timer = new QTimer(this);
timer->setInterval(100);
connect(timer, SIGNAL(timeout()), this, SLOT(saveImage()));
this->setAttribute(Qt::WA_TranslucentBackground);
this->setWindowFlags(Qt::FramelessWindowHint);
this->installEventFilter(this);
QStringList qss;
qss.append("QLabel{color:#ffffff;}");
qss.append("#btnClose,#btnIcon{border:none;border-radius:0px;}");
qss.append("#btnClose:hover{background-color:#ff0000;}");
qss.append("#btnClose{border-top-right-radius:5px;}");
qss.append("#labTitle{font:bold 16px;}");
qss.append("#labStatus{font:15px;}");
this->setStyleSheet(qss.join(""));
}
void GifWidget::saveImage()
{
if (!gifWriter) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
QScreen *screen = QApplication::primaryScreen();
QPixmap pix = screen->grabWindow(0, x() + rectGif.x(), y() + rectGif.y(), rectGif.width(), rectGif.height());
QImage image = pix.toImage().convertToFormat(QImage::Format_RGBA8888);
#else
//由于qt4没有RGBA8888,采用最接近RGBA8888的是ARGB32,颜色会有点偏差
QPixmap pix = QPixmap::grabWindow(0, x() + rectGif.x(), y() + rectGif.y(), rectGif.width(), rectGif.height());
QImage image = pix.toImage().convertToFormat(QImage::Format_ARGB32);
#endif
gif.GifWriteFrame(gifWriter, image.bits(), rectGif.width(), rectGif.height(), fps);
count++;
labStatus->setText(QString("正在录制 第 %1 帧").arg(count));
}
void GifWidget::record()
{
if (btnStart->text() == "开始") {
if (0 != gifWriter) {
delete gifWriter;
gifWriter = 0;
}
//先弹出文件保存对话框
//fileName = qApp->applicationDirPath() + "/" + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss.gif");
fileName = QFileDialog::getSaveFileName(this, "选择保存位置", qApp->applicationDirPath() + "/", "gif图片(*.gif)");
if (fileName.isEmpty()) {
return;
}
int width = txtWidth->text().toInt();
int height = txtHeight->text().toInt();
fps = txtFps->text().toInt();
#ifdef Q_OS_WIN
//windows上需要先转码
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
QTextCodec *code = QTextCodec::codecForName("utf-8");
#else
QTextCodec *code = QTextCodec::codecForName("gbk");
#endif
const char *name = code->fromUnicode(fileName).constData();
#else
const char *name = fileName.toUtf8().constData();
#endif
gifWriter = new Gif::GifWriter;
bool ok = gif.GifBegin(gifWriter, name, width, height, fps);
if (!ok) {
delete gifWriter;
gifWriter = 0;
return;
}
count = 0;
labStatus->setText("开始录制...");
btnStart->setText("停止");
//延时启动
timer->setInterval(1000 / fps);
QTimer::singleShot(1000, timer, SLOT(start()));
//saveImage();
} else {
timer->stop();
gif.GifEnd(gifWriter);
delete gifWriter;
gifWriter = 0;
labStatus->setText(QString("录制完成 共 %1 帧").arg(count));
btnStart->setText("开始");
QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
}
}
void GifWidget::closeAll()
{
if (0 != gifWriter) {
delete gifWriter;
gifWriter = 0;
}
this->close();
}
void GifWidget::resizeForm()
{
int width = txtWidth->text().toInt();
int height = txtHeight->text().toInt();
this->resize(width, height + widgetTop->height() + widgetBottom->height());
}
void GifWidget::setBorderWidth(int borderWidth)
{
if (this->borderWidth != borderWidth) {
this->borderWidth = borderWidth;
this->update();
}
}
void GifWidget::setBgColor(const QColor &bgColor)
{
if (this->bgColor != bgColor) {
this->bgColor = bgColor;
this->update();
}
}

View File

@@ -0,0 +1,80 @@
#ifndef GIFWIDGET_H
#define GIFWIDGET_H
/**
* GIF录屏控件 作者:feiyangqingyun(QQ:517216493) 2019-04-03
* 1. 可设置要录制屏幕的宽高,支持右下角直接拉动改变。
* 2. 可设置变宽的宽度。
* 3. 可设置录屏控件的背景颜色。
* 4. 可设置录制的帧数。
* 5. 录制区域可自由拖动选择。
*/
#include <QDialog>
#include "gif.h"
class QLineEdit;
class QLabel;
#ifdef quc
class Q_DECL_EXPORT GifWidget : public QDialog
#else
class GifWidget : public QDialog
#endif
{
Q_OBJECT
Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth)
Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
public:
static GifWidget *Instance();
explicit GifWidget(QWidget *parent = 0);
protected:
bool eventFilter(QObject *watched, QEvent *event);
void resizeEvent(QResizeEvent *);
void paintEvent(QPaintEvent *);
private:
static QScopedPointer<GifWidget> self;
QWidget *widgetTop; //标题栏
QWidget *widgetMain; //中间部分
QWidget *widgetBottom; //底部栏
QLineEdit *txtFps; //帧率输入框
QLineEdit *txtWidth; //宽度输入框
QLineEdit *txtHeight; //高度输入框
QPushButton *btnStart; //开始按钮
QLabel *labStatus; //显示状态信息
int fps; //帧数 100为1s
int borderWidth; //边框宽度
QColor bgColor; //背景颜色
int count; //帧数计数
QString fileName; //保存文件名称
QRect rectGif; //截屏区域
QTimer *timer; //截屏定时器
Gif gif; //gif类对象
Gif::GifWriter *gifWriter; //gif写入对象
public:
int getBorderWidth() const;
QColor getBgColor() const;
private slots:
void initControl();
void initForm();
void saveImage();
void record();
void closeAll();
void resizeForm();
public Q_SLOTS:
void setBorderWidth(int borderWidth);
void setBgColor(const QColor &bgColor);
};
#endif // GIFWIDGET_H

View File

@@ -0,0 +1,19 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = gifwidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmgifwidget.cpp
SOURCES += gifwidget.cpp
HEADERS += gifwidget.h
HEADERS += frmgifwidget.h
HEADERS += gif.h
FORMS += frmgifwidget.ui
RESOURCES += main.qrc

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

37
widget/gifwidget/main.cpp Normal file
View File

@@ -0,0 +1,37 @@
#pragma execution_character_set("utf-8")
#include "frmgifwidget.h"
#include <QApplication>
#include <QTextCodec>
#include <QIcon>
#include <QDebug>
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);
a.setFont(QFont("Microsoft Yahei", 9));
a.setWindowIcon(QIcon(":/image/gifwidget.ico"));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmGifWidget w;
w.setWindowTitle("GIF录屏");
w.show();
return a.exec();
}

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>image/gifwidget.ico</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,38 @@
#include "frmlunarcalendarwidget.h"
#include "ui_frmlunarcalendarwidget.h"
frmLunarCalendarWidget::frmLunarCalendarWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmLunarCalendarWidget)
{
ui->setupUi(this);
this->initForm();
}
frmLunarCalendarWidget::~frmLunarCalendarWidget()
{
delete ui;
}
void frmLunarCalendarWidget::initForm()
{
ui->cboxWeekNameFormat->setCurrentIndex(2);
}
void frmLunarCalendarWidget::on_cboxCalendarStyle_currentIndexChanged(int index)
{
ui->lunarCalendarWidget->setCalendarStyle((LunarCalendarWidget::CalendarStyle)index);
}
void frmLunarCalendarWidget::on_cboxSelectType_currentIndexChanged(int index)
{
ui->lunarCalendarWidget->setSelectType((LunarCalendarWidget::SelectType)index);
}
void frmLunarCalendarWidget::on_cboxWeekNameFormat_currentIndexChanged(int index)
{
ui->lunarCalendarWidget->setWeekNameFormat((LunarCalendarWidget::WeekNameFormat)index);
}
void frmLunarCalendarWidget::on_ckShowLunar_stateChanged(int arg1)
{
ui->lunarCalendarWidget->setShowLunar(arg1 != 0);
}

View File

@@ -0,0 +1,29 @@
#ifndef FRMLUNARCALENDARWIDGET_H
#define FRMLUNARCALENDARWIDGET_H
#include <QWidget>
namespace Ui {
class frmLunarCalendarWidget;
}
class frmLunarCalendarWidget : public QWidget
{
Q_OBJECT
public:
explicit frmLunarCalendarWidget(QWidget *parent = 0);
~frmLunarCalendarWidget();
private:
Ui::frmLunarCalendarWidget *ui;
private slots:
void initForm();
void on_cboxCalendarStyle_currentIndexChanged(int index);
void on_cboxSelectType_currentIndexChanged(int index);
void on_cboxWeekNameFormat_currentIndexChanged(int index);
void on_ckShowLunar_stateChanged(int arg1);
};
#endif // FRMLUNARCALENDARWIDGET_H

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmLunarCalendarWidget</class>
<widget class="QWidget" name="frmLunarCalendarWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LunarCalendarWidget" name="lunarCalendarWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetBottom" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<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="QLabel" name="labCalendarStyle">
<property name="text">
<string>整体样式</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxCalendarStyle">
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>红色风格</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="labSelectType">
<property name="text">
<string>选中样式</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxSelectType">
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>矩形背景</string>
</property>
</item>
<item>
<property name="text">
<string>圆形背景</string>
</property>
</item>
<item>
<property name="text">
<string>角标背景</string>
</property>
</item>
<item>
<property name="text">
<string>图片背景</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="labWeekNameFormat">
<property name="text">
<string>星期格式</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxWeekNameFormat">
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>短名称</string>
</property>
</item>
<item>
<property name="text">
<string>普通名称</string>
</property>
</item>
<item>
<property name="text">
<string>长名称</string>
</property>
</item>
<item>
<property name="text">
<string>英文名称</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckShowLunar">
<property name="text">
<string>显示农历</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LunarCalendarWidget</class>
<extends>QWidget</extends>
<header>lunarcalendarwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,796 @@
#pragma execution_character_set("utf-8")
#include "lunarcalendarinfo.h"
#include "qmutex.h"
#include "qdebug.h"
#define year_2099
QScopedPointer<LunarCalendarInfo> LunarCalendarInfo::self;
LunarCalendarInfo *LunarCalendarInfo::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new LunarCalendarInfo);
}
}
return self.data();
}
LunarCalendarInfo::LunarCalendarInfo(QObject *parent) : QObject(parent)
{
//农历查表
lunarCalendarTable << 0x04AE53 << 0x0A5748 << 0x5526BD << 0x0D2650 << 0x0D9544 << 0x46AAB9 << 0x056A4D << 0x09AD42 << 0x24AEB6 << 0x04AE4A; //1901-1910
lunarCalendarTable << 0x6A4DBE << 0x0A4D52 << 0x0D2546 << 0x5D52BA << 0x0B544E << 0x0D6A43 << 0x296D37 << 0x095B4B << 0x749BC1 << 0x049754; //1911-1920
lunarCalendarTable << 0x0A4B48 << 0x5B25BC << 0x06A550 << 0x06D445 << 0x4ADAB8 << 0x02B64D << 0x095742 << 0x2497B7 << 0x04974A << 0x664B3E; //1921-1930
lunarCalendarTable << 0x0D4A51 << 0x0EA546 << 0x56D4BA << 0x05AD4E << 0x02B644 << 0x393738 << 0x092E4B << 0x7C96BF << 0x0C9553 << 0x0D4A48; //1931-1940
lunarCalendarTable << 0x6DA53B << 0x0B554F << 0x056A45 << 0x4AADB9 << 0x025D4D << 0x092D42 << 0x2C95B6 << 0x0A954A << 0x7B4ABD << 0x06CA51; //1941-1950
lunarCalendarTable << 0x0B5546 << 0x555ABB << 0x04DA4E << 0x0A5B43 << 0x352BB8 << 0x052B4C << 0x8A953F << 0x0E9552 << 0x06AA48 << 0x6AD53C; //1951-1960
lunarCalendarTable << 0x0AB54F << 0x04B645 << 0x4A5739 << 0x0A574D << 0x052642 << 0x3E9335 << 0x0D9549 << 0x75AABE << 0x056A51 << 0x096D46; //1961-1970
lunarCalendarTable << 0x54AEBB << 0x04AD4F << 0x0A4D43 << 0x4D26B7 << 0x0D254B << 0x8D52BF << 0x0B5452 << 0x0B6A47 << 0x696D3C << 0x095B50; //1971-1980
lunarCalendarTable << 0x049B45 << 0x4A4BB9 << 0x0A4B4D << 0xAB25C2 << 0x06A554 << 0x06D449 << 0x6ADA3D << 0x0AB651 << 0x093746 << 0x5497BB; //1981-1990
lunarCalendarTable << 0x04974F << 0x064B44 << 0x36A537 << 0x0EA54A << 0x86B2BF << 0x05AC53 << 0x0AB647 << 0x5936BC << 0x092E50 << 0x0C9645; //1991-2000
lunarCalendarTable << 0x4D4AB8 << 0x0D4A4C << 0x0DA541 << 0x25AAB6 << 0x056A49 << 0x7AADBD << 0x025D52 << 0x092D47 << 0x5C95BA << 0x0A954E; //2001-2010
lunarCalendarTable << 0x0B4A43 << 0x4B5537 << 0x0AD54A << 0x955ABF << 0x04BA53 << 0x0A5B48 << 0x652BBC << 0x052B50 << 0x0A9345 << 0x474AB9; //2011-2020
lunarCalendarTable << 0x06AA4C << 0x0AD541 << 0x24DAB6 << 0x04B64A << 0x69573D << 0x0A4E51 << 0x0D2646 << 0x5E933A << 0x0D534D << 0x05AA43; //2021-2030
lunarCalendarTable << 0x36B537 << 0x096D4B << 0xB4AEBF << 0x04AD53 << 0x0A4D48 << 0x6D25BC << 0x0D254F << 0x0D5244 << 0x5DAA38 << 0x0B5A4C; //2031-2040
lunarCalendarTable << 0x056D41 << 0x24ADB6 << 0x049B4A << 0x7A4BBE << 0x0A4B51 << 0x0AA546 << 0x5B52BA << 0x06D24E << 0x0ADA42 << 0x355B37; //2041-2050
lunarCalendarTable << 0x09374B << 0x8497C1 << 0x049753 << 0x064B48 << 0x66A53C << 0x0EA54F << 0x06B244 << 0x4AB638 << 0x0AAE4C << 0x092E42; //2051-2060
lunarCalendarTable << 0x3C9735 << 0x0C9649 << 0x7D4ABD << 0x0D4A51 << 0x0DA545 << 0x55AABA << 0x056A4E << 0x0A6D43 << 0x452EB7 << 0x052D4B; //2061-2070
lunarCalendarTable << 0x8A95BF << 0x0A9553 << 0x0B4A47 << 0x6B553B << 0x0AD54F << 0x055A45 << 0x4A5D38 << 0x0A5B4C << 0x052B42 << 0x3A93B6; //2071-2080
lunarCalendarTable << 0x069349 << 0x7729BD << 0x06AA51 << 0x0AD546 << 0x54DABA << 0x04B64E << 0x0A5743 << 0x452738 << 0x0D264A << 0x8E933E; //2081-2090
lunarCalendarTable << 0x0D5252 << 0x0DAA47 << 0x66B53B << 0x056D4F << 0x04AE45 << 0x4A4EB9 << 0x0A4D4C << 0x0D1541 << 0x2D92B5; //2091-2099
//每年春节对应的公历日期
springFestival << 130 << 217 << 206; // 1968 1969 1970
springFestival << 127 << 215 << 203 << 123 << 211 << 131 << 218 << 207 << 128 << 216; // 1971--1980
springFestival << 205 << 125 << 213 << 202 << 220 << 209 << 219 << 217 << 206 << 127; // 1981--1990
springFestival << 215 << 204 << 123 << 210 << 131 << 219 << 207 << 128 << 216 << 205; // 1991--2000
springFestival << 124 << 212 << 201 << 122 << 209 << 129 << 218 << 207 << 126 << 214; // 2001--2010
springFestival << 203 << 123 << 210 << 131 << 219 << 208 << 128 << 216 << 205 << 125; // 2011--2020
springFestival << 212 << 201 << 122 << 210 << 129 << 217 << 206 << 126 << 213 << 203; // 2021--2030
springFestival << 123 << 211 << 131 << 219 << 208 << 128 << 215 << 204 << 124 << 212; // 2031--2040
//16--18位表示闰几月 0--12位表示农历每月的数据 高位表示1月 低位表示12月(农历闰月就会多一个月)
lunarData << 461653 << 1386 << 2413; // 1968 1969 1970
lunarData << 330077 << 1197 << 2637 << 268877 << 3365 << 531109 << 2900 << 2922 << 398042 << 2395; // 1971--1980
lunarData << 1179 << 267415 << 2635 << 661067 << 1701 << 1748 << 398772 << 2742 << 2391 << 330031; // 1981--1990
lunarData << 1175 << 1611 << 200010 << 3749 << 527717 << 1452 << 2742 << 332397 << 2350 << 3222; // 1991--2000
lunarData << 268949 << 3402 << 3493 << 133973 << 1386 << 464219 << 605 << 2349 << 334123 << 2709; // 2001--2010
lunarData << 2890 << 267946 << 2773 << 592565 << 1210 << 2651 << 395863 << 1323 << 2707 << 265877; // 2011--2020
lunarData << 1706 << 2773 << 133557 << 1206 << 398510 << 2638 << 3366 << 335142 << 3411 << 1450; // 2021--2030
lunarData << 200042 << 2413 << 723293 << 1197 << 2637 << 399947 << 3365 << 3410 << 334676 << 2906; // 2031--2040
//二十四节气表
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1970
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x79 << 0x69 << 0x78 << 0x77; // 1971
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1972
chineseTwentyFourData << 0xA5 << 0xB5 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1973
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1974
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1975
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x89 << 0x88 << 0x78 << 0x87 << 0x87; // 1976
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1977
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 1978
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1979
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1980
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x77 << 0x87; // 1981
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1982
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1983
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1984
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1985
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1986
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x79 << 0x78 << 0x69 << 0x78 << 0x87; // 1987
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1988
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1989
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1990
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x86 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1991
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1992
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1993
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1994
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x76 << 0x78 << 0x69 << 0x78 << 0x87; // 1995
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1996
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1997
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1998
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1999
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2000
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2001
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2002
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2003
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2004
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2005
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2006
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2007
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2008
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2009
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2010
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2011
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2012
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2013
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2014
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2015
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2016
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2017
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2018
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2019
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2020
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2021
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2022
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2023
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2024
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2025
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2026
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2027
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2028
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2029
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2030
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2031
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2032
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2033
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x78 << 0x88 << 0x78 << 0x87 << 0x87; // 2034
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2035
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2036
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2037
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2038
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2039
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2040
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2041
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2042
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2043
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2044
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2045
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2046
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2047
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2048
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2049
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2050
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2051
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2052
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2053
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2054
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2055
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2056
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2057
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2058
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2059
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2060
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2061
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2062
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2063
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2064
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2065
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2066
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2067
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2068
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2069
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2070
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2071
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2072
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2073
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2074
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2075
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2076
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2077
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2078
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2079
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2080
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2081
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2082
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2083
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2084
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2085
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2086
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2087
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2088
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x96 << 0x96; // 2089
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2090
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2091
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2092
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x87 << 0x96 << 0x96; // 2093
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2094
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2095
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2096
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x97 << 0x87 << 0x87 << 0x96 << 0x96; // 2097
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2098
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2099
//公历每月前面的天数
monthAdd << 0 << 31 << 59 << 90 << 120 << 151 << 181 << 212 << 243 << 273 << 304 << 334;
//农历日期名称
listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十"
<< "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十"
<< "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十";
//农历月份名称
listMonthName << "*" << "正月" << "二月" << "三月" << "四月" << "五月" << "六月" << "七月" << "八月" << "九月" << "十月" << "冬月" << "腊月";
//二十四节气名称
listSolarTerm << "小寒" << "大寒" << "立春" << "雨水" << "惊蛰" << "春分" << "清明" << "谷雨"
<< "立夏" << "小满" << "芒种" << "夏至" << "小暑" << "大暑" << "立秋" << "处暑"
<< "白露" << "秋分" << "寒露" << "霜降" << "立冬" << "小雪" << "大雪" << "冬至";
//天干
listTianGan << "" << "" << "" << "" << "" << "" << "" << "" << "" << "";
//地支
listDiZhi << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "";
//属相
listShuXiang << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "";
}
//计算是否闰年
bool LunarCalendarInfo::isLoopYear(int year)
{
return (((0 == (year % 4)) && (0 != (year % 100))) || (0 == (year % 400)));
}
//计算指定年月该月共多少天
int LunarCalendarInfo::getMonthDays(int year, int month)
{
int countDay = 0;
int loopDay = isLoopYear(year) ? 1 : 0;
switch (month) {
case 1:
countDay = 31;
break;
case 2:
countDay = 28 + loopDay;
break;
case 3:
countDay = 31;
break;
case 4:
countDay = 30;
break;
case 5:
countDay = 31;
break;
case 6:
countDay = 30;
break;
case 7:
countDay = 31;
break;
case 8:
countDay = 31;
break;
case 9:
countDay = 30;
break;
case 10:
countDay = 31;
break;
case 11:
countDay = 30;
break;
case 12:
countDay = 31;
break;
default:
countDay = 30;
break;
}
return countDay;
}
//计算指定年月对应到该月共多少天
int LunarCalendarInfo::getTotalMonthDays(int year, int month)
{
int countDay = 0;
int loopDay = isLoopYear(year) ? 1 : 0;
switch (month) {
case 1:
countDay = 0;
break;
case 2:
countDay = 31;
break;
case 3:
countDay = 59 + loopDay;
break;
case 4:
countDay = 90 + loopDay;
break;
case 5:
countDay = 120 + loopDay;
break;
case 6:
countDay = 151 + loopDay;
break;
case 7:
countDay = 181 + loopDay;
break;
case 8:
countDay = 212 + loopDay;
break;
case 9:
countDay = 243 + loopDay;
break;
case 10:
countDay = 273 + loopDay;
break;
case 11:
countDay = 304 + loopDay;
break;
case 12:
countDay = 334 + loopDay;
break;
default:
countDay = 0;
break;
}
return countDay;
}
//计算指定年月对应星期几
int LunarCalendarInfo::getFirstDayOfWeek(int year, int month)
{
int week = 0;
week = (year + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400) % 7;
week += getTotalMonthDays(year, month);
week = week % 7;
return week;
}
//计算国际节日
QString LunarCalendarInfo::getHoliday(int month, int day)
{
int temp = (month << 8) | day;
QString strHoliday;
switch (temp) {
case 0x0101:
strHoliday = "元旦";
break;
case 0x020E:
strHoliday = "情人节";
break;
case 0x0303:
strHoliday = "爱耳日";
break;
case 0x0305:
strHoliday = "志愿者服务日";
break;
case 0x0308:
strHoliday = "妇女节";
break;
case 0x0309:
strHoliday = "保护母亲河";
break;
case 0x030C:
strHoliday = "植树节";
break;
case 0x030F:
strHoliday = "消费者权益日";
break;
case 0x0401:
strHoliday = "愚人节";
break;
case 0x0501:
strHoliday = "劳动节";
break;
case 0x0504:
strHoliday = "青年节";
break;
case 0x0601:
strHoliday = "儿童节";
break;
case 0x0606:
strHoliday = "全国爱眼日";
break;
case 0x0701:
strHoliday = "建党节";
break;
case 0x0707:
strHoliday = "抗战纪念日";
break;
case 0x0801:
strHoliday = "建军节";
break;
case 0x090A:
strHoliday = "教师节";
break;
case 0x0910:
strHoliday = "脑健康日";
break;
case 0x0914:
strHoliday = "爱牙日";
break;
case 0x0A01:
strHoliday = "国庆节";
break;
case 0x0A0A:
strHoliday = "高血压日";
break;
case 0x0A1C:
strHoliday = "男性健康日";
break;
case 0x0B08:
strHoliday = "记者节";
break;
case 0x0B09:
strHoliday = "消防宣传日";
break;
case 0x0C04:
strHoliday = "法制宣传日";
break;
case 0x0C18:
strHoliday = "平安夜";
break;
case 0x0C19:
strHoliday = "圣诞节";
break;
default:
break;
}
return strHoliday;
}
//计算二十四节气
QString LunarCalendarInfo::getSolarTerms(int year, int month, int day)
{
QString strSolarTerms;
int dayTemp = 0;
//24节气对应表在1970年以后指定?
int index = (year - 1970) * 12 + month - 1;
if (index < 0) {
return "";
}
if (day < 15) {
dayTemp = 15 - day;
if ((chineseTwentyFourData.at(index) >> 4) == dayTemp) {
strSolarTerms = listSolarTerm.at(2 * (month - 1));
}
} else if (day > 15) {
dayTemp = day - 15;
if ((chineseTwentyFourData.at(index) & 0x0f) == dayTemp) {
strSolarTerms = listSolarTerm.at(2 * (month - 1) + 1);
}
}
return strSolarTerms;
}
//计算农历节日(必须传入农历年份月份)
QString LunarCalendarInfo::getLunarFestival(int month, int day)
{
int temp = (month << 8) | day;
QString strFestival;
switch (temp) {
case 0x0101:
strFestival = "春节";
break;
case 0x010F:
strFestival = "元宵节";
break;
case 0x0202:
strFestival = "龙抬头";
break;
case 0x0505:
strFestival = "端午节";
break;
case 0x0707:
strFestival = "七夕节";
break;
case 0x080F:
strFestival = "中秋节";
break;
case 0x0909:
strFestival = "重阳节";
break;
case 0x0C08:
strFestival = "腊八节";
break;
case 0x0C1E:
strFestival = "除夕";
break;
default:
break;
}
return strFestival;
}
//计算农历年 天干+地支+生肖
QString LunarCalendarInfo::getLunarYear(int year)
{
QString strYear;
if (year > 1924) {
int temp = year - 1924;
strYear.append(listTianGan.at(temp % 10));
strYear.append(listDiZhi.at(temp % 12));
strYear.append(listShuXiang.at(temp % 12));
}
return strYear;
}
void LunarCalendarInfo::getLunarCalendarInfo(int year, int month, int day,
QString &strHoliday,
QString &strSolarTerms,
QString &strLunarFestival,
QString &strLunarYear,
QString &strLunarMonth,
QString &strLunarDay)
{
//过滤不在范围内的年月日
if (year < 1901 || year > 2099 || month < 1 || month > 12 || day < 1 || day > 31) {
return;
}
strHoliday = getHoliday(month, day);
strSolarTerms = getSolarTerms(year, month, day);
#ifndef year_2099
//现在计算农历:获得当年春节的公历日期(比如2015年春节日期为(2月19日))
//以此为分界点,2.19前面的农历是2014年农历(用2014年农历数据来计算)
//2.19以及之后的日期农历为2015年农历(用2015年农历数据来计算)
int temp, tempYear, tempMonth, isEnd, k, n;
tempMonth = year - 1968;
int springFestivalMonth = springFestival.at(tempMonth) / 100;
int springFestivalDaty = springFestival.at(tempMonth) % 100;
if (month < springFestivalMonth) {
tempMonth--;
tempYear = 365 * 1 + day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
if ((!(year % 4)) && (month > 2)) {
tempYear = tempYear + 1;
}
if ((!((year - 1) % 4))) {
tempYear = tempYear + 1;
}
} else if (month == springFestivalMonth) {
if (day < springFestivalDaty) {
tempMonth--;
tempYear = 365 * 1 + day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
if ((!(year % 4)) && (month > 2)) {
tempYear = tempYear + 1;
}
if ((!((year - 1) % 4))) {
tempYear = tempYear + 1;
}
} else {
tempYear = day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
if ((!(year % 4)) && (month > 2)) {
tempYear = tempYear + 1;
}
}
} else {
tempYear = day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
if ((!(year % 4)) && (month > 2)) {
tempYear = tempYear + 1;
}
}
//计算农历天干地支月日
isEnd = 0;
while (isEnd != 1) {
if (lunarData.at(tempMonth) < 4095) {
k = 11;
} else {
k = 12;
}
n = k;
while (n >= 0) {
temp = lunarData.at(tempMonth);
temp = temp >> n;
temp = temp % 2;
if (tempYear <= (29 + temp)) {
isEnd = 1;
break;
}
tempYear = tempYear - 29 - temp;
n = n - 1;
}
if (isEnd) {
break;
}
tempMonth = tempMonth + 1;
}
//农历的年月日
year = 1969 + tempMonth - 1;
month = k - n + 1;
day = tempYear;
if (k == 12) {
if (month == (lunarData.at(tempMonth) / 65536) + 1) {
month = 1 - month;
} else if (month > (lunarData.at(tempMonth) / 65536) + 1) {
month = month - 1;
}
}
strLunarYear = getLunarYear(year);
if (month < 1 && (1 == day)) {
month = month * -1;
strLunarMonth = "" + listMonthName.at(month);
} else {
strLunarMonth = listMonthName.at(month);
}
strLunarDay = listDayName.at(day);
strLunarFestival = getLunarFestival(month, day);
#else
//记录春节离当年元旦的天数
int springOffset = 0;
//记录阳历日离当年元旦的天数
int newYearOffset = 0;
//记录大小月的天数 29或30
int monthCount = 0;
if (((lunarCalendarTable.at(year - 1901) & 0x0060) >> 5) == 1) {
springOffset = (lunarCalendarTable.at(year - 1901) & 0x001F) - 1;
} else {
springOffset = (lunarCalendarTable.at(year - 1901) & 0x001F) - 1 + 31;
}
//如果是不闰年且不是2月份 +1
newYearOffset = monthAdd.at(month - 1) + day - 1;
if ((!(year % 4)) && (month > 2)) {
newYearOffset++;
}
//记录从哪个月开始来计算
int index = 0;
//用来对闰月的特殊处理
int flag = 0;
//判断阳历日在春节前还是春节后,计算农历的月/日
if (newYearOffset >= springOffset) {
newYearOffset -= springOffset;
month = 1;
index = 1;
flag = 0;
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
monthCount = 29;
} else {
monthCount = 30;
}
while (newYearOffset >= monthCount) {
newYearOffset -= monthCount;
index++;
if (month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) {
flag = ~flag;
if (flag == 0) {
month++;
}
} else {
month++;
}
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
monthCount = 29;
} else {
monthCount = 30;
}
}
day = newYearOffset + 1;
} else {
springOffset -= newYearOffset;
year--;
month = 12;
flag = 0;
if (((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20) == 0) {
index = 12;
} else {
index = 13;
}
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
monthCount = 29;
} else {
monthCount = 30;
}
while (springOffset > monthCount) {
springOffset -= monthCount;
index--;
if (flag == 0) {
month--;
}
if (month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) {
flag = ~flag;
}
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
monthCount = 29;
} else {
monthCount = 30;
}
}
day = monthCount - springOffset + 1;
}
//计算农历的索引配置
int temp = 0;
temp |= day;
temp |= (month << 6);
//转换农历的年月
month = (temp & 0x3C0) >> 6;
day = temp & 0x3F;
strLunarYear = getLunarYear(year);
if ((month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) && (1 == day)) {
strLunarMonth = "" + listMonthName.at(month);
} else {
strLunarMonth = listMonthName.at(month);
}
strLunarDay = listDayName.at(day);
strLunarFestival = getLunarFestival(month, day);
#endif
}
QString LunarCalendarInfo::getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo)
{
QString strHoliday, strSolarTerms, strLunarFestival, strLunarYear, strLunarMonth, strLunarDay;
LunarCalendarInfo::Instance()->getLunarCalendarInfo(year, month, day,
strHoliday, strSolarTerms, strLunarFestival,
strLunarYear, strLunarMonth, strLunarDay);
//农历节日优先,其次农历节气,然后公历节日,最后才是农历月份名称
if (!strLunarFestival.isEmpty()) {
strLunarDay = strLunarFestival;
} else if (!strSolarTerms.isEmpty()) {
strLunarDay = strSolarTerms;
} else if (!strHoliday.isEmpty()) {
strLunarDay = strHoliday;
}
QString info = QString("%1%2%3")
.arg(yearInfo ? strLunarYear + "" : "")
.arg(monthInfo ? strLunarMonth : "")
.arg(dayInfo ? strLunarDay : "");
return info;
}
QString LunarCalendarInfo::getLunarYearMonthDay(int year, int month, int day)
{
return getLunarInfo(year, month, day, true, true, true);
}
QString LunarCalendarInfo::getLunarMonthDay(int year, int month, int day)
{
return getLunarInfo(year, month, day, false, true, true);
}
QString LunarCalendarInfo::getLunarDay(int year, int month, int day)
{
return getLunarInfo(year, month, day, false, false, true);
}

View File

@@ -0,0 +1,84 @@
#ifndef LUNARCALENDARINFO_H
#define LUNARCALENDARINFO_H
/**
* 农历信息类 作者:倪大侠 整理:feiyangqingyun(QQ:517216493) 2016-12-10
* 1. 计算是否闰年。
* 2. 计算国际节日。
* 3. 计算二十四节气。
* 4. 计算农历年 天干、地支、生肖。
* 5. 计算指定年月日农历信息,包括公历节日和农历节日及二十四节气。
*/
#include <QObject>
#ifdef quc
class Q_DECL_EXPORT LunarCalendarInfo : public QObject
#else
class LunarCalendarInfo : public QObject
#endif
{
Q_OBJECT
public:
static LunarCalendarInfo *Instance();
explicit LunarCalendarInfo(QObject *parent = 0);
//计算是否闰年
bool isLoopYear(int year);
//计算指定年月该月共多少天
int getMonthDays(int year, int month);
//计算指定年月对应到该月共多少天
int getTotalMonthDays(int year, int month);
//计算指定年月对应星期几
int getFirstDayOfWeek(int year, int month);
//计算国际节日
QString getHoliday(int month, int day);
//计算二十四节气
QString getSolarTerms(int year, int month, int day);
//计算农历节日(必须传入农历年份月份)
QString getLunarFestival(int month, int day);
//计算农历年 天干+地支+生肖
QString getLunarYear(int year);
//计算指定年月日农历信息,包括公历节日和农历节日及二十四节气
void getLunarCalendarInfo(int year, int month, int day,
QString &strHoliday,
QString &strSolarTerms,
QString &strLunarFestival,
QString &strLunarYear,
QString &strLunarMonth,
QString &strLunarDay);
//获取指定年月日农历信息
QString getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo);
QString getLunarYearMonthDay(int year, int month, int day);
QString getLunarMonthDay(int year, int month, int day);
QString getLunarDay(int year, int month, int day);
private:
static QScopedPointer<LunarCalendarInfo> self;
QList<int> lunarCalendarTable; //农历年表
QList<int> springFestival; //春节公历日期
QList<int> lunarData; //农历每月数据
QList<int> chineseTwentyFourData; //农历二十四节气数据
QList<int> monthAdd; //公历每月前面的天数
QList<QString> listDayName; //农历日期名称集合
QList<QString> listMonthName; //农历月份名称集合
QList<QString> listSolarTerm; //二十四节气名称集合
QList<QString> listTianGan; //天干名称集合
QList<QString> listDiZhi; //地支名称集合
QList<QString> listShuXiang; //属相名称集合
};
#endif // LUNARCALENDARINFO_H

View File

@@ -0,0 +1,550 @@
#pragma execution_character_set("utf-8")
#include "lunarcalendaritem.h"
#include "qpainter.h"
#include "qevent.h"
#include "qdatetime.h"
#include "qdebug.h"
LunarCalendarItem::LunarCalendarItem(QWidget *parent) : QWidget(parent)
{
hover = false;
pressed = false;
listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十"
<< "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十"
<< "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十";
select = false;
showLunar = true;
bgImage = ":/image/bg_calendar.png";
selectType = SelectType_Rect;
date = QDate::currentDate();
lunar = "初一";
dayType = DayType_MonthCurrent;
borderColor = QColor(180, 180, 180);
weekColor = QColor(255, 0, 0);
superColor = QColor(255, 129, 6);
lunarColor = QColor(55, 156, 238);
currentTextColor = QColor(0, 0, 0);
otherTextColor = QColor(200, 200, 200);
selectTextColor = QColor(255, 255, 255);
hoverTextColor = QColor(250, 250, 250);
currentLunarColor = QColor(150, 150, 150);
otherLunarColor = QColor(200, 200, 200);
selectLunarColor = QColor(255, 255, 255);
hoverLunarColor = QColor(250, 250, 250);
currentBgColor = QColor(255, 255, 255);
otherBgColor = QColor(240, 240, 240);
selectBgColor = QColor(208, 47, 18);
hoverBgColor = QColor(204, 183, 180);
}
void LunarCalendarItem::enterEvent(QEvent *)
{
hover = true;
this->update();
}
void LunarCalendarItem::leaveEvent(QEvent *)
{
hover = false;
this->update();
}
void LunarCalendarItem::mousePressEvent(QMouseEvent *)
{
pressed = true;
this->update();
emit clicked(date, dayType);
}
void LunarCalendarItem::mouseReleaseEvent(QMouseEvent *)
{
pressed = false;
this->update();
}
void LunarCalendarItem::paintEvent(QPaintEvent *)
{
//绘制准备工作,启用反锯齿
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
//绘制背景和边框
drawBg(&painter);
//优先绘制选中状态,其次绘制悬停状态
if (select) {
drawBgCurrent(&painter, selectBgColor);
} else if (hover) {
drawBgCurrent(&painter, hoverBgColor);
}
//绘制日期
drawDay(&painter);
//绘制农历信息
drawLunar(&painter);
}
void LunarCalendarItem::drawBg(QPainter *painter)
{
painter->save();
//根据当前类型选择对应的颜色
QColor bgColor = currentBgColor;
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
bgColor = otherBgColor;
}
painter->setPen(borderColor);
painter->setBrush(bgColor);
painter->drawRect(rect());
painter->restore();
}
void LunarCalendarItem::drawBgCurrent(QPainter *painter, const QColor &color)
{
int width = this->width();
int height = this->height();
int side = qMin(width, height);
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(color);
//根据设定绘制背景样式
if (selectType == SelectType_Rect) {
painter->drawRect(rect());
} else if (selectType == SelectType_Circle) {
int radius = side / 2 - 3;
painter->drawEllipse(QPointF(width / 2, height / 2), radius, radius);
} else if (selectType == SelectType_Triangle) {
int radius = side / 3;
QPolygon pts;
pts.setPoints(3, 1, 1, radius, 1, 1, radius);
painter->drawRect(rect());
painter->setBrush(superColor);
painter->drawConvexPolygon(pts);
} else if (selectType == SelectType_Image) {
//等比例缩放居中绘制
QImage img(bgImage);
if (!img.isNull()) {
img = img.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
int x = (width - img.width()) / 2;
int y = (height - img.height()) / 2;
painter->drawImage(x, y, img);
}
}
painter->restore();
}
void LunarCalendarItem::drawDay(QPainter *painter)
{
int width = this->width();
int height = this->height();
int side = qMin(width, height);
painter->save();
//根据当前类型选择对应的颜色
QColor color = currentTextColor;
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
color = otherTextColor;
} else if (dayType == DayType_WeekEnd) {
color = weekColor;
}
if (select) {
color = selectTextColor;
} else if (hover) {
color = hoverTextColor;
}
painter->setPen(color);
if (showLunar) {
QFont font;
font.setPixelSize(side / 2.7);
painter->setFont(font);
QRect dayRect = QRect(0, 0, width, height / 1.7);
painter->drawText(dayRect, Qt::AlignHCenter | Qt::AlignBottom, QString::number(date.day()));
} else {
QFont font;
font.setPixelSize(side / 2);
painter->setFont(font);
QRect dayRect = QRect(0, 0, width, height);
painter->drawText(dayRect, Qt::AlignCenter, QString::number(date.day()));
}
painter->restore();
}
void LunarCalendarItem::drawLunar(QPainter *painter)
{
if (!showLunar) {
return;
}
int width = this->width();
int height = this->height();
int side = qMin(width, height);
painter->save();
//判断当前农历文字是否节日,是节日且是当月则用农历节日颜色显示
bool exist = (!listDayName.contains(lunar) && dayType != DayType_MonthPre && dayType != DayType_MonthNext);
//根据当前类型选择对应的颜色
QColor color = currentLunarColor;
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
color = otherLunarColor;
}
if (select) {
color = selectTextColor;
} else if (hover) {
color = hoverTextColor;
} else if (exist) {
color = lunarColor;
}
painter->setPen(color);
QFont font;
font.setPixelSize(side / 5);
painter->setFont(font);
QRect lunarRect(0, height / 2, width, height / 2);
painter->drawText(lunarRect, Qt::AlignCenter, lunar);
painter->restore();
}
bool LunarCalendarItem::getSelect() const
{
return this->select;
}
bool LunarCalendarItem::getShowLunar() const
{
return this->showLunar;
}
QString LunarCalendarItem::getBgImage() const
{
return this->bgImage;
}
LunarCalendarItem::SelectType LunarCalendarItem::getSelectType() const
{
return this->selectType;
}
QDate LunarCalendarItem::getDate() const
{
return this->date;
}
QString LunarCalendarItem::getLunar() const
{
return this->lunar;
}
LunarCalendarItem::DayType LunarCalendarItem::getDayType() const
{
return this->dayType;
}
QColor LunarCalendarItem::getBorderColor() const
{
return this->borderColor;
}
QColor LunarCalendarItem::getWeekColor() const
{
return this->weekColor;
}
QColor LunarCalendarItem::getSuperColor() const
{
return this->superColor;
}
QColor LunarCalendarItem::getLunarColor() const
{
return this->lunarColor;
}
QColor LunarCalendarItem::getCurrentTextColor() const
{
return this->currentTextColor;
}
QColor LunarCalendarItem::getOtherTextColor() const
{
return this->otherTextColor;
}
QColor LunarCalendarItem::getSelectTextColor() const
{
return this->selectTextColor;
}
QColor LunarCalendarItem::getHoverTextColor() const
{
return this->hoverTextColor;
}
QColor LunarCalendarItem::getCurrentLunarColor() const
{
return this->currentLunarColor;
}
QColor LunarCalendarItem::getOtherLunarColor() const
{
return this->otherLunarColor;
}
QColor LunarCalendarItem::getSelectLunarColor() const
{
return this->selectLunarColor;
}
QColor LunarCalendarItem::getHoverLunarColor() const
{
return this->hoverLunarColor;
}
QColor LunarCalendarItem::getCurrentBgColor() const
{
return this->currentBgColor;
}
QColor LunarCalendarItem::getOtherBgColor() const
{
return this->otherBgColor;
}
QColor LunarCalendarItem::getSelectBgColor() const
{
return this->selectBgColor;
}
QColor LunarCalendarItem::getHoverBgColor() const
{
return this->hoverBgColor;
}
QSize LunarCalendarItem::sizeHint() const
{
return QSize(100, 100);
}
QSize LunarCalendarItem::minimumSizeHint() const
{
return QSize(20, 20);
}
void LunarCalendarItem::setSelect(bool select)
{
if (this->select != select) {
this->select = select;
this->update();
}
}
void LunarCalendarItem::setShowLunar(bool showLunar)
{
if (this->showLunar != showLunar) {
this->showLunar = showLunar;
this->update();
}
}
void LunarCalendarItem::setBgImage(const QString &bgImage)
{
if (this->bgImage != bgImage) {
this->bgImage = bgImage;
this->update();
}
}
void LunarCalendarItem::setSelectType(const LunarCalendarItem::SelectType &selectType)
{
if (this->selectType != selectType) {
this->selectType = selectType;
this->update();
}
}
void LunarCalendarItem::setDate(const QDate &date)
{
if (this->date != date) {
this->date = date;
this->update();
}
}
void LunarCalendarItem::setLunar(const QString &lunar)
{
if (this->lunar != lunar) {
this->lunar = lunar;
this->update();
}
}
void LunarCalendarItem::setDayType(const LunarCalendarItem::DayType &dayType)
{
if (this->dayType != dayType) {
this->dayType = dayType;
this->update();
}
}
void LunarCalendarItem::setDate(const QDate &date, const QString &lunar, const DayType &dayType)
{
this->date = date;
this->lunar = lunar;
this->dayType = dayType;
this->update();
}
void LunarCalendarItem::setBorderColor(const QColor &borderColor)
{
if (this->borderColor != borderColor) {
this->borderColor = borderColor;
this->update();
}
}
void LunarCalendarItem::setWeekColor(const QColor &weekColor)
{
if (this->weekColor != weekColor) {
this->weekColor = weekColor;
this->update();
}
}
void LunarCalendarItem::setSuperColor(const QColor &superColor)
{
if (this->superColor != superColor) {
this->superColor = superColor;
this->update();
}
}
void LunarCalendarItem::setLunarColor(const QColor &lunarColor)
{
if (this->lunarColor != lunarColor) {
this->lunarColor = lunarColor;
this->update();
}
}
void LunarCalendarItem::setCurrentTextColor(const QColor &currentTextColor)
{
if (this->currentTextColor != currentTextColor) {
this->currentTextColor = currentTextColor;
this->update();
}
}
void LunarCalendarItem::setOtherTextColor(const QColor &otherTextColor)
{
if (this->otherTextColor != otherTextColor) {
this->otherTextColor = otherTextColor;
this->update();
}
}
void LunarCalendarItem::setSelectTextColor(const QColor &selectTextColor)
{
if (this->selectTextColor != selectTextColor) {
this->selectTextColor = selectTextColor;
this->update();
}
}
void LunarCalendarItem::setHoverTextColor(const QColor &hoverTextColor)
{
if (this->hoverTextColor != hoverTextColor) {
this->hoverTextColor = hoverTextColor;
this->update();
}
}
void LunarCalendarItem::setCurrentLunarColor(const QColor &currentLunarColor)
{
if (this->currentLunarColor != currentLunarColor) {
this->currentLunarColor = currentLunarColor;
this->update();
}
}
void LunarCalendarItem::setOtherLunarColor(const QColor &otherLunarColor)
{
if (this->otherLunarColor != otherLunarColor) {
this->otherLunarColor = otherLunarColor;
this->update();
}
}
void LunarCalendarItem::setSelectLunarColor(const QColor &selectLunarColor)
{
if (this->selectLunarColor != selectLunarColor) {
this->selectLunarColor = selectLunarColor;
this->update();
}
}
void LunarCalendarItem::setHoverLunarColor(const QColor &hoverLunarColor)
{
if (this->hoverLunarColor != hoverLunarColor) {
this->hoverLunarColor = hoverLunarColor;
this->update();
}
}
void LunarCalendarItem::setCurrentBgColor(const QColor &currentBgColor)
{
if (this->currentBgColor != currentBgColor) {
this->currentBgColor = currentBgColor;
this->update();
}
}
void LunarCalendarItem::setOtherBgColor(const QColor &otherBgColor)
{
if (this->otherBgColor != otherBgColor) {
this->otherBgColor = otherBgColor;
this->update();
}
}
void LunarCalendarItem::setSelectBgColor(const QColor &selectBgColor)
{
if (this->selectBgColor != selectBgColor) {
this->selectBgColor = selectBgColor;
this->update();
}
}
void LunarCalendarItem::setHoverBgColor(const QColor &hoverBgColor)
{
if (this->hoverBgColor != hoverBgColor) {
this->hoverBgColor = hoverBgColor;
this->update();
}
}

View File

@@ -0,0 +1,201 @@
#ifndef LUNARCALENDARITEM_H
#define LUNARCALENDARITEM_H
#include <QWidget>
#include <QDate>
#ifdef quc
class Q_DECL_EXPORT LunarCalendarItem : public QWidget
#else
class LunarCalendarItem : public QWidget
#endif
{
Q_OBJECT
Q_ENUMS(DayType)
Q_ENUMS(SelectType)
Q_PROPERTY(bool select READ getSelect WRITE setSelect)
Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar)
Q_PROPERTY(QString bgImage READ getBgImage WRITE setBgImage)
Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType)
Q_PROPERTY(QDate date READ getDate WRITE setDate)
Q_PROPERTY(QString lunar READ getLunar WRITE setLunar)
Q_PROPERTY(DayType dayType READ getDayType WRITE setDayType)
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor)
Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor)
Q_PROPERTY(QColor superColor READ getSuperColor WRITE setSuperColor)
Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor)
Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor)
Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor)
Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor)
Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor)
Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor)
Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor)
Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor)
Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor)
Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor)
Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor)
Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor)
Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor)
public:
enum DayType {
DayType_MonthPre = 0, //上月剩余天数
DayType_MonthNext = 1, //下个月的天数
DayType_MonthCurrent = 2, //当月天数
DayType_WeekEnd = 3 //周末
};
enum SelectType {
SelectType_Rect = 0, //矩形背景
SelectType_Circle = 1, //圆形背景
SelectType_Triangle = 2, //带三角标
SelectType_Image = 3 //图片背景
};
explicit LunarCalendarItem(QWidget *parent = 0);
protected:
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void paintEvent(QPaintEvent *);
void drawBg(QPainter *painter);
void drawBgCurrent(QPainter *painter, const QColor &color);
void drawDay(QPainter *painter);
void drawLunar(QPainter *painter);
private:
bool hover; //鼠标是否悬停
bool pressed; //鼠标是否按下
QStringList listDayName; //农历日期
bool select; //是否选中
bool showLunar; //显示农历
QString bgImage; //背景图片
SelectType selectType; //选中模式
QDate date; //当前日期
QString lunar; //农历信息
DayType dayType; //当前日类型
QColor borderColor; //边框颜色
QColor weekColor; //周末颜色
QColor superColor; //角标颜色
QColor lunarColor; //农历节日颜色
QColor currentTextColor; //当前月文字颜色
QColor otherTextColor; //其他月文字颜色
QColor selectTextColor; //选中日期文字颜色
QColor hoverTextColor; //悬停日期文字颜色
QColor currentLunarColor; //当前月农历文字颜色
QColor otherLunarColor; //其他月农历文字颜色
QColor selectLunarColor; //选中日期农历文字颜色
QColor hoverLunarColor; //悬停日期农历文字颜色
QColor currentBgColor; //当前月背景颜色
QColor otherBgColor; //其他月背景颜色
QColor selectBgColor; //选中日期背景颜色
QColor hoverBgColor; //悬停日期背景颜色
public:
bool getSelect() const;
bool getShowLunar() const;
QString getBgImage() const;
SelectType getSelectType() const;
QDate getDate() const;
QString getLunar() const;
DayType getDayType() const;
QColor getBorderColor() const;
QColor getWeekColor() const;
QColor getSuperColor() const;
QColor getLunarColor() const;
QColor getCurrentTextColor() const;
QColor getOtherTextColor() const;
QColor getSelectTextColor() const;
QColor getHoverTextColor() const;
QColor getCurrentLunarColor() const;
QColor getOtherLunarColor() const;
QColor getSelectLunarColor() const;
QColor getHoverLunarColor() const;
QColor getCurrentBgColor() const;
QColor getOtherBgColor() const;
QColor getSelectBgColor() const;
QColor getHoverBgColor() const;
QSize sizeHint() const;
QSize minimumSizeHint() const;
public Q_SLOTS:
//设置是否选中
void setSelect(bool select);
//设置是否显示农历信息
void setShowLunar(bool showLunar);
//设置背景图片
void setBgImage(const QString &bgImage);
//设置选中背景样式
void setSelectType(const SelectType &selectType);
//设置日期
void setDate(const QDate &date);
//设置农历
void setLunar(const QString &lunar);
//设置类型
void setDayType(const DayType &dayType);
//设置日期/农历/类型
void setDate(const QDate &date, const QString &lunar, const DayType &dayType);
//设置边框颜色
void setBorderColor(const QColor &borderColor);
//设置周末颜色
void setWeekColor(const QColor &weekColor);
//设置角标颜色
void setSuperColor(const QColor &superColor);
//设置农历节日颜色
void setLunarColor(const QColor &lunarColor);
//设置当前月文字颜色
void setCurrentTextColor(const QColor &currentTextColor);
//设置其他月文字颜色
void setOtherTextColor(const QColor &otherTextColor);
//设置选中日期文字颜色
void setSelectTextColor(const QColor &selectTextColor);
//设置悬停日期文字颜色
void setHoverTextColor(const QColor &hoverTextColor);
//设置当前月农历文字颜色
void setCurrentLunarColor(const QColor &currentLunarColor);
//设置其他月农历文字颜色
void setOtherLunarColor(const QColor &otherLunarColor);
//设置选中日期农历文字颜色
void setSelectLunarColor(const QColor &selectLunarColor);
//设置悬停日期农历文字颜色
void setHoverLunarColor(const QColor &hoverLunarColor);
//设置当前月背景颜色
void setCurrentBgColor(const QColor &currentBgColor);
//设置其他月背景颜色
void setOtherBgColor(const QColor &otherBgColor);
//设置选中日期背景颜色
void setSelectBgColor(const QColor &selectBgColor);
//设置悬停日期背景颜色
void setHoverBgColor(const QColor &hoverBgColor);
Q_SIGNALS:
void clicked(const QDate &date, const LunarCalendarItem::DayType &dayType);
};
#endif // LUNARCALENDARITEM_H

View File

@@ -0,0 +1,835 @@
#pragma execution_character_set("utf-8")
#include "lunarcalendarwidget.h"
#include "qfontdatabase.h"
#include "qdatetime.h"
#include "qlayout.h"
#include "qlabel.h"
#include "qpushbutton.h"
#include "qtoolbutton.h"
#include "qcombobox.h"
#include "qdebug.h"
LunarCalendarWidget::LunarCalendarWidget(QWidget *parent) : QWidget(parent)
{
//判断图形字体是否存在,不存在则加入
QFontDatabase fontDb;
if (!fontDb.families().contains("FontAwesome")) {
int fontId = fontDb.addApplicationFont(":/font/fontawesome-webfont.ttf");
QStringList fontName = fontDb.applicationFontFamilies(fontId);
if (fontName.count() == 0) {
qDebug() << "load fontawesome-webfont.ttf error";
}
}
if (fontDb.families().contains("FontAwesome")) {
iconFont = QFont("FontAwesome");
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))
iconFont.setHintingPreference(QFont::PreferNoHinting);
#endif
}
btnClick = false;
calendarStyle = CalendarStyle_Red;
weekNameFormat = WeekNameFormat_Short;
date = QDate::currentDate();
weekTextColor = QColor(255, 255, 255);
weekBgColor = QColor(22, 160, 134);
showLunar = true;
bgImage = ":/image/bg_calendar.png";
selectType = SelectType_Rect;
borderColor = QColor(180, 180, 180);
weekColor = QColor(255, 0, 0);
superColor = QColor(255, 129, 6);
lunarColor = QColor(55, 156, 238);
currentTextColor = QColor(0, 0, 0);
otherTextColor = QColor(200, 200, 200);
selectTextColor = QColor(255, 255, 255);
hoverTextColor = QColor(250, 250, 250);
currentLunarColor = QColor(150, 150, 150);
otherLunarColor = QColor(200, 200, 200);
selectLunarColor = QColor(255, 255, 255);
hoverLunarColor = QColor(250, 250, 250);
currentBgColor = QColor(255, 255, 255);
otherBgColor = QColor(240, 240, 240);
selectBgColor = QColor(208, 47, 18);
hoverBgColor = QColor(204, 183, 180);
initWidget();
initStyle();
initDate();
}
LunarCalendarWidget::~LunarCalendarWidget()
{
}
void LunarCalendarWidget::initWidget()
{
setObjectName("lunarCalendarWidget");
//顶部widget
QWidget *widgetTop = new QWidget;
widgetTop->setObjectName("widgetTop");
widgetTop->setMinimumHeight(35);
//上一年按钮
QToolButton *btnPrevYear = new QToolButton;
btnPrevYear->setObjectName("btnPrevYear");
btnPrevYear->setFixedWidth(35);
btnPrevYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
btnPrevYear->setFont(iconFont);
btnPrevYear->setText(QChar(0xf060));
//下一年按钮
QToolButton *btnNextYear = new QToolButton;
btnNextYear->setObjectName("btnNextYear");
btnNextYear->setFixedWidth(35);
btnNextYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
btnNextYear->setFont(iconFont);
btnNextYear->setText(QChar(0xf061));
//上个月按钮
QToolButton *btnPrevMonth = new QToolButton;
btnPrevMonth->setObjectName("btnPrevMonth");
btnPrevMonth->setFixedWidth(35);
btnPrevMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btnPrevMonth->setFont(iconFont);
btnPrevMonth->setText(QChar(0xf060));
//下个月按钮
QToolButton *btnNextMonth = new QToolButton;
btnNextMonth->setObjectName("btnNextMonth");
btnNextMonth->setFixedWidth(35);
btnNextMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btnNextMonth->setFont(iconFont);
btnNextMonth->setText(QChar(0xf061));
//转到今天
QPushButton *btnToday = new QPushButton;
btnToday->setObjectName("btnToday");
btnToday->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btnToday->setText("转到今天");
//年份下拉框
cboxYear = new QComboBox;
cboxYear->setObjectName("cboxYear");
for (int i = 1901; i <= 2099; i++) {
cboxYear->addItem(QString("%1年").arg(i));
}
//月份下拉框
cboxMonth = new QComboBox;
cboxMonth->setObjectName("cboxMonth");
for (int i = 1; i <= 12; i++) {
cboxMonth->addItem(QString("%1月").arg(i));
}
//中间用个空widget隔开
QWidget *widgetBlank1 = new QWidget;
widgetBlank1->setFixedWidth(5);
QWidget *widgetBlank2 = new QWidget;
widgetBlank2->setFixedWidth(5);
//顶部横向布局
QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop);
layoutTop->setContentsMargins(0, 0, 0, 9);
layoutTop->addWidget(btnPrevYear);
layoutTop->addWidget(cboxYear);
layoutTop->addWidget(btnNextYear);
layoutTop->addWidget(widgetBlank1);
layoutTop->addWidget(btnPrevMonth);
layoutTop->addWidget(cboxMonth);
layoutTop->addWidget(btnNextMonth);
layoutTop->addWidget(widgetBlank2);
layoutTop->addWidget(btnToday);
//星期widget
QWidget *widgetWeek = new QWidget;
widgetWeek->setObjectName("widgetWeek");
widgetWeek->setMinimumHeight(30);
//星期布局
QHBoxLayout *layoutWeek = new QHBoxLayout(widgetWeek);
layoutWeek->setContentsMargins(0, 0, 0, 0);
layoutWeek->setSpacing(0);
for (int i = 0; i < 7; i++) {
QLabel *lab = new QLabel;
lab->setAlignment(Qt::AlignCenter);
layoutWeek->addWidget(lab);
labWeeks.append(lab);
}
setWeekNameFormat(WeekNameFormat_Long);
//日期标签widget
QWidget *widgetBody = new QWidget;
widgetBody->setObjectName("widgetBody");
//日期标签布局
QGridLayout *layoutBody = new QGridLayout(widgetBody);
layoutBody->setContentsMargins(1, 1, 1, 1);
layoutBody->setHorizontalSpacing(0);
layoutBody->setVerticalSpacing(0);
//逐个添加日标签
for (int i = 0; i < 42; i++) {
LunarCalendarItem *lab = new LunarCalendarItem;
connect(lab, SIGNAL(clicked(QDate, LunarCalendarItem::DayType)), this, SLOT(clicked(QDate, LunarCalendarItem::DayType)));
layoutBody->addWidget(lab, i / 7, i % 7);
dayItems.append(lab);
}
//主布局
QVBoxLayout *verLayoutCalendar = new QVBoxLayout(this);
verLayoutCalendar->setContentsMargins(0, 0, 0, 0);
verLayoutCalendar->setSpacing(0);
verLayoutCalendar->addWidget(widgetTop);
verLayoutCalendar->addWidget(widgetWeek);
verLayoutCalendar->addWidget(widgetBody, 1);
//绑定按钮和下拉框信号
connect(btnPrevYear, SIGNAL(clicked(bool)), this, SLOT(showPreviousYear()));
connect(btnNextYear, SIGNAL(clicked(bool)), this, SLOT(showNextYear()));
connect(btnPrevMonth, SIGNAL(clicked(bool)), this, SLOT(showPreviousMonth()));
connect(btnNextMonth, SIGNAL(clicked(bool)), this, SLOT(showNextMonth()));
connect(btnToday, SIGNAL(clicked(bool)), this, SLOT(showToday()));
connect(cboxYear, SIGNAL(currentIndexChanged(int)), this, SLOT(yearChanged(int)));
connect(cboxMonth, SIGNAL(currentIndexChanged(int)), this, SLOT(monthChanged(int)));
}
void LunarCalendarWidget::initStyle()
{
//设置样式
QStringList qss;
//星期名称样式
qss.append(QString("QLabel{background:%1;color:%2;}").arg(weekBgColor.name()).arg(weekTextColor.name()));
//边框
qss.append(QString("QWidget#widgetBody{border:1px solid %1;}").arg(borderColor.name()));
//顶部下拉框
qss.append(QString("QToolButton{padding:0px;background:none;border:none;border-radius:5px;}"));
qss.append(QString("QToolButton:hover{background:#16A085;color:#FFFFFF;}"));
//转到今天
qss.append(QString("QPushButton{background:#16A085;color:#FFFFFF;border-radius:5px;}"));
//自定义日控件颜色
QString strSelectType;
if (selectType == SelectType_Rect) {
strSelectType = "SelectType_Rect";
} else if (selectType == SelectType_Circle) {
strSelectType = "SelectType_Circle";
} else if (selectType == SelectType_Triangle) {
strSelectType = "SelectType_Triangle";
} else if (selectType == SelectType_Image) {
strSelectType = "SelectType_Image";
}
qss.append(QString("LunarCalendarItem{qproperty-showLunar:%1;}").arg(showLunar));
qss.append(QString("LunarCalendarItem{qproperty-bgImage:%1;}").arg(bgImage));
qss.append(QString("LunarCalendarItem{qproperty-selectType:%1;}").arg(strSelectType));
qss.append(QString("LunarCalendarItem{qproperty-borderColor:%1;}").arg(borderColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-weekColor:%1;}").arg(weekColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-superColor:%1;}").arg(superColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-lunarColor:%1;}").arg(lunarColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-currentTextColor:%1;}").arg(currentTextColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-otherTextColor:%1;}").arg(otherTextColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-selectTextColor:%1;}").arg(selectTextColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-hoverTextColor:%1;}").arg(hoverTextColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-currentLunarColor:%1;}").arg(currentLunarColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-otherLunarColor:%1;}").arg(otherLunarColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-selectLunarColor:%1;}").arg(selectLunarColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-hoverLunarColor:%1;}").arg(hoverLunarColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-currentBgColor:%1;}").arg(currentBgColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-otherBgColor:%1;}").arg(otherBgColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-selectBgColor:%1;}").arg(selectBgColor.name()));
qss.append(QString("LunarCalendarItem{qproperty-hoverBgColor:%1;}").arg(hoverBgColor.name()));
this->setStyleSheet(qss.join(""));
}
//初始化日期面板
void LunarCalendarWidget::initDate()
{
int year = date.year();
int month = date.month();
int day = date.day();
//设置为今天,设置变量防止重复触发
btnClick = true;
cboxYear->setCurrentIndex(cboxYear->findText(QString("%1年").arg(year)));
cboxMonth->setCurrentIndex(cboxMonth->findText(QString("%1月").arg(month)));
btnClick = false;
//首先判断当前月的第一天是星期几
int week = LunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month);
//当前月天数
int countDay = LunarCalendarInfo::Instance()->getMonthDays(year, month);
//上月天数
int countDayPre = LunarCalendarInfo::Instance()->getMonthDays(1 == month ? year - 1 : year, 1 == month ? 12 : month - 1);
//如果上月天数上月刚好一周则另外处理
int startPre, endPre, startNext, endNext, index, tempYear, tempMonth, tempDay;
if (0 == week) {
startPre = 0;
endPre = 7;
startNext = 0;
endNext = 42 - (countDay + 7);
} else {
startPre = 0;
endPre = week;
startNext = week + countDay;
endNext = 42;
}
//纠正1月份前面部分偏差,1月份前面部分是上一年12月份
tempYear = year;
tempMonth = month - 1;
if (tempMonth < 1) {
tempYear--;
tempMonth = 12;
}
//显示上月天数
for (int i = startPre; i < endPre; i++) {
index = i;
tempDay = countDayPre - endPre + i + 1;
QDate date(tempYear, tempMonth, tempDay);
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthPre);
}
//纠正12月份后面部分偏差,12月份后面部分是下一年1月份
tempYear = year;
tempMonth = month + 1;
if (tempMonth > 12) {
tempYear++;
tempMonth = 1;
}
//显示下月天数
for (int i = startNext; i < endNext; i++) {
index = 42 - endNext + i;
tempDay = i - startNext + 1;
QDate date(tempYear, tempMonth, tempDay);
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthNext);
}
//重新置为当前年月
tempYear = year;
tempMonth = month;
//显示当前月
for (int i = week; i < (countDay + week); i++) {
index = (0 == week ? (i + 7) : i);
tempDay = i - week + 1;
QDate date(tempYear, tempMonth, tempDay);
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
if (0 == (i % 7) || 6 == (i % 7)) {
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_WeekEnd);
} else {
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthCurrent);
}
}
dayChanged(this->date);
}
void LunarCalendarWidget::yearChanged(int)
{
//如果是单击按钮切换的日期变动则不需要触发
if (btnClick) {
return;
}
QString arg1 = cboxYear->currentText();
int year = arg1.mid(0, arg1.length() - 1).toInt();
int month = date.month();
int day = date.day();
dateChanged(year, month, day);
}
void LunarCalendarWidget::monthChanged(int)
{
//如果是单击按钮切换的日期变动则不需要触发
if (btnClick) {
return;
}
QString arg1 = cboxMonth->currentText();
int year = date.year();
int month = arg1.mid(0, arg1.length() - 1).toInt();
int day = date.day();
dateChanged(year, month, day);
}
void LunarCalendarWidget::clicked(const QDate &date, const LunarCalendarItem::DayType &dayType)
{
if (LunarCalendarItem::DayType_MonthPre == dayType) {
showPreviousMonth();
} else if (LunarCalendarItem::DayType_MonthNext == dayType) {
showNextMonth();
} else {
this->date = date;
dayChanged(this->date);
}
}
void LunarCalendarWidget::dayChanged(const QDate &date)
{
//计算星期几,当前天对应标签索引=日期+星期几-1
int year = date.year();
int month = date.month();
int day = date.day();
int week = LunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month);
//qDebug() << QString("%1-%2-%3").arg(year).arg(month).arg(day);
//选中当前日期,其他日期恢复,这里还有优化空间,比方说类似单选框机制
for (int i = 0; i < 42; i++) {
//当月第一天是星期天要另外计算
int index = day + week - 1;
if (week == 0) {
index = day + 6;
}
dayItems.at(i)->setSelect(i == index);
}
//发送日期单击信号
emit clicked(date);
//发送日期更新信号
emit selectionChanged();
}
void LunarCalendarWidget::dateChanged(int year, int month, int day)
{
//如果原有天大于28则设置为1,防止出错
date.setDate(year, month, day > 28 ? 1 : day);
initDate();
}
LunarCalendarWidget::CalendarStyle LunarCalendarWidget::getCalendarStyle() const
{
return this->calendarStyle;
}
LunarCalendarWidget::WeekNameFormat LunarCalendarWidget::getWeekNameFormat() const
{
return this->weekNameFormat;
}
QDate LunarCalendarWidget::getDate() const
{
return this->date;
}
QColor LunarCalendarWidget::getWeekTextColor() const
{
return this->weekTextColor;
}
QColor LunarCalendarWidget::getWeekBgColor() const
{
return this->weekBgColor;
}
bool LunarCalendarWidget::getShowLunar() const
{
return this->showLunar;
}
QString LunarCalendarWidget::getBgImage() const
{
return this->bgImage;
}
LunarCalendarWidget::SelectType LunarCalendarWidget::getSelectType() const
{
return this->selectType;
}
QColor LunarCalendarWidget::getBorderColor() const
{
return this->borderColor;
}
QColor LunarCalendarWidget::getWeekColor() const
{
return this->weekColor;
}
QColor LunarCalendarWidget::getSuperColor() const
{
return this->superColor;
}
QColor LunarCalendarWidget::getLunarColor() const
{
return this->lunarColor;
}
QColor LunarCalendarWidget::getCurrentTextColor() const
{
return this->currentTextColor;
}
QColor LunarCalendarWidget::getOtherTextColor() const
{
return this->otherTextColor;
}
QColor LunarCalendarWidget::getSelectTextColor() const
{
return this->selectTextColor;
}
QColor LunarCalendarWidget::getHoverTextColor() const
{
return this->hoverTextColor;
}
QColor LunarCalendarWidget::getCurrentLunarColor() const
{
return this->currentLunarColor;
}
QColor LunarCalendarWidget::getOtherLunarColor() const
{
return this->otherLunarColor;
}
QColor LunarCalendarWidget::getSelectLunarColor() const
{
return this->selectLunarColor;
}
QColor LunarCalendarWidget::getHoverLunarColor() const
{
return this->hoverLunarColor;
}
QColor LunarCalendarWidget::getCurrentBgColor() const
{
return this->currentBgColor;
}
QColor LunarCalendarWidget::getOtherBgColor() const
{
return this->otherBgColor;
}
QColor LunarCalendarWidget::getSelectBgColor() const
{
return this->selectBgColor;
}
QColor LunarCalendarWidget::getHoverBgColor() const
{
return this->hoverBgColor;
}
QSize LunarCalendarWidget::sizeHint() const
{
return QSize(600, 500);
}
QSize LunarCalendarWidget::minimumSizeHint() const
{
return QSize(200, 150);
}
//显示上一年
void LunarCalendarWidget::showPreviousYear()
{
int year = date.year();
int month = date.month();
int day = date.day();
if (year <= 1901) {
return;
}
year--;
dateChanged(year, month, day);
}
//显示下一年
void LunarCalendarWidget::showNextYear()
{
int year = date.year();
int month = date.month();
int day = date.day();
if (year >= 2099) {
return;
}
year++;
dateChanged(year, month, day);
}
//显示上月日期
void LunarCalendarWidget::showPreviousMonth()
{
int year = date.year();
int month = date.month();
int day = date.day();
if (year <= 1901 && month == 1) {
return;
}
month--;
if (month < 1) {
month = 12;
year--;
}
dateChanged(year, month, day);
}
//显示下月日期
void LunarCalendarWidget::showNextMonth()
{
int year = date.year();
int month = date.month();
int day = date.day();
if (year >= 2099 && month == 12) {
return;
}
month++;
if (month > 12) {
month = 1;
year++;
}
dateChanged(year, month, day);
}
//转到今天
void LunarCalendarWidget::showToday()
{
date = QDate::currentDate();
initDate();
dayChanged(date);
}
void LunarCalendarWidget::setCalendarStyle(const LunarCalendarWidget::CalendarStyle &calendarStyle)
{
if (this->calendarStyle != calendarStyle) {
this->calendarStyle = calendarStyle;
}
}
void LunarCalendarWidget::setWeekNameFormat(const LunarCalendarWidget::WeekNameFormat &weekNameFormat)
{
if (this->weekNameFormat != weekNameFormat) {
this->weekNameFormat = weekNameFormat;
QStringList listWeek;
if (weekNameFormat == WeekNameFormat_Short) {
listWeek << "" << "" << "" << "" << "" << "" << "";
} else if (weekNameFormat == WeekNameFormat_Normal) {
listWeek << "周日" << "周一" << "周二" << "周三" << "周四" << "周五" << "周六";
} else if (weekNameFormat == WeekNameFormat_Long) {
listWeek << "星期天" << "星期一" << "星期二" << "星期三" << "星期四" << "星期五" << "星期六";
} else if (weekNameFormat == WeekNameFormat_En) {
listWeek << "Sun" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat";
}
//逐个添加日期文字
for (int i = 0; i < 7; i++) {
labWeeks.at(i)->setText(listWeek.at(i));
}
}
}
void LunarCalendarWidget::setDate(const QDate &date)
{
if (this->date != date) {
this->date = date;
initDate();
}
}
void LunarCalendarWidget::setWeekTextColor(const QColor &weekTextColor)
{
if (this->weekTextColor != weekTextColor) {
this->weekTextColor = weekTextColor;
initStyle();
}
}
void LunarCalendarWidget::setWeekBgColor(const QColor &weekBgColor)
{
if (this->weekBgColor != weekBgColor) {
this->weekBgColor = weekBgColor;
initStyle();
}
}
void LunarCalendarWidget::setShowLunar(bool showLunar)
{
if (this->showLunar != showLunar) {
this->showLunar = showLunar;
initStyle();
}
}
void LunarCalendarWidget::setBgImage(const QString &bgImage)
{
if (this->bgImage != bgImage) {
this->bgImage = bgImage;
initStyle();
}
}
void LunarCalendarWidget::setSelectType(const LunarCalendarWidget::SelectType &selectType)
{
if (this->selectType != selectType) {
this->selectType = selectType;
initStyle();
}
}
void LunarCalendarWidget::setBorderColor(const QColor &borderColor)
{
if (this->borderColor != borderColor) {
this->borderColor = borderColor;
initStyle();
}
}
void LunarCalendarWidget::setWeekColor(const QColor &weekColor)
{
if (this->weekColor != weekColor) {
this->weekColor = weekColor;
initStyle();
}
}
void LunarCalendarWidget::setSuperColor(const QColor &superColor)
{
if (this->superColor != superColor) {
this->superColor = superColor;
initStyle();
}
}
void LunarCalendarWidget::setLunarColor(const QColor &lunarColor)
{
if (this->lunarColor != lunarColor) {
this->lunarColor = lunarColor;
initStyle();
}
}
void LunarCalendarWidget::setCurrentTextColor(const QColor &currentTextColor)
{
if (this->currentTextColor != currentTextColor) {
this->currentTextColor = currentTextColor;
initStyle();
}
}
void LunarCalendarWidget::setOtherTextColor(const QColor &otherTextColor)
{
if (this->otherTextColor != otherTextColor) {
this->otherTextColor = otherTextColor;
initStyle();
}
}
void LunarCalendarWidget::setSelectTextColor(const QColor &selectTextColor)
{
if (this->selectTextColor != selectTextColor) {
this->selectTextColor = selectTextColor;
initStyle();
}
}
void LunarCalendarWidget::setHoverTextColor(const QColor &hoverTextColor)
{
if (this->hoverTextColor != hoverTextColor) {
this->hoverTextColor = hoverTextColor;
initStyle();
}
}
void LunarCalendarWidget::setCurrentLunarColor(const QColor &currentLunarColor)
{
if (this->currentLunarColor != currentLunarColor) {
this->currentLunarColor = currentLunarColor;
initStyle();
}
}
void LunarCalendarWidget::setOtherLunarColor(const QColor &otherLunarColor)
{
if (this->otherLunarColor != otherLunarColor) {
this->otherLunarColor = otherLunarColor;
initStyle();
}
}
void LunarCalendarWidget::setSelectLunarColor(const QColor &selectLunarColor)
{
if (this->selectLunarColor != selectLunarColor) {
this->selectLunarColor = selectLunarColor;
initStyle();
}
}
void LunarCalendarWidget::setHoverLunarColor(const QColor &hoverLunarColor)
{
if (this->hoverLunarColor != hoverLunarColor) {
this->hoverLunarColor = hoverLunarColor;
initStyle();
}
}
void LunarCalendarWidget::setCurrentBgColor(const QColor &currentBgColor)
{
if (this->currentBgColor != currentBgColor) {
this->currentBgColor = currentBgColor;
initStyle();
}
}
void LunarCalendarWidget::setOtherBgColor(const QColor &otherBgColor)
{
if (this->otherBgColor != otherBgColor) {
this->otherBgColor = otherBgColor;
initStyle();
}
}
void LunarCalendarWidget::setSelectBgColor(const QColor &selectBgColor)
{
if (this->selectBgColor != selectBgColor) {
this->selectBgColor = selectBgColor;
initStyle();
}
}
void LunarCalendarWidget::setHoverBgColor(const QColor &hoverBgColor)
{
if (this->hoverBgColor != hoverBgColor) {
this->hoverBgColor = hoverBgColor;
initStyle();
}
}

View File

@@ -0,0 +1,248 @@
#ifndef LUNARCALENDARWIDGET_H
#define LUNARCALENDARWIDGET_H
/**
* 自定义农历控件 作者:倪大侠 整理:feiyangqingyun(QQ:517216493) 2017-11-17
* 1. 可设置边框颜色、周末颜色、角标颜色、农历节日颜色。
* 2. 可设置当前月文字颜色、其他月文字颜色、选中日期文字颜色、悬停日期文字颜色。
* 3. 可设置当前月农历文字颜色、其他月农历文字颜色、选中日期农历文字颜色、悬停日期农历文字颜色。
* 4. 可设置当前月背景颜色、其他月背景颜色、选中日期背景颜色、悬停日期背景颜色。
* 5. 可设置三种选中背景模式,矩形背景、圆形背景、图片背景。
* 6. 可直接切换到上一年、下一年、上一月、下一月、转到今天。
* 7. 可设置是否显示农历信息,不显示则当做正常的日历使用。
* 8. 支持1901年-2099年范围。
* 9. 很方便改成多选日期。
*/
#include <QWidget>
#include <QDate>
#include "lunarcalendarinfo.h"
#include "lunarcalendaritem.h"
class QLabel;
class QComboBox;
class LunarCalendarItem;
#ifdef quc
class Q_DECL_EXPORT LunarCalendarWidget : public QWidget
#else
class LunarCalendarWidget : public QWidget
#endif
{
Q_OBJECT
Q_ENUMS(CalendarStyle)
Q_ENUMS(WeekNameFormat)
Q_ENUMS(SelectType)
Q_PROPERTY(CalendarStyle calendarStyle READ getCalendarStyle WRITE setCalendarStyle)
Q_PROPERTY(WeekNameFormat weekNameFormat READ getWeekNameFormat WRITE setWeekNameFormat)
Q_PROPERTY(QDate date READ getDate WRITE setDate)
Q_PROPERTY(QColor weekTextColor READ getWeekTextColor WRITE setWeekTextColor)
Q_PROPERTY(QColor weekBgColor READ getWeekBgColor WRITE setWeekBgColor)
Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar)
Q_PROPERTY(QString bgImage READ getBgImage WRITE setBgImage)
Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType)
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor)
Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor)
Q_PROPERTY(QColor superColor READ getSuperColor WRITE setSuperColor)
Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor)
Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor)
Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor)
Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor)
Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor)
Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor)
Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor)
Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor)
Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor)
Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor)
Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor)
Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor)
Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor)
public:
enum CalendarStyle {
CalendarStyle_Red = 0
};
enum WeekNameFormat {
WeekNameFormat_Short = 0, //短名称
WeekNameFormat_Normal = 1, //普通名称
WeekNameFormat_Long = 2, //长名称
WeekNameFormat_En = 3 //英文名称
};
enum SelectType {
SelectType_Rect = 0, //矩形背景
SelectType_Circle = 1, //圆形背景
SelectType_Triangle = 2, //带三角标
SelectType_Image = 3 //图片背景
};
explicit LunarCalendarWidget(QWidget *parent = 0);
~LunarCalendarWidget();
private:
QFont iconFont; //图形字体
bool btnClick; //按钮单击,避开下拉选择重复触发
QComboBox *cboxYear; //年份下拉框
QComboBox *cboxMonth; //月份下拉框
QList<QLabel *> labWeeks; //顶部星期名称
QList<LunarCalendarItem *> dayItems;//日期元素
CalendarStyle calendarStyle; //整体样式
WeekNameFormat weekNameFormat; //星期名称格式
QDate date; //当前日期
QColor weekTextColor; //星期名称文字颜色
QColor weekBgColor; //星期名称背景色
bool showLunar; //显示农历
QString bgImage; //背景图片
SelectType selectType; //选中模式
QColor borderColor; //边框颜色
QColor weekColor; //周末颜色
QColor superColor; //角标颜色
QColor lunarColor; //农历节日颜色
QColor currentTextColor; //当前月文字颜色
QColor otherTextColor; //其他月文字颜色
QColor selectTextColor; //选中日期文字颜色
QColor hoverTextColor; //悬停日期文字颜色
QColor currentLunarColor; //当前月农历文字颜色
QColor otherLunarColor; //其他月农历文字颜色
QColor selectLunarColor; //选中日期农历文字颜色
QColor hoverLunarColor; //悬停日期农历文字颜色
QColor currentBgColor; //当前月背景颜色
QColor otherBgColor; //其他月背景颜色
QColor selectBgColor; //选中日期背景颜色
QColor hoverBgColor; //悬停日期背景颜色
private slots:
void initWidget();
void initStyle();
void initDate();
void yearChanged(int);
void monthChanged(int);
void clicked(const QDate &date, const LunarCalendarItem::DayType &dayType);
void dayChanged(const QDate &date);
void dateChanged(int year, int month, int day);
public:
CalendarStyle getCalendarStyle() const;
WeekNameFormat getWeekNameFormat() const;
QDate getDate() const;
QColor getWeekTextColor() const;
QColor getWeekBgColor() const;
bool getShowLunar() const;
QString getBgImage() const;
SelectType getSelectType() const;
QColor getBorderColor() const;
QColor getWeekColor() const;
QColor getSuperColor() const;
QColor getLunarColor() const;
QColor getCurrentTextColor() const;
QColor getOtherTextColor() const;
QColor getSelectTextColor() const;
QColor getHoverTextColor() const;
QColor getCurrentLunarColor() const;
QColor getOtherLunarColor() const;
QColor getSelectLunarColor() const;
QColor getHoverLunarColor() const;
QColor getCurrentBgColor() const;
QColor getOtherBgColor() const;
QColor getSelectBgColor() const;
QColor getHoverBgColor() const;
QSize sizeHint() const;
QSize minimumSizeHint() const;
public Q_SLOTS:
//上一年,下一年
void showPreviousYear();
void showNextYear();
//上一月,下一月
void showPreviousMonth();
void showNextMonth();
//转到今天
void showToday();
//设置整体样式
void setCalendarStyle(const CalendarStyle &calendarStyle);
//设置星期名称格式
void setWeekNameFormat(const WeekNameFormat &weekNameFormat);
//设置日期
void setDate(const QDate &date);
//设置顶部星期名称文字颜色+背景色
void setWeekTextColor(const QColor &weekTextColor);
void setWeekBgColor(const QColor &weekBgColor);
//设置是否显示农历信息
void setShowLunar(bool showLunar);
//设置背景图片
void setBgImage(const QString &bgImage);
//设置选中背景样式
void setSelectType(const SelectType &selectType);
//设置边框颜色
void setBorderColor(const QColor &borderColor);
//设置周末颜色
void setWeekColor(const QColor &weekColor);
//设置角标颜色
void setSuperColor(const QColor &superColor);
//设置农历节日颜色
void setLunarColor(const QColor &lunarColor);
//设置当前月文字颜色
void setCurrentTextColor(const QColor &currentTextColor);
//设置其他月文字颜色
void setOtherTextColor(const QColor &otherTextColor);
//设置选中日期文字颜色
void setSelectTextColor(const QColor &selectTextColor);
//设置悬停日期文字颜色
void setHoverTextColor(const QColor &hoverTextColor);
//设置当前月农历文字颜色
void setCurrentLunarColor(const QColor &currentLunarColor);
//设置其他月农历文字颜色
void setOtherLunarColor(const QColor &otherLunarColor);
//设置选中日期农历文字颜色
void setSelectLunarColor(const QColor &selectLunarColor);
//设置悬停日期农历文字颜色
void setHoverLunarColor(const QColor &hoverLunarColor);
//设置当前月背景颜色
void setCurrentBgColor(const QColor &currentBgColor);
//设置其他月背景颜色
void setOtherBgColor(const QColor &otherBgColor);
//设置选中日期背景颜色
void setSelectBgColor(const QColor &selectBgColor);
//设置悬停日期背景颜色
void setHoverBgColor(const QColor &hoverBgColor);
Q_SIGNALS:
void clicked(const QDate &date);
void selectionChanged();
};
#endif // LUNARCALENDARWIDGET_H

View File

@@ -0,0 +1,28 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = lunarcalendarwidget
TEMPLATE = app
MOC_DIR = temp/moc
RCC_DIR = temp/rcc
UI_DIR = temp/ui
OBJECTS_DIR = temp/obj
DESTDIR = $$PWD/../bin
CONFIG += qt warn_off
RESOURCES += main.qrc
SOURCES += main.cpp
SOURCES += frmlunarcalendarwidget.cpp
SOURCES += lunarcalendaritem.cpp
SOURCES += lunarcalendarinfo.cpp
SOURCES += lunarcalendarwidget.cpp
HEADERS += frmlunarcalendarwidget.h
HEADERS += lunarcalendaritem.h
HEADERS += lunarcalendarinfo.h
HEADERS += lunarcalendarwidget.h
FORMS += frmlunarcalendarwidget.ui
INCLUDEPATH += $$PWD

View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmlunarcalendarwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmLunarCalendarWidget w;
w.setWindowTitle("农历控件");
w.show();
return a.exec();
}

View File

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

View File

@@ -0,0 +1,34 @@
#pragma execution_character_set("utf-8")
#include "frmmaskwidget.h"
#include "ui_frmmaskwidget.h"
#include "maskwidget.h"
#include "qdialog.h"
#include "qtimer.h"
#include "qdebug.h"
frmMaskWidget::frmMaskWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmMaskWidget)
{
ui->setupUi(this);
QTimer::singleShot(1000, this, SLOT(initForm()));
}
frmMaskWidget::~frmMaskWidget()
{
delete ui;
}
void frmMaskWidget::initForm()
{
MaskWidget::Instance()->setMainWidget(this->topLevelWidget());
MaskWidget::Instance()->setDialogNames(QStringList() << "frmTest");
}
void frmMaskWidget::on_pushButton_clicked()
{
QDialog d;
d.setObjectName("frmTest");
d.setWindowTitle("遮罩层弹出窗体");
d.resize(400, 300);
d.exec();
}

View File

@@ -0,0 +1,26 @@
#ifndef FRMMASKWIDGET_H
#define FRMMASKWIDGET_H
#include <QWidget>
namespace Ui {
class frmMaskWidget;
}
class frmMaskWidget : public QWidget
{
Q_OBJECT
public:
explicit frmMaskWidget(QWidget *parent = 0);
~frmMaskWidget();
private:
Ui::frmMaskWidget *ui;
private slots:
void initForm();
void on_pushButton_clicked();
};
#endif // FRMMASKWIDGET_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmMaskWidget</class>
<widget class="QWidget" name="frmMaskWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>92</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>弹出</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmmaskwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmMaskWidget w;
w.setWindowTitle("遮罩层窗体");
w.show();
return a.exec();
}

View File

@@ -0,0 +1,104 @@
#pragma execution_character_set("utf-8")
#include "maskwidget.h"
#include "qmutex.h"
#include "qapplication.h"
#include "qdebug.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
#include "qscreen.h"
#define deskGeometry qApp->primaryScreen()->geometry()
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
#else
#include "qdesktopwidget.h"
#define deskGeometry qApp->desktop()->geometry()
#define deskGeometry2 qApp->desktop()->availableGeometry()
#endif
QScopedPointer<MaskWidget> MaskWidget::self;
MaskWidget *MaskWidget::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new MaskWidget);
}
}
return self.data();
}
MaskWidget::MaskWidget(QWidget *parent) : QWidget(parent)
{
mainWidget = 0;
setOpacity(0.7);
setBgColor(QColor(0, 0, 0));
//不设置主窗体则遮罩层大小为默认桌面大小
this->setGeometry(deskGeometry);
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
//绑定全局事件,过滤弹窗窗体进行处理
qApp->installEventFilter(this);
}
void MaskWidget::setMainWidget(QWidget *mainWidget)
{
if (this->mainWidget != mainWidget) {
this->mainWidget = mainWidget;
}
}
void MaskWidget::setDialogNames(const QStringList &dialogNames)
{
if (this->dialogNames != dialogNames) {
this->dialogNames = dialogNames;
}
}
void MaskWidget::setOpacity(double opacity)
{
this->setWindowOpacity(opacity);
}
void MaskWidget::setBgColor(const QColor &bgColor)
{
QPalette palette = this->palette();
palette.setBrush(QPalette::Window, bgColor);
this->setPalette(palette);
}
void MaskWidget::showEvent(QShowEvent *)
{
if (mainWidget != 0) {
this->setGeometry(mainWidget->geometry());
}
}
bool MaskWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Show) {
if (dialogNames.contains(obj->objectName())) {
this->show();
this->activateWindow();
QWidget *w = (QWidget *)obj;
w->activateWindow();
}
} else if (event->type() == QEvent::Hide) {
if (dialogNames.contains(obj->objectName())) {
this->hide();
}
} else if (event->type() == QEvent::WindowActivate) {
//当主窗体激活时,同时激活遮罩层
if (mainWidget != 0) {
if (obj->objectName() == mainWidget->objectName()) {
if (this->isVisible()) {
this->activateWindow();
}
}
}
}
return QObject::eventFilter(obj, event);
}

View File

@@ -0,0 +1,51 @@
#ifndef MASKWIDGET_H
#define MASKWIDGET_H
/**
* 弹窗遮罩层控件 作者:feiyangqingyun(QQ:517216493) 2016-12-26
* 1. 可设置需要遮罩的主窗体,自动跟随主窗体位置显示遮罩面积。
* 2. 只需要将弹窗窗体的名称一开始传入队列即可,足够简单。
* 3. 可设置透明度。
* 4. 可设置遮罩层颜色。
* 5. 不阻塞消息循坏。
*/
#include <QWidget>
#ifdef quc
class Q_DECL_EXPORT MaskWidget : public QWidget
#else
class MaskWidget : public QWidget
#endif
{
Q_OBJECT
public:
static MaskWidget *Instance();
explicit MaskWidget(QWidget *parent = 0);
protected:
void showEvent(QShowEvent *);
bool eventFilter(QObject *obj, QEvent *event);
private:
static QScopedPointer<MaskWidget> self;
//需要遮罩的主窗体
QWidget *mainWidget;
//需要弹窗的窗体对象名称集合链表
QStringList dialogNames;
public Q_SLOTS:
//设置需要遮罩的主窗体
void setMainWidget(QWidget *mainWidget);
//设置需要弹窗的窗体对象名称集合链表
void setDialogNames(const QStringList &dialogNames);
//设置遮罩颜色
void setBgColor(const QColor &bgColor);
//设置颜色透明度
void setOpacity(double opacity);
};
#endif // MASKWIDGET_H

View File

@@ -0,0 +1,19 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = maskwidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += maskwidget.cpp
SOURCES += frmmaskwidget.cpp
HEADERS += maskwidget.h
HEADERS += frmmaskwidget.h
FORMS += frmmaskwidget.ui

View File

@@ -0,0 +1,41 @@
#pragma execution_character_set("utf-8")
#include "frmmovewidget.h"
#include "ui_frmmovewidget.h"
#include "qpushbutton.h"
#include "qprogressbar.h"
#include "movewidget.h"
frmMoveWidget::frmMoveWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmMoveWidget)
{
ui->setupUi(this);
this->initForm();
}
frmMoveWidget::~frmMoveWidget()
{
delete ui;
}
void frmMoveWidget::initForm()
{
QPushButton *btn1 = new QPushButton(this);
btn1->setGeometry(10, 10, 250, 25);
btn1->setText("按住我拖动(仅限左键拖动)");
MoveWidget *moveWidget1 = new MoveWidget(this);
moveWidget1->setWidget(btn1);
QPushButton *btn2 = new QPushButton(this);
btn2->setGeometry(10, 40, 250, 25);
btn2->setText("按住我拖动(支持右键拖动)");
MoveWidget *moveWidget2 = new MoveWidget(this);
moveWidget2->setWidget(btn2);
moveWidget2->setLeftButton(false);
QProgressBar *bar = new QProgressBar(this);
bar->setGeometry(10, 70, 250, 25);
bar->setRange(0, 0);
bar->setTextVisible(false);
MoveWidget *moveWidget3 = new MoveWidget(this);
moveWidget3->setWidget(bar);
}

View File

@@ -0,0 +1,25 @@
#ifndef FRMMOVEWIDGET_H
#define FRMMOVEWIDGET_H
#include <QWidget>
namespace Ui {
class frmMoveWidget;
}
class frmMoveWidget : public QWidget
{
Q_OBJECT
public:
explicit frmMoveWidget(QWidget *parent = 0);
~frmMoveWidget();
private:
Ui::frmMoveWidget *ui;
private slots:
void initForm();
};
#endif // FRMMOVEWIDGET_H

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmMoveWidget</class>
<widget class="QWidget" name="frmMoveWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmmovewidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmMoveWidget w;
w.setWindowTitle("通用移动类");
w.show();
return a.exec();
}

View File

@@ -0,0 +1,74 @@
#include "movewidget.h"
#include "qevent.h"
#include "qdebug.h"
MoveWidget::MoveWidget(QObject *parent) : QObject(parent)
{
lastPoint = QPoint(0, 0);
pressed = false;
leftButton = true;
inControl = true;
widget = 0;
}
bool MoveWidget::eventFilter(QObject *watched, QEvent *event)
{
if (widget != 0 && watched == widget) {
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if (mouseEvent->type() == QEvent::MouseButtonPress) {
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
if (leftButton && mouseEvent->button() != Qt::LeftButton) {
return false;
}
//判断控件的区域是否包含了当前鼠标的坐标
if (widget->rect().contains(mouseEvent->pos())) {
lastPoint = mouseEvent->pos();
pressed = true;
}
} else if (mouseEvent->type() == QEvent::MouseMove && pressed) {
//计算坐标偏移值,调用move函数移动过去
int offsetX = mouseEvent->pos().x() - lastPoint.x();
int offsetY = mouseEvent->pos().y() - lastPoint.y();
int x = widget->x() + offsetX;
int y = widget->y() + offsetY;
if (inControl) {
//可以自行调整限定在容器中的范围,这里默认保留20个像素在里面
int offset = 20;
bool xyOut = (x + widget->width() < offset || y + widget->height() < offset);
bool whOut = false;
QWidget *w = (QWidget *)widget->parent();
if (w != 0) {
whOut = (w->width() - x < offset || w->height() - y < offset);
}
if (xyOut || whOut) {
return false;
}
}
widget->move(x, y);
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) {
pressed = false;
}
}
return QObject::eventFilter(watched, event);
}
void MoveWidget::setLeftButton(bool leftButton)
{
this->leftButton = leftButton;
}
void MoveWidget::setInControl(bool inControl)
{
this->inControl = inControl;
}
void MoveWidget::setWidget(QWidget *widget)
{
if (this->widget == 0) {
this->widget = widget;
this->widget->installEventFilter(this);
}
}

View File

@@ -0,0 +1,43 @@
#ifndef MOVEWIDGET_H
#define MOVEWIDGET_H
/**
* 通用控件移动类 作者:feiyangqingyun(QQ:517216493) 2019-09-28
* 1. 可以指定需要移动的widget。
* 2. 可设置是否限定鼠标左键拖动。
* 3. 支持任意widget控件。
*/
#include <QWidget>
#ifdef quc
class Q_DECL_EXPORT MoveWidget : public QObject
#else
class MoveWidget : public QObject
#endif
{
Q_OBJECT
public:
explicit MoveWidget(QObject *parent = 0);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
QPoint lastPoint; //最后按下的坐标
bool pressed; //鼠标是否按下
bool leftButton; //限定鼠标左键
bool inControl; //限定在容器内
QWidget *widget; //移动的控件
public Q_SLOTS:
//设置是否限定鼠标左键
void setLeftButton(bool leftButton);
//设置是否限定不能移出容器外面
void setInControl(bool inControl);
//设置要移动的控件
void setWidget(QWidget *widget);
};
#endif // MOVEWIDGET_H

View File

@@ -0,0 +1,17 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = movewidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmmovewidget.cpp
SOURCES += movewidget.cpp
HEADERS += frmmovewidget.h
HEADERS += movewidget.h
FORMS += frmmovewidget.ui

View File

@@ -0,0 +1,18 @@
#include "frmscreenwidget.h"
#include "ui_frmscreenwidget.h"
#include "screenwidget.h"
frmScreenWidget::frmScreenWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmScreenWidget)
{
ui->setupUi(this);
}
frmScreenWidget::~frmScreenWidget()
{
delete ui;
}
void frmScreenWidget::on_pushButton_clicked()
{
ScreenWidget::Instance()->showFullScreen();
}

View File

@@ -0,0 +1,25 @@
#ifndef FRMSCREENWIDGET_H
#define FRMSCREENWIDGET_H
#include <QWidget>
namespace Ui {
class frmScreenWidget;
}
class frmScreenWidget : public QWidget
{
Q_OBJECT
public:
explicit frmScreenWidget(QWidget *parent = 0);
~frmScreenWidget();
private slots:
void on_pushButton_clicked();
private:
Ui::frmScreenWidget *ui;
};
#endif // FRMSCREENWIDGET_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmScreenWidget</class>
<widget class="QWidget" name="frmScreenWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>92</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>弹出</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmscreenwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#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
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmScreenWidget w;
w.setWindowTitle("屏幕截图");
w.show();
return a.exec();
}

View File

@@ -0,0 +1,332 @@
#pragma execution_character_set("utf-8")
#include "screenwidget.h"
#include "qmutex.h"
#include "qapplication.h"
#include "qpainter.h"
#include "qfiledialog.h"
#include "qevent.h"
#include "qdatetime.h"
#include "qstringlist.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
#include "qscreen.h"
#define deskGeometry qApp->primaryScreen()->geometry()
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
#else
#include "qdesktopwidget.h"
#define deskGeometry qApp->desktop()->geometry()
#define deskGeometry2 qApp->desktop()->availableGeometry()
#endif
#define STRDATETIME qPrintable (QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
Screen::Screen(QSize size)
{
maxWidth = size.width();
maxHeight = size.height();
startPos = QPoint(-1, -1);
endPos = startPos;
leftUpPos = startPos;
rightDownPos = startPos;
status = SELECT;
}
int Screen::width()
{
return maxWidth;
}
int Screen::height()
{
return maxHeight;
}
Screen::STATUS Screen::getStatus()
{
return status;
}
void Screen::setStatus(STATUS status)
{
this->status = status;
}
void Screen::setEnd(QPoint pos)
{
endPos = pos;
leftUpPos = startPos;
rightDownPos = endPos;
cmpPoint(leftUpPos, rightDownPos);
}
void Screen::setStart(QPoint pos)
{
startPos = pos;
}
QPoint Screen::getEnd()
{
return endPos;
}
QPoint Screen::getStart()
{
return startPos;
}
QPoint Screen::getLeftUp()
{
return leftUpPos;
}
QPoint Screen::getRightDown()
{
return rightDownPos;
}
bool Screen::isInArea(QPoint pos)
{
if (pos.x() > leftUpPos.x() && pos.x() < rightDownPos.x() && pos.y() > leftUpPos.y() && pos.y() < rightDownPos.y()) {
return true;
}
return false;
}
void Screen::move(QPoint p)
{
int lx = leftUpPos.x() + p.x();
int ly = leftUpPos.y() + p.y();
int rx = rightDownPos.x() + p.x();
int ry = rightDownPos.y() + p.y();
if (lx < 0) {
lx = 0;
rx -= p.x();
}
if (ly < 0) {
ly = 0;
ry -= p.y();
}
if (rx > maxWidth) {
rx = maxWidth;
lx -= p.x();
}
if (ry > maxHeight) {
ry = maxHeight;
ly -= p.y();
}
leftUpPos = QPoint(lx, ly);
rightDownPos = QPoint(rx, ry);
startPos = leftUpPos;
endPos = rightDownPos;
}
void Screen::cmpPoint(QPoint &leftTop, QPoint &rightDown)
{
QPoint l = leftTop;
QPoint r = rightDown;
if (l.x() <= r.x()) {
if (l.y() <= r.y()) {
;
} else {
leftTop.setY(r.y());
rightDown.setY(l.y());
}
} else {
if (l.y() < r.y()) {
leftTop.setX(r.x());
rightDown.setX(l.x());
} else {
QPoint tmp;
tmp = leftTop;
leftTop = rightDown;
rightDown = tmp;
}
}
}
QScopedPointer<ScreenWidget> ScreenWidget::self;
ScreenWidget *ScreenWidget::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new ScreenWidget);
}
}
return self.data();
}
ScreenWidget::ScreenWidget(QWidget *parent) : QWidget(parent)
{
//this->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
menu = new QMenu(this);
menu->addAction("保存当前截图", this, SLOT(saveScreen()));
menu->addAction("保存全屏截图", this, SLOT(saveFullScreen()));
menu->addAction("截图另存为", this, SLOT(saveScreenOther()));
menu->addAction("全屏另存为", this, SLOT(saveFullOther()));
menu->addAction("退出截图", this, SLOT(hide()));
//取得屏幕大小
screen = new Screen(deskGeometry.size());
//保存全屏图像
fullScreen = new QPixmap();
}
void ScreenWidget::paintEvent(QPaintEvent *)
{
int x = screen->getLeftUp().x();
int y = screen->getLeftUp().y();
int w = screen->getRightDown().x() - x;
int h = screen->getRightDown().y() - y;
QPainter painter(this);
QPen pen;
pen.setColor(Qt::green);
pen.setWidth(2);
pen.setStyle(Qt::DotLine);
painter.setPen(pen);
painter.drawPixmap(0, 0, *bgScreen);
if (w != 0 && h != 0) {
painter.drawPixmap(x, y, fullScreen->copy(x, y, w, h));
}
painter.drawRect(x, y, w, h);
pen.setColor(Qt::yellow);
painter.setPen(pen);
painter.drawText(x + 2, y - 8, tr("截图范围:( %1 x %2 ) - ( %3 x %4 ) 图片大小:( %5 x %6 )")
.arg(x).arg(y).arg(x + w).arg(y + h).arg(w).arg(h));
}
void ScreenWidget::showEvent(QShowEvent *)
{
QPoint point(-1, -1);
screen->setStart(point);
screen->setEnd(point);
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
QScreen *pscreen = QApplication::primaryScreen();
*fullScreen = pscreen->grabWindow(0, 0, 0, screen->width(), screen->height());
#else
*fullScreen = fullScreen->grabWindow(0, 0, 0, screen->width(), screen->height());
#endif
//设置透明度实现模糊背景
QPixmap pix(screen->width(), screen->height());
pix.fill((QColor(160, 160, 160, 200)));
bgScreen = new QPixmap(*fullScreen);
QPainter p(bgScreen);
p.drawPixmap(0, 0, pix);
}
void ScreenWidget::saveScreen()
{
int x = screen->getLeftUp().x();
int y = screen->getLeftUp().y();
int w = screen->getRightDown().x() - x;
int h = screen->getRightDown().y() - y;
QString fileName = QString("%1/screen_%2.png").arg(qApp->applicationDirPath()).arg(STRDATETIME);
fullScreen->copy(x, y, w, h).save(fileName, "png");
close();
}
void ScreenWidget::saveFullScreen()
{
QString fileName = QString("%1/full_%2.png").arg(qApp->applicationDirPath()).arg(STRDATETIME);
fullScreen->save(fileName, "png");
close();
}
void ScreenWidget::saveScreenOther()
{
QString name = QString("%1.png").arg(STRDATETIME);
QString fileName = QFileDialog::getSaveFileName(this, "保存图片", name, "png Files (*.png)");
if (!fileName.endsWith(".png")) {
fileName += ".png";
}
if (fileName.length() > 0) {
int x = screen->getLeftUp().x();
int y = screen->getLeftUp().y();
int w = screen->getRightDown().x() - x;
int h = screen->getRightDown().y() - y;
fullScreen->copy(x, y, w, h).save(fileName, "png");
close();
}
}
void ScreenWidget::saveFullOther()
{
QString name = QString("%1.png").arg(STRDATETIME);
QString fileName = QFileDialog::getSaveFileName(this, "保存图片", name, "png Files (*.png)");
if (!fileName.endsWith(".png")) {
fileName += ".png";
}
if (fileName.length() > 0) {
fullScreen->save(fileName, "png");
close();
}
}
void ScreenWidget::mouseMoveEvent(QMouseEvent *e)
{
if (screen->getStatus() == Screen::SELECT) {
screen->setEnd(e->pos());
} else if (screen->getStatus() == Screen::MOV) {
QPoint p(e->x() - movPos.x(), e->y() - movPos.y());
screen->move(p);
movPos = e->pos();
}
this->update();
}
void ScreenWidget::mousePressEvent(QMouseEvent *e)
{
int status = screen->getStatus();
if (status == Screen::SELECT) {
screen->setStart(e->pos());
} else if (status == Screen::MOV) {
if (screen->isInArea(e->pos()) == false) {
screen->setStart(e->pos());
screen->setStatus(Screen::SELECT);
} else {
movPos = e->pos();
this->setCursor(Qt::SizeAllCursor);
}
}
this->update();
}
void ScreenWidget::mouseReleaseEvent(QMouseEvent *)
{
if (screen->getStatus() == Screen::SELECT) {
screen->setStatus(Screen::MOV);
} else if (screen->getStatus() == Screen::MOV) {
this->setCursor(Qt::ArrowCursor);
}
}
void ScreenWidget::contextMenuEvent(QContextMenuEvent *)
{
this->setCursor(Qt::ArrowCursor);
menu->exec(cursor().pos());
}

View File

@@ -0,0 +1,94 @@
#ifndef SCREENWIDGET_H
#define SCREENWIDGET_H
/**
* 全局截屏控件 作者:feiyangqingyun(QQ:517216493) 2016-11-11
* 1. 鼠标右键弹出菜单。
* 2. 支持全局截屏。
* 3. 支持局部截屏。
* 4. 支持截图区域拖动。
* 5. 支持图片另存为。
*/
#include <QWidget>
#include <QMenu>
#include <QPoint>
#include <QSize>
class Screen
{
public:
enum STATUS {SELECT, MOV, SET_W_H};
Screen() {}
Screen(QSize size);
void setStart(QPoint pos);
void setEnd(QPoint pos);
QPoint getStart();
QPoint getEnd();
QPoint getLeftUp();
QPoint getRightDown();
STATUS getStatus();
void setStatus(STATUS status);
int width();
int height();
//检测坐标点是否在截图区域内
bool isInArea(QPoint pos);
//按坐标移动截图区域
void move(QPoint p);
private:
//记录 截图区域 左上角、右下角
QPoint leftUpPos, rightDownPos;
//记录 鼠标开始位置、结束位置
QPoint startPos, endPos;
//记录屏幕大小
int maxWidth, maxHeight;
//三个状态: 选择区域、移动区域、设置width height
STATUS status;
//比较两位置,判断左上角、右下角
void cmpPoint(QPoint &s, QPoint &e);
};
#ifdef quc
class Q_DECL_EXPORT ScreenWidget : public QWidget
#else
class ScreenWidget : public QWidget
#endif
{
Q_OBJECT
public:
static ScreenWidget *Instance();
explicit ScreenWidget(QWidget *parent = 0);
private:
static QScopedPointer<ScreenWidget> self;
QMenu *menu; //右键菜单对象
Screen *screen; //截屏对象
QPixmap *fullScreen; //保存全屏图像
QPixmap *bgScreen; //模糊背景图
QPoint movPos; //坐标
protected:
void contextMenuEvent(QContextMenuEvent *);
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void paintEvent(QPaintEvent *);
void showEvent(QShowEvent *);
private slots:
void saveScreen();
void saveFullScreen();
void saveScreenOther();
void saveFullOther();
};
#endif // SCREENWIDGET_H

View File

@@ -0,0 +1,17 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = screenwidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmscreenwidget.cpp
SOURCES += screenwidget.cpp
HEADERS += screenwidget.h
HEADERS += frmscreenwidget.h
FORMS += frmscreenwidget.ui

8
widget/widget.pro Normal file
View File

@@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += colorwidget
SUBDIRS += framelesswidget
SUBDIRS += gifwidget
SUBDIRS += lunarcalendarwidget
SUBDIRS += maskwidget
SUBDIRS += movewidget
SUBDIRS += screenwidget