feat: 初始化widget模块代码

master
laixingyu 3 years ago
parent 12f641d4c5
commit 8907614811

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -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);
}

@ -0,0 +1,58 @@
#ifndef COLORWIDGET_H
#define COLORWIDGET_H
/**
* :feiyangqingyun(QQ:517216493) 2016-11-11
* 1.
* 2.
* 3. 16rgb
* 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

@ -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

@ -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();
}

@ -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

@ -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>

@ -0,0 +1,34 @@
#pragma execution_character_set("utf-8")
#include "frmcolorwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
#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("屏幕拾色器 (QQ: 517216493 WX: feiyangqingyun)");
w.show();
return a.exec();
}

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

@ -0,0 +1,377 @@
#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;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
Q_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) {
Q_EMIT titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
Q_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_SYSKEYDOWN) {
//屏蔽alt键按下
} else if (msg->message == WM_SYSKEYUP) {
//屏蔽alt键松开
} 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 && 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);
}

@ -0,0 +1,96 @@
#ifndef FRAMELESSDIALOG_H
#define FRAMELESSDIALOG_H
/**
* :feiyangqingyun(QQ:517216493) 2021-07-27
* 1. Qt4-Qt6Qt4.7Qt6.2
* 2. mingwmsvcgcc
* 3. windowslinuxmac
* 4. QMainWindowQWidgetQDialog
* 5. 使
* 6.
* 7. windows
* 8. windows
* 9. macbug
* 10. bug
* 11. bug
* 12. 1300
* 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

@ -0,0 +1,375 @@
#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;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
Q_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) {
Q_EMIT titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
Q_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_SYSKEYDOWN) {
//屏蔽alt键按下
} else if (msg->message == WM_SYSKEYUP) {
//屏蔽alt键松开
} 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 && 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);
}

@ -0,0 +1,96 @@
#ifndef FRAMELESSMAINWINDOW_H
#define FRAMELESSMAINWINDOW_H
/**
* :feiyangqingyun(QQ:517216493) 2021-07-27
* 1. Qt4-Qt6Qt4.7Qt6.2
* 2. mingwmsvcgcc
* 3. windowslinuxmac
* 4. QMainWindowQWidgetQDialog
* 5. 使
* 6.
* 7. windows
* 8. windows
* 9. macbug
* 10. bug
* 11. bug
* 12. 1300
* 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

@ -0,0 +1,377 @@
#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;
}
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
Q_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) {
Q_EMIT titleDblClick();
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
Q_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_SYSKEYDOWN) {
//屏蔽alt键按下
} else if (msg->message == WM_SYSKEYUP) {
//屏蔽alt键松开
} 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 && 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);
}

@ -0,0 +1,96 @@
#ifndef FRAMELESSWIDGET_H
#define FRAMELESSWIDGET_H
/**
* :feiyangqingyun(QQ:517216493) 2021-07-27
* 1. Qt4-Qt6Qt4.7Qt6.2
* 2. mingwmsvcgcc
* 3. windowslinuxmac
* 4. QMainWindowQWidgetQDialog
* 5. 使
* 6.
* 7. windows
* 8. windows
* 9. macbug
* 10. bug
* 11. bug
* 12. 1300
* 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

@ -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();
}

@ -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

@ -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>

@ -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

@ -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();
}

@ -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

@ -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>

@ -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();
}

@ -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

@ -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>

@ -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)

@ -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 && 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();
}
}

@ -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

@ -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
}

@ -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

@ -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>

@ -0,0 +1,42 @@
#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(5,0,0))
QApplication::setAttribute(Qt::AA_Use96Dpi);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
#endif
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
#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("无边框窗体 (QQ: 517216493 WX: feiyangqingyun)");
w.resize(800, 600);
w.show();
return a.exec();
}

@ -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();
}

@ -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

@ -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>

@ -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

@ -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();
}
}

@ -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

@ -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

@ -0,0 +1,44 @@
#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(5,0,0))
QApplication::setAttribute(Qt::AA_Use96Dpi);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
#endif
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
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录屏 (QQ: 517216493 WX: feiyangqingyun)");
w.show();
return a.exec();
}

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

@ -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);
}

@ -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

@ -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

@ -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);
}

@ -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

@ -0,0 +1,553 @@
#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();
Q_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();
}
QSize LunarCalendarItem::sizeHint() const
{
return QSize(100, 100);
}
QSize LunarCalendarItem::minimumSizeHint() const
{
return QSize(20, 20);
}
bool LunarCalendarItem::getSelect() const
{
return this->select;
}
void LunarCalendarItem::setSelect(bool select)
{
if (this->select != select) {
this->select = select;
this->update();
}
}
bool LunarCalendarItem::getShowLunar() const
{
return this->showLunar;
}
void LunarCalendarItem::setShowLunar(bool showLunar)
{
if (this->showLunar != showLunar) {
this->showLunar = showLunar;
this->update();
}
}
QString LunarCalendarItem::getBgImage() const
{
return this->bgImage;
}
void LunarCalendarItem::setBgImage(const QString &bgImage)
{
if (this->bgImage != bgImage) {
this->bgImage = bgImage;
this->update();
}
}
LunarCalendarItem::SelectType LunarCalendarItem::getSelectType() const
{
return this->selectType;
}
void LunarCalendarItem::setSelectType(const LunarCalendarItem::SelectType &selectType)
{
if (this->selectType != selectType) {
this->selectType = selectType;
this->update();
}
}
QDate LunarCalendarItem::getDate() const
{
return this->date;
}
void LunarCalendarItem::setDate(const QDate &date)
{
if (this->date != date) {
this->date = date;
this->update();
}
}
QString LunarCalendarItem::getLunar() const
{
return this->lunar;
}
void LunarCalendarItem::setLunar(const QString &lunar)
{
if (this->lunar != lunar) {
this->lunar = lunar;
this->update();
}
}
LunarCalendarItem::DayType LunarCalendarItem::getDayType() const
{
return this->dayType;
}
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();
}
QColor LunarCalendarItem::getBorderColor() const
{
return this->borderColor;
}
void LunarCalendarItem::setBorderColor(const QColor &borderColor)
{
if (this->borderColor != borderColor) {
this->borderColor = borderColor;
this->update();
}
}
QColor LunarCalendarItem::getWeekColor() const
{
return this->weekColor;
}
void LunarCalendarItem::setWeekColor(const QColor &weekColor)
{
if (this->weekColor != weekColor) {
this->weekColor = weekColor;
this->update();
}
}
QColor LunarCalendarItem::getSuperColor() const
{
return this->superColor;
}
void LunarCalendarItem::setSuperColor(const QColor &superColor)
{
if (this->superColor != superColor) {
this->superColor = superColor;
this->update();
}
}
QColor LunarCalendarItem::getLunarColor() const
{
return this->lunarColor;
}
void LunarCalendarItem::setLunarColor(const QColor &lunarColor)
{
if (this->lunarColor != lunarColor) {
this->lunarColor = lunarColor;
this->update();
}
}
QColor LunarCalendarItem::getCurrentTextColor() const
{
return this->currentTextColor;
}
void LunarCalendarItem::setCurrentTextColor(const QColor &currentTextColor)
{
if (this->currentTextColor != currentTextColor) {
this->currentTextColor = currentTextColor;
this->update();
}
}
QColor LunarCalendarItem::getOtherTextColor() const
{
return this->otherTextColor;
}
void LunarCalendarItem::setOtherTextColor(const QColor &otherTextColor)
{
if (this->otherTextColor != otherTextColor) {
this->otherTextColor = otherTextColor;
this->update();
}
}
QColor LunarCalendarItem::getSelectTextColor() const
{
return this->selectTextColor;
}
void LunarCalendarItem::setSelectTextColor(const QColor &selectTextColor)
{
if (this->selectTextColor != selectTextColor) {
this->selectTextColor = selectTextColor;
this->update();
}
}
QColor LunarCalendarItem::getHoverTextColor() const
{
return this->hoverTextColor;
}
void LunarCalendarItem::setHoverTextColor(const QColor &hoverTextColor)
{
if (this->hoverTextColor != hoverTextColor) {
this->hoverTextColor = hoverTextColor;
this->update();
}
}
QColor LunarCalendarItem::getCurrentLunarColor() const
{
return this->currentLunarColor;
}
void LunarCalendarItem::setCurrentLunarColor(const QColor &currentLunarColor)
{
if (this->currentLunarColor != currentLunarColor) {
this->currentLunarColor = currentLunarColor;
this->update();
}
}
QColor LunarCalendarItem::getOtherLunarColor() const
{
return this->otherLunarColor;
}
void LunarCalendarItem::setOtherLunarColor(const QColor &otherLunarColor)
{
if (this->otherLunarColor != otherLunarColor) {
this->otherLunarColor = otherLunarColor;
this->update();
}
}
QColor LunarCalendarItem::getSelectLunarColor() const
{
return this->selectLunarColor;
}
void LunarCalendarItem::setSelectLunarColor(const QColor &selectLunarColor)
{
if (this->selectLunarColor != selectLunarColor) {
this->selectLunarColor = selectLunarColor;
this->update();
}
}
QColor LunarCalendarItem::getHoverLunarColor() const
{
return this->hoverLunarColor;
}
void LunarCalendarItem::setHoverLunarColor(const QColor &hoverLunarColor)
{
if (this->hoverLunarColor != hoverLunarColor) {
this->hoverLunarColor = hoverLunarColor;
this->update();
}
}
QColor LunarCalendarItem::getCurrentBgColor() const
{
return this->currentBgColor;
}
void LunarCalendarItem::setCurrentBgColor(const QColor &currentBgColor)
{
if (this->currentBgColor != currentBgColor) {
this->currentBgColor = currentBgColor;
this->update();
}
}
QColor LunarCalendarItem::getOtherBgColor() const
{
return this->otherBgColor;
}
void LunarCalendarItem::setOtherBgColor(const QColor &otherBgColor)
{
if (this->otherBgColor != otherBgColor) {
this->otherBgColor = otherBgColor;
this->update();
}
}
QColor LunarCalendarItem::getSelectBgColor() const
{
return this->selectBgColor;
}
void LunarCalendarItem::setSelectBgColor(const QColor &selectBgColor)
{
if (this->selectBgColor != selectBgColor) {
this->selectBgColor = selectBgColor;
this->update();
}
}
QColor LunarCalendarItem::getHoverBgColor() const
{
return this->hoverBgColor;
}
void LunarCalendarItem::setHoverBgColor(const QColor &hoverBgColor)
{
if (this->hoverBgColor != hoverBgColor) {
this->hoverBgColor = hoverBgColor;
this->update();
}
}

@ -0,0 +1,213 @@
#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:
//默认尺寸和最小尺寸
QSize sizeHint() const;
QSize minimumSizeHint() const;
//获取和设置是否选中
bool getSelect() const;
void setSelect(bool select);
//获取和设置是否显示农历信息
bool getShowLunar() const;
void setShowLunar(bool showLunar);
//获取和设置背景图片
QString getBgImage() const;
void setBgImage(const QString &bgImage);
//获取和设置选中背景样式
SelectType getSelectType() const;
void setSelectType(const SelectType &selectType);
//获取和设置日期
QDate getDate() const;
void setDate(const QDate &date);
//获取和设置农历
QString getLunar() const;
void setLunar(const QString &lunar);
//获取和设置类型
DayType getDayType() const;
void setDayType(const DayType &dayType);
//设置日期/农历/类型
void setDate(const QDate &date, const QString &lunar, const DayType &dayType);
//获取和设置边框颜色
QColor getBorderColor() const;
void setBorderColor(const QColor &borderColor);
//获取和设置周末颜色
QColor getWeekColor() const;
void setWeekColor(const QColor &weekColor);
//获取和设置角标颜色
QColor getSuperColor() const;
void setSuperColor(const QColor &superColor);
//获取和设置农历节日颜色
QColor getLunarColor() const;
void setLunarColor(const QColor &lunarColor);
//获取和设置当前月文字颜色
QColor getCurrentTextColor() const;
void setCurrentTextColor(const QColor &currentTextColor);
//获取和设置其他月文字颜色
QColor getOtherTextColor() const;
void setOtherTextColor(const QColor &otherTextColor);
//获取和设置选中日期文字颜色
QColor getSelectTextColor() const;
void setSelectTextColor(const QColor &selectTextColor);
//获取和设置悬停日期文字颜色
QColor getHoverTextColor() const;
void setHoverTextColor(const QColor &hoverTextColor);
//获取和设置当前月农历文字颜色
QColor getCurrentLunarColor() const;
void setCurrentLunarColor(const QColor &currentLunarColor);
//获取和设置其他月农历文字颜色
QColor getOtherLunarColor() const;
void setOtherLunarColor(const QColor &otherLunarColor);
//获取和设置选中日期农历文字颜色
QColor getSelectLunarColor() const;
void setSelectLunarColor(const QColor &selectLunarColor);
//获取和设置悬停日期农历文字颜色
QColor getHoverLunarColor() const;
void setHoverLunarColor(const QColor &hoverLunarColor);
//获取和设置当前月背景颜色
QColor getCurrentBgColor() const;
void setCurrentBgColor(const QColor &currentBgColor);
//获取和设置其他月背景颜色
QColor getOtherBgColor() const;
void setOtherBgColor(const QColor &otherBgColor);
//获取和设置选中日期背景颜色
QColor getSelectBgColor() const;
void setSelectBgColor(const QColor &selectBgColor);
//获取和设置悬停日期背景颜色
QColor getHoverBgColor() const;
void setHoverBgColor(const QColor &hoverBgColor);
Q_SIGNALS:
void clicked(const QDate &date, const LunarCalendarItem::DayType &dayType);
};
#endif // LUNARCALENDARITEM_H

@ -0,0 +1,838 @@
#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 *item = new LunarCalendarItem;
connect(item, SIGNAL(clicked(QDate, LunarCalendarItem::DayType)), this, SLOT(clicked(QDate, LunarCalendarItem::DayType)));
layoutBody->addWidget(item, i / 7, i % 7);
items << item;
}
//主布局
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);
items.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);
items.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)) {
items.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_WeekEnd);
} else {
items.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;
}
items.at(i)->setSelect(i == index);
}
//发送日期单击信号
Q_EMIT clicked(date);
//发送日期更新信号
Q_EMIT selectionChanged();
}
void LunarCalendarWidget::dateChanged(int year, int month, int day)
{
//如果原有天大于28则设置为1,防止出错
date.setDate(year, month, day > 28 ? 1 : day);
initDate();
}
QSize LunarCalendarWidget::sizeHint() const
{
return QSize(600, 500);
}
QSize LunarCalendarWidget::minimumSizeHint() const
{
return QSize(200, 150);
}
LunarCalendarWidget::CalendarStyle LunarCalendarWidget::getCalendarStyle() const
{
return this->calendarStyle;
}
void LunarCalendarWidget::setCalendarStyle(const LunarCalendarWidget::CalendarStyle &calendarStyle)
{
if (this->calendarStyle != calendarStyle) {
this->calendarStyle = calendarStyle;
}
}
LunarCalendarWidget::WeekNameFormat LunarCalendarWidget::getWeekNameFormat() const
{
return this->weekNameFormat;
}
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));
}
}
}
QDate LunarCalendarWidget::getDate() const
{
return this->date;
}
void LunarCalendarWidget::setDate(const QDate &date)
{
if (this->date != date) {
this->date = date;
initDate();
}
}
QColor LunarCalendarWidget::getWeekTextColor() const
{
return this->weekTextColor;
}
void LunarCalendarWidget::setWeekTextColor(const QColor &weekTextColor)
{
if (this->weekTextColor != weekTextColor) {
this->weekTextColor = weekTextColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getWeekBgColor() const
{
return this->weekBgColor;
}
void LunarCalendarWidget::setWeekBgColor(const QColor &weekBgColor)
{
if (this->weekBgColor != weekBgColor) {
this->weekBgColor = weekBgColor;
this->initStyle();
}
}
bool LunarCalendarWidget::getShowLunar() const
{
return this->showLunar;
}
void LunarCalendarWidget::setShowLunar(bool showLunar)
{
if (this->showLunar != showLunar) {
this->showLunar = showLunar;
this->initStyle();
}
}
QString LunarCalendarWidget::getBgImage() const
{
return this->bgImage;
}
void LunarCalendarWidget::setBgImage(const QString &bgImage)
{
if (this->bgImage != bgImage) {
this->bgImage = bgImage;
this->initStyle();
}
}
LunarCalendarWidget::SelectType LunarCalendarWidget::getSelectType() const
{
return this->selectType;
}
void LunarCalendarWidget::setSelectType(const LunarCalendarWidget::SelectType &selectType)
{
if (this->selectType != selectType) {
this->selectType = selectType;
this->initStyle();
}
}
QColor LunarCalendarWidget::getBorderColor() const
{
return this->borderColor;
}
void LunarCalendarWidget::setBorderColor(const QColor &borderColor)
{
if (this->borderColor != borderColor) {
this->borderColor = borderColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getWeekColor() const
{
return this->weekColor;
}
void LunarCalendarWidget::setWeekColor(const QColor &weekColor)
{
if (this->weekColor != weekColor) {
this->weekColor = weekColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getSuperColor() const
{
return this->superColor;
}
void LunarCalendarWidget::setSuperColor(const QColor &superColor)
{
if (this->superColor != superColor) {
this->superColor = superColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getLunarColor() const
{
return this->lunarColor;
}
void LunarCalendarWidget::setLunarColor(const QColor &lunarColor)
{
if (this->lunarColor != lunarColor) {
this->lunarColor = lunarColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getCurrentTextColor() const
{
return this->currentTextColor;
}
void LunarCalendarWidget::setCurrentTextColor(const QColor &currentTextColor)
{
if (this->currentTextColor != currentTextColor) {
this->currentTextColor = currentTextColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getOtherTextColor() const
{
return this->otherTextColor;
}
void LunarCalendarWidget::setOtherTextColor(const QColor &otherTextColor)
{
if (this->otherTextColor != otherTextColor) {
this->otherTextColor = otherTextColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getSelectTextColor() const
{
return this->selectTextColor;
}
void LunarCalendarWidget::setSelectTextColor(const QColor &selectTextColor)
{
if (this->selectTextColor != selectTextColor) {
this->selectTextColor = selectTextColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getHoverTextColor() const
{
return this->hoverTextColor;
}
void LunarCalendarWidget::setHoverTextColor(const QColor &hoverTextColor)
{
if (this->hoverTextColor != hoverTextColor) {
this->hoverTextColor = hoverTextColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getCurrentLunarColor() const
{
return this->currentLunarColor;
}
void LunarCalendarWidget::setCurrentLunarColor(const QColor &currentLunarColor)
{
if (this->currentLunarColor != currentLunarColor) {
this->currentLunarColor = currentLunarColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getOtherLunarColor() const
{
return this->otherLunarColor;
}
void LunarCalendarWidget::setOtherLunarColor(const QColor &otherLunarColor)
{
if (this->otherLunarColor != otherLunarColor) {
this->otherLunarColor = otherLunarColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getSelectLunarColor() const
{
return this->selectLunarColor;
}
void LunarCalendarWidget::setSelectLunarColor(const QColor &selectLunarColor)
{
if (this->selectLunarColor != selectLunarColor) {
this->selectLunarColor = selectLunarColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getHoverLunarColor() const
{
return this->hoverLunarColor;
}
void LunarCalendarWidget::setHoverLunarColor(const QColor &hoverLunarColor)
{
if (this->hoverLunarColor != hoverLunarColor) {
this->hoverLunarColor = hoverLunarColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getCurrentBgColor() const
{
return this->currentBgColor;
}
void LunarCalendarWidget::setCurrentBgColor(const QColor &currentBgColor)
{
if (this->currentBgColor != currentBgColor) {
this->currentBgColor = currentBgColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getOtherBgColor() const
{
return this->otherBgColor;
}
void LunarCalendarWidget::setOtherBgColor(const QColor &otherBgColor)
{
if (this->otherBgColor != otherBgColor) {
this->otherBgColor = otherBgColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getSelectBgColor() const
{
return this->selectBgColor;
}
void LunarCalendarWidget::setSelectBgColor(const QColor &selectBgColor)
{
if (this->selectBgColor != selectBgColor) {
this->selectBgColor = selectBgColor;
this->initStyle();
}
}
QColor LunarCalendarWidget::getHoverBgColor() const
{
return this->hoverBgColor;
}
void LunarCalendarWidget::setHoverBgColor(const QColor &hoverBgColor)
{
if (this->hoverBgColor != hoverBgColor) {
this->hoverBgColor = hoverBgColor;
this->initStyle();
}
}
//显示上一年
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);
}

@ -0,0 +1,261 @@
#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 *> items;//日期元素
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:
//默认尺寸和最小尺寸
QSize sizeHint() const;
QSize minimumSizeHint() const;
//获取和设置整体样式
CalendarStyle getCalendarStyle() const;
void setCalendarStyle(const CalendarStyle &calendarStyle);
//获取和设置星期名称格式
WeekNameFormat getWeekNameFormat() const;
void setWeekNameFormat(const WeekNameFormat &weekNameFormat);
//获取和设置日期
QDate getDate() const;
void setDate(const QDate &date);
//获取和设置顶部星期名称文字颜色
QColor getWeekTextColor() const;
void setWeekTextColor(const QColor &weekTextColor);
//获取和设置顶部星期名称文字背景色
QColor getWeekBgColor() const;
void setWeekBgColor(const QColor &weekBgColor);
//获取和设置是否显示农历信息
bool getShowLunar() const;
void setShowLunar(bool showLunar);
//获取和设置背景图片
QString getBgImage() const;
void setBgImage(const QString &bgImage);
//获取和设置选中背景样式
SelectType getSelectType() const;
void setSelectType(const SelectType &selectType);
//获取和设置边框颜色
QColor getBorderColor() const;
void setBorderColor(const QColor &borderColor);
//获取和设置周末颜色
QColor getWeekColor() const;
void setWeekColor(const QColor &weekColor);
//获取和设置角标颜色
QColor getSuperColor() const;
void setSuperColor(const QColor &superColor);
//获取和设置农历节日颜色
QColor getLunarColor() const;
void setLunarColor(const QColor &lunarColor);
//获取和设置当前月文字颜色
QColor getCurrentTextColor() const;
void setCurrentTextColor(const QColor &currentTextColor);
//获取和设置其他月文字颜色
QColor getOtherTextColor() const;
void setOtherTextColor(const QColor &otherTextColor);
//获取和设置选中日期文字颜色
QColor getSelectTextColor() const;
void setSelectTextColor(const QColor &selectTextColor);
//获取和设置悬停日期文字颜色
QColor getHoverTextColor() const;
void setHoverTextColor(const QColor &hoverTextColor);
//获取和设置当前月农历文字颜色
QColor getCurrentLunarColor() const;
void setCurrentLunarColor(const QColor &currentLunarColor);
//获取和设置其他月农历文字颜色
QColor getOtherLunarColor() const;
void setOtherLunarColor(const QColor &otherLunarColor);
//获取和设置选中日期农历文字颜色
QColor getSelectLunarColor() const;
void setSelectLunarColor(const QColor &selectLunarColor);
//获取和设置悬停日期农历文字颜色
QColor getHoverLunarColor() const;
void setHoverLunarColor(const QColor &hoverLunarColor);
//获取和设置当前月背景颜色
QColor getCurrentBgColor() const;
void setCurrentBgColor(const QColor &currentBgColor);
//获取和设置其他月背景颜色
QColor getOtherBgColor() const;
void setOtherBgColor(const QColor &otherBgColor);
//获取和设置选中日期背景颜色
QColor getSelectBgColor() const;
void setSelectBgColor(const QColor &selectBgColor);
//获取和设置悬停日期背景颜色
QColor getHoverBgColor() const;
void setHoverBgColor(const QColor &hoverBgColor);
public Q_SLOTS:
//转到上一年
void showPreviousYear();
//转到下一年
void showNextYear();
//转到上一月
void showPreviousMonth();
//转到下一月
void showNextMonth();
//转到今天
void showToday();
Q_SIGNALS:
void clicked(const QDate &date);
void selectionChanged();
};
#endif // LUNARCALENDARWIDGET_H

@ -0,0 +1,24 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = lunarcalendarwidget
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += 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

@ -0,0 +1,34 @@
#pragma execution_character_set("utf-8")
#include "frmlunarcalendarwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
#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("农历控件 (QQ: 517216493 WX: feiyangqingyun)");
w.show();
return a.exec();
}

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

@ -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();
}

@ -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

@ -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>

@ -0,0 +1,34 @@
#pragma execution_character_set("utf-8")
#include "frmmaskwidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
#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("遮罩层窗体 (QQ: 517216493 WX: feiyangqingyun)");
w.show();
return a.exec();
}

@ -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) {
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) {
if (obj->objectName() == mainWidget->objectName()) {
if (this->isVisible()) {
this->activateWindow();
}
}
}
}
return QObject::eventFilter(obj, event);
}

@ -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

@ -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

@ -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);
}

@ -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

@ -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>

@ -0,0 +1,34 @@
#pragma execution_character_set("utf-8")
#include "frmmovewidget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont font;
font.setFamily("Microsoft Yahei");
font.setPixelSize(13);
a.setFont(font);
#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("通用移动类 (QQ: 517216493 WX: feiyangqingyun)");
w.show();
return a.exec();
}

@ -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 && 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) {
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);
}
}

@ -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

@ -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

@ -0,0 +1,19 @@
#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;
exit(0);
}
void frmScreenWidget::on_pushButton_clicked()
{
ScreenWidget::Instance()->showFullScreen();
}

@ -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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save