彻底改版2.0
BIN
widget/0snap/colorwidget.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
widget/0snap/framelesswidget.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
widget/0snap/gifwidget.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
widget/0snap/lunarcalendarwidget.jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
widget/0snap/maskwidget.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
widget/0snap/movewidget.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
widget/0snap/screenwidget.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
174
widget/colorwidget/colorwidget.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "colorwidget.h"
|
||||
#include "qmutex.h"
|
||||
#include "qgridlayout.h"
|
||||
#include "qlabel.h"
|
||||
#include "qlineedit.h"
|
||||
#include "qapplication.h"
|
||||
#include "qtimer.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
#include "qscreen.h"
|
||||
#define deskGeometry qApp->primaryScreen()->geometry()
|
||||
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
|
||||
#else
|
||||
#include "qdesktopwidget.h"
|
||||
#define deskGeometry qApp->desktop()->geometry()
|
||||
#define deskGeometry2 qApp->desktop()->availableGeometry()
|
||||
#endif
|
||||
|
||||
ColorWidget *ColorWidget::instance = 0;
|
||||
ColorWidget *ColorWidget::Instance()
|
||||
{
|
||||
if (!instance) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
if (!instance) {
|
||||
instance = new ColorWidget;
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
ColorWidget::ColorWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
gridLayout = new QGridLayout(this);
|
||||
gridLayout->setSpacing(6);
|
||||
gridLayout->setContentsMargins(11, 11, 11, 11);
|
||||
|
||||
verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->setSpacing(0);
|
||||
|
||||
labColor = new QLabel(this);
|
||||
labColor->setText("+");
|
||||
labColor->setStyleSheet("background-color: rgb(255, 107, 107);color: rgb(250, 250, 250);");
|
||||
labColor->setAlignment(Qt::AlignCenter);
|
||||
QFont font;
|
||||
font.setPixelSize(35);
|
||||
font.setBold(true);
|
||||
labColor->setFont(font);
|
||||
|
||||
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(labColor->sizePolicy().hasHeightForWidth());
|
||||
labColor->setSizePolicy(sizePolicy);
|
||||
labColor->setMinimumSize(QSize(80, 70));
|
||||
labColor->setMaximumSize(QSize(80, 70));
|
||||
labColor->setCursor(QCursor(Qt::CrossCursor));
|
||||
labColor->setFrameShape(QFrame::StyledPanel);
|
||||
labColor->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
verticalLayout->addWidget(labColor);
|
||||
|
||||
label = new QLabel(this);
|
||||
label->setMinimumSize(QSize(0, 18));
|
||||
label->setStyleSheet("background-color: rgb(0, 0, 0);color: rgb(200, 200, 200);");
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
|
||||
verticalLayout->addWidget(label);
|
||||
gridLayout->addLayout(verticalLayout, 0, 0, 3, 1);
|
||||
|
||||
labWeb = new QLabel(this);
|
||||
gridLayout->addWidget(labWeb, 0, 1, 1, 1);
|
||||
|
||||
txtWeb = new QLineEdit(this);
|
||||
gridLayout->addWidget(txtWeb, 0, 2, 1, 1);
|
||||
|
||||
labRgb = new QLabel(this);
|
||||
gridLayout->addWidget(labRgb, 1, 1, 1, 1);
|
||||
|
||||
txtRgb = new QLineEdit(this);
|
||||
gridLayout->addWidget(txtRgb, 1, 2, 1, 1);
|
||||
|
||||
labPoint = new QLabel(this);
|
||||
gridLayout->addWidget(labPoint, 2, 1, 1, 1);
|
||||
|
||||
txtPoint = new QLineEdit(this);
|
||||
gridLayout->addWidget(txtPoint, 2, 2, 1, 1);
|
||||
|
||||
label->setText("当前颜色");
|
||||
labWeb->setText("web值:");
|
||||
labRgb->setText("rgb值:");
|
||||
labPoint->setText("坐标值:");
|
||||
|
||||
this->setLayout(gridLayout);
|
||||
this->setWindowTitle("屏幕拾色器");
|
||||
this->setFixedSize(300, 108);
|
||||
|
||||
cp = QApplication::clipboard();
|
||||
pressed = false;
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(100);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(showColorValue()));
|
||||
timer->start();
|
||||
}
|
||||
|
||||
ColorWidget::~ColorWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void ColorWidget::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
if (labColor->rect().contains(e->pos())) {
|
||||
pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ColorWidget::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
void ColorWidget::showColorValue()
|
||||
{
|
||||
if (!pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = QCursor::pos().x();
|
||||
int y = QCursor::pos().y();
|
||||
txtPoint->setText(tr("x:%1 y:%2").arg(x).arg(y));
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
QScreen *screen = qApp->primaryScreen();
|
||||
QPixmap pixmap = screen->grabWindow(0, x, y, 2, 2);
|
||||
#else
|
||||
QPixmap pixmap = QPixmap::grabWindow(qApp->desktop()->winId(), x, y, 2, 2);
|
||||
#endif
|
||||
|
||||
int red, green, blue;
|
||||
QString strDecimalValue, strHex;
|
||||
if (pixmap.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QImage image = pixmap.toImage();
|
||||
if (image.valid(0, 0)) {
|
||||
QColor color = image.pixel(0, 0);
|
||||
red = color.red();
|
||||
green = color.green();
|
||||
blue = color.blue();
|
||||
QString strRed = tr("%1").arg(red & 0xFF, 2, 16, QChar('0'));
|
||||
QString strGreen = tr("%1").arg(green & 0xFF, 2, 16, QChar('0'));
|
||||
QString strBlue = tr("%1").arg(blue & 0xFF, 2, 16, QChar('0'));
|
||||
|
||||
strDecimalValue = tr("%1, %2, %3").arg(red).arg(green).arg(blue);
|
||||
strHex = tr("#%1%2%3").arg(strRed.toUpper()).arg(strGreen.toUpper()).arg(strBlue.toUpper());
|
||||
}
|
||||
|
||||
//根据背景色自动计算合适的前景色
|
||||
QColor color(red, green, blue);
|
||||
double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
|
||||
QColor textColor = gray > 0.5 ? Qt::black : Qt::white;
|
||||
|
||||
QString str = tr("background:rgb(%1);color:%2").arg(strDecimalValue).arg(textColor.name());
|
||||
labColor->setStyleSheet(str);
|
||||
txtRgb->setText(strDecimalValue);
|
||||
txtWeb->setText(strHex);
|
||||
}
|
||||
58
widget/colorwidget/colorwidget.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef COLORWIDGET_H
|
||||
#define COLORWIDGET_H
|
||||
|
||||
/**
|
||||
* 屏幕拾色器 作者:feiyangqingyun(QQ:517216493) 2016-11-11
|
||||
* 1. 鼠标按下实时采集鼠标处的颜色。
|
||||
* 2. 实时显示颜色值。
|
||||
* 3. 支持16进制格式和rgb格式。
|
||||
* 4. 实时显示预览颜色。
|
||||
* 5. 根据背景色自动计算合适的前景色。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QGridLayout;
|
||||
class QVBoxLayout;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT ColorWidget : public QWidget
|
||||
#else
|
||||
class ColorWidget : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ColorWidget *Instance();
|
||||
explicit ColorWidget(QWidget *parent = 0);
|
||||
~ColorWidget();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
void mouseReleaseEvent(QMouseEvent *);
|
||||
|
||||
private:
|
||||
static ColorWidget *instance;
|
||||
QClipboard *cp;
|
||||
bool pressed;
|
||||
QTimer *timer;
|
||||
|
||||
QGridLayout *gridLayout;
|
||||
QVBoxLayout *verticalLayout;
|
||||
QLabel *labColor;
|
||||
QLabel *label;
|
||||
QLabel *labWeb;
|
||||
QLineEdit *txtWeb;
|
||||
QLabel *labRgb;
|
||||
QLineEdit *txtRgb;
|
||||
QLabel *labPoint;
|
||||
QLineEdit *txtPoint;
|
||||
|
||||
private Q_SLOTS:
|
||||
void showColorValue();
|
||||
};
|
||||
|
||||
#endif // COLORWIDGET_H
|
||||
17
widget/colorwidget/colorwidget.pro
Normal file
@@ -0,0 +1,17 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = colorwidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmcolorwidget.cpp
|
||||
SOURCES += colorwidget.cpp
|
||||
|
||||
HEADERS += colorwidget.h
|
||||
HEADERS += frmcolorwidget.h
|
||||
|
||||
FORMS += frmcolorwidget.ui
|
||||
18
widget/colorwidget/frmcolorwidget.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "frmcolorwidget.h"
|
||||
#include "ui_frmcolorwidget.h"
|
||||
#include "colorwidget.h"
|
||||
|
||||
frmColorWidget::frmColorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmColorWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
frmColorWidget::~frmColorWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmColorWidget::on_pushButton_clicked()
|
||||
{
|
||||
ColorWidget::Instance()->show();
|
||||
}
|
||||
25
widget/colorwidget/frmcolorwidget.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FRMCOLORWIDGET_H
|
||||
#define FRMCOLORWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmColorWidget;
|
||||
}
|
||||
|
||||
class frmColorWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmColorWidget(QWidget *parent = 0);
|
||||
~frmColorWidget();
|
||||
|
||||
private slots:
|
||||
void on_pushButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::frmColorWidget *ui;
|
||||
};
|
||||
|
||||
#endif // FRMCOLORWIDGET_H
|
||||
32
widget/colorwidget/frmcolorwidget.ui
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmColorWidget</class>
|
||||
<widget class="QWidget" name="frmColorWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>92</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>弹出</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
widget/colorwidget/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmcolorwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmColorWidget w;
|
||||
w.setWindowTitle("屏幕拾色器");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
9
widget/framelesswidget/framelesscore/framelesscore.pri
Normal file
@@ -0,0 +1,9 @@
|
||||
HEADERS += \
|
||||
$$PWD/framelessdialog.h \
|
||||
$$PWD/framelessmainwindow.h \
|
||||
$$PWD/framelesswidget.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/framelessdialog.cpp \
|
||||
$$PWD/framelessmainwindow.cpp \
|
||||
$$PWD/framelesswidget.cpp
|
||||
373
widget/framelesswidget/framelesscore/framelessdialog.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
#include "framelessdialog.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "windows.h"
|
||||
#include "windowsx.h"
|
||||
#pragma comment (lib,"user32.lib")
|
||||
#endif
|
||||
|
||||
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||
|
||||
FramelessDialog::FramelessDialog(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
padding = 8;
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
|
||||
mousePressed = false;
|
||||
mousePoint = QPoint(0, 0);
|
||||
mouseRect = QRect(0, 0, 0, 0);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea << false;
|
||||
pressedRect << QRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
isMin = false;
|
||||
flags = this->windowFlags();
|
||||
titleBar = 0;
|
||||
|
||||
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
|
||||
this->setAttribute(Qt::WA_TranslucentBackground);
|
||||
#endif
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
//安装事件过滤器识别拖动
|
||||
this->installEventFilter(this);
|
||||
|
||||
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
|
||||
//设置以后会产生标题栏需要在下面拦截消息重新去掉
|
||||
#ifdef Q_OS_WIN
|
||||
HWND hwnd = (HWND)this->winId();
|
||||
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
//解决有时候窗体重新显示的时候假死不刷新的BUG
|
||||
setAttribute(Qt::WA_Mapped);
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void FramelessDialog::doWindowStateChange(QEvent *event)
|
||||
{
|
||||
//非最大化才能移动和拖动大小
|
||||
if (windowState() == Qt::WindowNoState) {
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
} else {
|
||||
moveEnable = false;
|
||||
resizeEnable = false;
|
||||
}
|
||||
|
||||
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
|
||||
emit windowStateChange(!moveEnable);
|
||||
|
||||
//解决mac系统上无边框最小化失效的BUG
|
||||
#ifdef Q_OS_MACOS
|
||||
if (windowState() & Qt::WindowMinimized) {
|
||||
isMin = true;
|
||||
} else {
|
||||
if (isMin) {
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
this->setVisible(true);
|
||||
isMin = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessDialog::doResizeEvent(QEvent *event)
|
||||
{
|
||||
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
|
||||
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::Resize) {
|
||||
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
|
||||
//左侧描点区域
|
||||
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
|
||||
//右侧描点区域
|
||||
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
|
||||
//上侧描点区域
|
||||
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
|
||||
//下侧描点区域
|
||||
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
|
||||
|
||||
//左上角描点区域
|
||||
pressedRect[4] = QRect(0, 0, padding, padding);
|
||||
//右上角描点区域
|
||||
pressedRect[5] = QRect(width - padding, 0, padding, padding);
|
||||
//左下角描点区域
|
||||
pressedRect[6] = QRect(0, height - padding, padding, padding);
|
||||
//右下角描点区域
|
||||
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
|
||||
} else if (event->type() == QEvent::HoverMove) {
|
||||
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
|
||||
QHoverEvent *hoverEvent = (QHoverEvent *)event;
|
||||
QPoint point = hoverEvent->pos();
|
||||
if (resizeEnable) {
|
||||
if (pressedRect.at(0).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(1).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(2).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(3).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(4).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (pressedRect.at(5).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(6).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(7).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
//根据当前鼠标位置,计算XY轴移动了多少
|
||||
int offsetX = point.x() - mousePoint.x();
|
||||
int offsetY = point.y() - mousePoint.y();
|
||||
|
||||
//根据按下处的位置判断是否是移动控件还是拉伸控件
|
||||
if (moveEnable && mousePressed) {
|
||||
this->move(this->x() + offsetX, this->y() + offsetY);
|
||||
}
|
||||
|
||||
if (resizeEnable) {
|
||||
int rectX = mouseRect.x();
|
||||
int rectY = mouseRect.y();
|
||||
int rectW = mouseRect.width();
|
||||
int rectH = mouseRect.height();
|
||||
|
||||
if (pressedArea.at(0)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
|
||||
}
|
||||
} else if (pressedArea.at(1)) {
|
||||
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
|
||||
} else if (pressedArea.at(2)) {
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(3)) {
|
||||
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
|
||||
} else if (pressedArea.at(4)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(5)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(6)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(7)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
//记住鼠标按下的坐标+窗体区域
|
||||
QMouseEvent *mouseEvent = (QMouseEvent *)event;
|
||||
mousePoint = mouseEvent->pos();
|
||||
mouseRect = this->geometry();
|
||||
|
||||
//判断按下的手柄的区域位置
|
||||
if (pressedRect.at(0).contains(mousePoint)) {
|
||||
pressedArea[0] = true;
|
||||
} else if (pressedRect.at(1).contains(mousePoint)) {
|
||||
pressedArea[1] = true;
|
||||
} else if (pressedRect.at(2).contains(mousePoint)) {
|
||||
pressedArea[2] = true;
|
||||
} else if (pressedRect.at(3).contains(mousePoint)) {
|
||||
pressedArea[3] = true;
|
||||
} else if (pressedRect.at(4).contains(mousePoint)) {
|
||||
pressedArea[4] = true;
|
||||
} else if (pressedRect.at(5).contains(mousePoint)) {
|
||||
pressedArea[5] = true;
|
||||
} else if (pressedRect.at(6).contains(mousePoint)) {
|
||||
pressedArea[6] = true;
|
||||
} else if (pressedRect.at(7).contains(mousePoint)) {
|
||||
pressedArea[7] = true;
|
||||
} else {
|
||||
mousePressed = true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
//改成用HoverMove识别
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
//恢复所有
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
mousePressed = false;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea[i] = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessDialog::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == this) {
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
doWindowStateChange(event);
|
||||
} else {
|
||||
doResizeEvent(event);
|
||||
}
|
||||
} else if (watched == titleBar) {
|
||||
//双击标题栏发出双击信号给主界面
|
||||
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return QDialog::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||
#else
|
||||
bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
#endif
|
||||
{
|
||||
if (eventType == "windows_generic_MSG") {
|
||||
#ifdef Q_OS_WIN
|
||||
MSG *msg = static_cast<MSG *>(message);
|
||||
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
|
||||
|
||||
//不同的消息类型和参数进行不同的处理
|
||||
if (msg->message == WM_NCCALCSIZE) {
|
||||
*result = 0;
|
||||
return true;
|
||||
} else if (msg->message == WM_NCHITTEST) {
|
||||
//计算鼠标对应的屏幕坐标
|
||||
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
|
||||
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
|
||||
long x = GET_X_LPARAM(msg->lParam);
|
||||
long y = GET_Y_LPARAM(msg->lParam);
|
||||
QPoint pos = mapFromGlobal(QPoint(x, y));
|
||||
|
||||
//判断当前鼠标位置在哪个区域
|
||||
bool left = pos.x() < padding;
|
||||
bool right = pos.x() > width() - padding;
|
||||
bool top = pos.y() < padding;
|
||||
bool bottom = pos.y() > height() - padding;
|
||||
|
||||
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
|
||||
*result = 0;
|
||||
if (resizeEnable) {
|
||||
if (left && top) {
|
||||
*result = HTTOPLEFT;
|
||||
} else if (left && bottom) {
|
||||
*result = HTBOTTOMLEFT;
|
||||
} else if (right && top) {
|
||||
*result = HTTOPRIGHT;
|
||||
} else if (right && bottom) {
|
||||
*result = HTBOTTOMRIGHT;
|
||||
} else if (left) {
|
||||
*result = HTLEFT;
|
||||
} else if (right) {
|
||||
*result = HTRIGHT;
|
||||
} else if (top) {
|
||||
*result = HTTOP;
|
||||
} else if (bottom) {
|
||||
*result = HTBOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
//先处理掉拉伸
|
||||
if (0 != *result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//识别标题栏拖动产生半屏全屏效果
|
||||
if (titleBar != 0 && titleBar->rect().contains(pos)) {
|
||||
QWidget *child = titleBar->childAt(pos);
|
||||
if (!child) {
|
||||
*result = HTCAPTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
|
||||
//系统休眠的时候自动最小化可以规避程序可能出现的问题
|
||||
this->showMinimized();
|
||||
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
|
||||
//休眠唤醒后自动打开
|
||||
this->showNormal();
|
||||
}
|
||||
#endif
|
||||
} else if (eventType == "NSEvent") {
|
||||
#ifdef Q_OS_MACOS
|
||||
#endif
|
||||
} else if (eventType == "xcb_generic_event_t") {
|
||||
#ifdef Q_OS_LINUX
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool FramelessDialog::winEvent(MSG *message, long *result)
|
||||
{
|
||||
return nativeEvent("windows_generic_MSG", message, result);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void FramelessDialog::setPadding(int padding)
|
||||
{
|
||||
this->padding = padding;
|
||||
}
|
||||
|
||||
void FramelessDialog::setMoveEnable(bool moveEnable)
|
||||
{
|
||||
this->moveEnable = moveEnable;
|
||||
}
|
||||
|
||||
void FramelessDialog::setResizeEnable(bool resizeEnable)
|
||||
{
|
||||
this->resizeEnable = resizeEnable;
|
||||
}
|
||||
|
||||
void FramelessDialog::setTitleBar(QWidget *titleBar)
|
||||
{
|
||||
this->titleBar = titleBar;
|
||||
this->titleBar->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
96
widget/framelesswidget/framelesscore/framelessdialog.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef FRAMELESSDIALOG_H
|
||||
#define FRAMELESSDIALOG_H
|
||||
|
||||
/**
|
||||
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
|
||||
* 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。
|
||||
* 2. 同时支持mingw、msvc、gcc等。
|
||||
* 3. 同时支持windows、linux、mac。
|
||||
* 4. 同时支持QMainWindow、QWidget、QDialog。
|
||||
* 5. 使用方法极其简单,只需要将继承类修改即可。
|
||||
* 6. 自动识别双击标题栏响应。
|
||||
* 7. 无边框拉伸在windows下不抖动。
|
||||
* 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。
|
||||
* 9. 解决mac系统上无边框最小化最大化失效的BUG。
|
||||
* 10. 解决系统休眠后再次启动程序懵逼的BUG。
|
||||
* 11. 解决有时候窗体重新显示的时候假死不刷新的BUG。
|
||||
* 12. 轻量级,1个代码文件,核心代码行数不到300行。
|
||||
* 13. 注释详细,示例完美,非常适合阅读和学习。
|
||||
* 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。
|
||||
*/
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT FramelessDialog : public QDialog
|
||||
#else
|
||||
class FramelessDialog : public QDialog
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FramelessDialog(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
//窗体显示的时候触发
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
//事件过滤器识别拖动拉伸等
|
||||
void doWindowStateChange(QEvent *event);
|
||||
void doResizeEvent(QEvent *event);
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
|
||||
#else
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||
#endif
|
||||
|
||||
//Qt4的写法
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool winEvent(MSG *message, long *result);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
//边距+可移动+可拉伸
|
||||
int padding;
|
||||
bool moveEnable;
|
||||
bool resizeEnable;
|
||||
|
||||
//标题栏控件
|
||||
QWidget *titleBar;
|
||||
|
||||
//鼠标是否按下+按下坐标+按下时窗体区域
|
||||
bool mousePressed;
|
||||
QPoint mousePoint;
|
||||
QRect mouseRect;
|
||||
|
||||
//鼠标是否按下某个区域+按下区域的大小
|
||||
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
|
||||
QList<bool> pressedArea;
|
||||
QList<QRect> pressedRect;
|
||||
|
||||
//记录是否最小化
|
||||
bool isMin;
|
||||
//存储窗体默认的属性
|
||||
Qt::WindowFlags flags;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置边距+可拖动+可拉伸
|
||||
void setPadding(int padding);
|
||||
void setMoveEnable(bool moveEnable);
|
||||
void setResizeEnable(bool resizeEnable);
|
||||
|
||||
//设置标题栏控件
|
||||
void setTitleBar(QWidget *titleBar);
|
||||
|
||||
Q_SIGNALS:
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
};
|
||||
|
||||
#endif // FRAMELESSDIALOG_H
|
||||
371
widget/framelesswidget/framelesscore/framelessmainwindow.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
#include "framelessmainwindow.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "windows.h"
|
||||
#include "windowsx.h"
|
||||
#pragma comment (lib,"user32.lib")
|
||||
#endif
|
||||
|
||||
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
{
|
||||
padding = 8;
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
|
||||
mousePressed = false;
|
||||
mousePoint = QPoint(0, 0);
|
||||
mouseRect = QRect(0, 0, 0, 0);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea << false;
|
||||
pressedRect << QRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
isMin = false;
|
||||
flags = this->windowFlags();
|
||||
titleBar = 0;
|
||||
|
||||
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
|
||||
this->setAttribute(Qt::WA_TranslucentBackground);
|
||||
#endif
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
//安装事件过滤器识别拖动
|
||||
this->installEventFilter(this);
|
||||
|
||||
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
|
||||
//设置以后会产生标题栏,需要在下面拦截消息WM_NCCALCSIZE重新去掉
|
||||
#ifdef Q_OS_WIN
|
||||
HWND hwnd = (HWND)this->winId();
|
||||
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessMainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
//解决有时候窗体重新显示的时候假死不刷新的BUG
|
||||
setAttribute(Qt::WA_Mapped);
|
||||
QMainWindow::showEvent(event);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::doWindowStateChange(QEvent *event)
|
||||
{
|
||||
//非最大化才能移动和拖动大小
|
||||
if (windowState() == Qt::WindowNoState) {
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
} else {
|
||||
moveEnable = false;
|
||||
resizeEnable = false;
|
||||
}
|
||||
|
||||
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
|
||||
emit windowStateChange(!moveEnable);
|
||||
|
||||
//解决mac系统上无边框最小化失效的BUG
|
||||
#ifdef Q_OS_MACOS
|
||||
if (windowState() & Qt::WindowMinimized) {
|
||||
isMin = true;
|
||||
} else {
|
||||
if (isMin) {
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
this->setVisible(true);
|
||||
isMin = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessMainWindow::doResizeEvent(QEvent *event)
|
||||
{
|
||||
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
|
||||
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::Resize) {
|
||||
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
|
||||
//左侧描点区域
|
||||
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
|
||||
//右侧描点区域
|
||||
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
|
||||
//上侧描点区域
|
||||
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
|
||||
//下侧描点区域
|
||||
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
|
||||
|
||||
//左上角描点区域
|
||||
pressedRect[4] = QRect(0, 0, padding, padding);
|
||||
//右上角描点区域
|
||||
pressedRect[5] = QRect(width - padding, 0, padding, padding);
|
||||
//左下角描点区域
|
||||
pressedRect[6] = QRect(0, height - padding, padding, padding);
|
||||
//右下角描点区域
|
||||
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
|
||||
} else if (event->type() == QEvent::HoverMove) {
|
||||
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
|
||||
QHoverEvent *hoverEvent = (QHoverEvent *)event;
|
||||
QPoint point = hoverEvent->pos();
|
||||
if (resizeEnable) {
|
||||
if (pressedRect.at(0).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(1).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(2).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(3).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(4).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (pressedRect.at(5).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(6).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(7).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
//根据当前鼠标位置,计算XY轴移动了多少
|
||||
int offsetX = point.x() - mousePoint.x();
|
||||
int offsetY = point.y() - mousePoint.y();
|
||||
|
||||
//根据按下处的位置判断是否是移动控件还是拉伸控件
|
||||
if (moveEnable && mousePressed) {
|
||||
this->move(this->x() + offsetX, this->y() + offsetY);
|
||||
}
|
||||
|
||||
if (resizeEnable) {
|
||||
int rectX = mouseRect.x();
|
||||
int rectY = mouseRect.y();
|
||||
int rectW = mouseRect.width();
|
||||
int rectH = mouseRect.height();
|
||||
|
||||
if (pressedArea.at(0)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
|
||||
}
|
||||
} else if (pressedArea.at(1)) {
|
||||
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
|
||||
} else if (pressedArea.at(2)) {
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(3)) {
|
||||
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
|
||||
} else if (pressedArea.at(4)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(5)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(6)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(7)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
//记住鼠标按下的坐标+窗体区域
|
||||
QMouseEvent *mouseEvent = (QMouseEvent *)event;
|
||||
mousePoint = mouseEvent->pos();
|
||||
mouseRect = this->geometry();
|
||||
|
||||
//判断按下的手柄的区域位置
|
||||
if (pressedRect.at(0).contains(mousePoint)) {
|
||||
pressedArea[0] = true;
|
||||
} else if (pressedRect.at(1).contains(mousePoint)) {
|
||||
pressedArea[1] = true;
|
||||
} else if (pressedRect.at(2).contains(mousePoint)) {
|
||||
pressedArea[2] = true;
|
||||
} else if (pressedRect.at(3).contains(mousePoint)) {
|
||||
pressedArea[3] = true;
|
||||
} else if (pressedRect.at(4).contains(mousePoint)) {
|
||||
pressedArea[4] = true;
|
||||
} else if (pressedRect.at(5).contains(mousePoint)) {
|
||||
pressedArea[5] = true;
|
||||
} else if (pressedRect.at(6).contains(mousePoint)) {
|
||||
pressedArea[6] = true;
|
||||
} else if (pressedRect.at(7).contains(mousePoint)) {
|
||||
pressedArea[7] = true;
|
||||
} else {
|
||||
mousePressed = true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
//改成用HoverMove识别
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
//恢复所有
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
mousePressed = false;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea[i] = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessMainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == this) {
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
doWindowStateChange(event);
|
||||
} else {
|
||||
doResizeEvent(event);
|
||||
}
|
||||
} else if (watched == titleBar) {
|
||||
//双击标题栏发出双击信号给主界面
|
||||
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return QMainWindow::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||
#else
|
||||
bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
#endif
|
||||
{
|
||||
if (eventType == "windows_generic_MSG") {
|
||||
#ifdef Q_OS_WIN
|
||||
MSG *msg = static_cast<MSG *>(message);
|
||||
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
|
||||
|
||||
//不同的消息类型和参数进行不同的处理
|
||||
if (msg->message == WM_NCCALCSIZE) {
|
||||
*result = 0;
|
||||
return true;
|
||||
} else if (msg->message == WM_NCHITTEST) {
|
||||
//计算鼠标对应的屏幕坐标
|
||||
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
|
||||
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
|
||||
long x = GET_X_LPARAM(msg->lParam);
|
||||
long y = GET_Y_LPARAM(msg->lParam);
|
||||
QPoint pos = mapFromGlobal(QPoint(x, y));
|
||||
|
||||
//判断当前鼠标位置在哪个区域
|
||||
bool left = pos.x() < padding;
|
||||
bool right = pos.x() > width() - padding;
|
||||
bool top = pos.y() < padding;
|
||||
bool bottom = pos.y() > height() - padding;
|
||||
|
||||
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
|
||||
*result = 0;
|
||||
if (resizeEnable) {
|
||||
if (left && top) {
|
||||
*result = HTTOPLEFT;
|
||||
} else if (left && bottom) {
|
||||
*result = HTBOTTOMLEFT;
|
||||
} else if (right && top) {
|
||||
*result = HTTOPRIGHT;
|
||||
} else if (right && bottom) {
|
||||
*result = HTBOTTOMRIGHT;
|
||||
} else if (left) {
|
||||
*result = HTLEFT;
|
||||
} else if (right) {
|
||||
*result = HTRIGHT;
|
||||
} else if (top) {
|
||||
*result = HTTOP;
|
||||
} else if (bottom) {
|
||||
*result = HTBOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
//先处理掉拉伸
|
||||
if (0 != *result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//识别标题栏拖动产生半屏全屏效果
|
||||
if (titleBar != 0 && titleBar->rect().contains(pos)) {
|
||||
QWidget *child = titleBar->childAt(pos);
|
||||
if (!child) {
|
||||
*result = HTCAPTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
|
||||
//系统休眠的时候自动最小化可以规避程序可能出现的问题
|
||||
this->showMinimized();
|
||||
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
|
||||
//休眠唤醒后自动打开
|
||||
this->showNormal();
|
||||
}
|
||||
#endif
|
||||
} else if (eventType == "NSEvent") {
|
||||
#ifdef Q_OS_MACOS
|
||||
#endif
|
||||
} else if (eventType == "xcb_generic_event_t") {
|
||||
#ifdef Q_OS_LINUX
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool FramelessMainWindow::winEvent(MSG *message, long *result)
|
||||
{
|
||||
return nativeEvent("windows_generic_MSG", message, result);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void FramelessMainWindow::setPadding(int padding)
|
||||
{
|
||||
this->padding = padding;
|
||||
}
|
||||
|
||||
void FramelessMainWindow::setMoveEnable(bool moveEnable)
|
||||
{
|
||||
this->moveEnable = moveEnable;
|
||||
}
|
||||
|
||||
void FramelessMainWindow::setResizeEnable(bool resizeEnable)
|
||||
{
|
||||
this->resizeEnable = resizeEnable;
|
||||
}
|
||||
|
||||
void FramelessMainWindow::setTitleBar(QWidget *titleBar)
|
||||
{
|
||||
this->titleBar = titleBar;
|
||||
this->titleBar->installEventFilter(this);
|
||||
}
|
||||
96
widget/framelesswidget/framelesscore/framelessmainwindow.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef FRAMELESSMAINWINDOW_H
|
||||
#define FRAMELESSMAINWINDOW_H
|
||||
|
||||
/**
|
||||
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
|
||||
* 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。
|
||||
* 2. 同时支持mingw、msvc、gcc等。
|
||||
* 3. 同时支持windows、linux、mac。
|
||||
* 4. 同时支持QMainWindow、QWidget、QDialog。
|
||||
* 5. 使用方法极其简单,只需要将继承类修改即可。
|
||||
* 6. 自动识别双击标题栏响应。
|
||||
* 7. 无边框拉伸在windows下不抖动。
|
||||
* 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。
|
||||
* 9. 解决mac系统上无边框最小化最大化失效的BUG。
|
||||
* 10. 解决系统休眠后再次启动程序懵逼的BUG。
|
||||
* 11. 解决有时候窗体重新显示的时候假死不刷新的BUG。
|
||||
* 12. 轻量级,1个代码文件,核心代码行数不到300行。
|
||||
* 13. 注释详细,示例完美,非常适合阅读和学习。
|
||||
* 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。
|
||||
*/
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT FramelessMainWindow : public QMainWindow
|
||||
#else
|
||||
class FramelessMainWindow : public QMainWindow
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FramelessMainWindow(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
//窗体显示的时候触发
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
//事件过滤器识别拖动拉伸等
|
||||
void doWindowStateChange(QEvent *event);
|
||||
void doResizeEvent(QEvent *event);
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
|
||||
#else
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||
#endif
|
||||
|
||||
//Qt4的写法
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool winEvent(MSG *message, long *result);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
//边距+可移动+可拉伸
|
||||
int padding;
|
||||
bool moveEnable;
|
||||
bool resizeEnable;
|
||||
|
||||
//标题栏控件
|
||||
QWidget *titleBar;
|
||||
|
||||
//鼠标是否按下+按下坐标+按下时窗体区域
|
||||
bool mousePressed;
|
||||
QPoint mousePoint;
|
||||
QRect mouseRect;
|
||||
|
||||
//鼠标是否按下某个区域+按下区域的大小
|
||||
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
|
||||
QList<bool> pressedArea;
|
||||
QList<QRect> pressedRect;
|
||||
|
||||
//记录是否最小化
|
||||
bool isMin;
|
||||
//存储窗体默认的属性
|
||||
Qt::WindowFlags flags;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置边距+可拖动+可拉伸
|
||||
void setPadding(int padding);
|
||||
void setMoveEnable(bool moveEnable);
|
||||
void setResizeEnable(bool resizeEnable);
|
||||
|
||||
//设置标题栏控件
|
||||
void setTitleBar(QWidget *titleBar);
|
||||
|
||||
Q_SIGNALS:
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
};
|
||||
|
||||
#endif // FRAMELESSMAINWINDOW_H
|
||||
373
widget/framelesswidget/framelesscore/framelesswidget.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
#include "framelesswidget.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "windows.h"
|
||||
#include "windowsx.h"
|
||||
#pragma comment (lib,"user32.lib")
|
||||
#endif
|
||||
|
||||
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
padding = 8;
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
|
||||
mousePressed = false;
|
||||
mousePoint = QPoint(0, 0);
|
||||
mouseRect = QRect(0, 0, 0, 0);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea << false;
|
||||
pressedRect << QRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
isMin = false;
|
||||
flags = this->windowFlags();
|
||||
titleBar = 0;
|
||||
|
||||
//设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0))
|
||||
this->setAttribute(Qt::WA_TranslucentBackground);
|
||||
#endif
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
//安装事件过滤器识别拖动
|
||||
this->installEventFilter(this);
|
||||
|
||||
//设置属性产生win窗体效果,移动到边缘半屏或者最大化等
|
||||
//设置以后会产生标题栏需要在下面拦截消息重新去掉
|
||||
#ifdef Q_OS_WIN
|
||||
HWND hwnd = (HWND)this->winId();
|
||||
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
//解决有时候窗体重新显示的时候假死不刷新的BUG
|
||||
setAttribute(Qt::WA_Mapped);
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void FramelessWidget::doWindowStateChange(QEvent *event)
|
||||
{
|
||||
//非最大化才能移动和拖动大小
|
||||
if (windowState() == Qt::WindowNoState) {
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
} else {
|
||||
moveEnable = false;
|
||||
resizeEnable = false;
|
||||
}
|
||||
|
||||
//发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字
|
||||
emit windowStateChange(!moveEnable);
|
||||
|
||||
//解决mac系统上无边框最小化失效的BUG
|
||||
#ifdef Q_OS_MACOS
|
||||
if (windowState() & Qt::WindowMinimized) {
|
||||
isMin = true;
|
||||
} else {
|
||||
if (isMin) {
|
||||
//设置无边框属性
|
||||
this->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
this->setVisible(true);
|
||||
isMin = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidget::doResizeEvent(QEvent *event)
|
||||
{
|
||||
//非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸
|
||||
//为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::Resize) {
|
||||
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
|
||||
//左侧描点区域
|
||||
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
|
||||
//右侧描点区域
|
||||
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
|
||||
//上侧描点区域
|
||||
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
|
||||
//下侧描点区域
|
||||
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
|
||||
|
||||
//左上角描点区域
|
||||
pressedRect[4] = QRect(0, 0, padding, padding);
|
||||
//右上角描点区域
|
||||
pressedRect[5] = QRect(width - padding, 0, padding, padding);
|
||||
//左下角描点区域
|
||||
pressedRect[6] = QRect(0, height - padding, padding, padding);
|
||||
//右下角描点区域
|
||||
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
|
||||
} else if (event->type() == QEvent::HoverMove) {
|
||||
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
|
||||
QHoverEvent *hoverEvent = (QHoverEvent *)event;
|
||||
QPoint point = hoverEvent->pos();
|
||||
if (resizeEnable) {
|
||||
if (pressedRect.at(0).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(1).contains(point)) {
|
||||
this->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(2).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(3).contains(point)) {
|
||||
this->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(4).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (pressedRect.at(5).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(6).contains(point)) {
|
||||
this->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(7).contains(point)) {
|
||||
this->setCursor(Qt::SizeFDiagCursor);
|
||||
} else {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
//根据当前鼠标位置,计算XY轴移动了多少
|
||||
int offsetX = point.x() - mousePoint.x();
|
||||
int offsetY = point.y() - mousePoint.y();
|
||||
|
||||
//根据按下处的位置判断是否是移动控件还是拉伸控件
|
||||
if (moveEnable && mousePressed) {
|
||||
this->move(this->x() + offsetX, this->y() + offsetY);
|
||||
}
|
||||
|
||||
if (resizeEnable) {
|
||||
int rectX = mouseRect.x();
|
||||
int rectY = mouseRect.y();
|
||||
int rectW = mouseRect.width();
|
||||
int rectH = mouseRect.height();
|
||||
|
||||
if (pressedArea.at(0)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
|
||||
}
|
||||
} else if (pressedArea.at(1)) {
|
||||
this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
|
||||
} else if (pressedArea.at(2)) {
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(3)) {
|
||||
this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
|
||||
} else if (pressedArea.at(4)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(5)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = this->height() - offsetY;
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(6)) {
|
||||
int resizeW = this->width() - offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
if (this->minimumWidth() <= resizeW) {
|
||||
this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
|
||||
}
|
||||
if (this->minimumHeight() <= resizeH) {
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(7)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
this->setGeometry(this->x(), this->y(), resizeW, resizeH);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
//记住鼠标按下的坐标+窗体区域
|
||||
QMouseEvent *mouseEvent = (QMouseEvent *)event;
|
||||
mousePoint = mouseEvent->pos();
|
||||
mouseRect = this->geometry();
|
||||
|
||||
//判断按下的手柄的区域位置
|
||||
if (pressedRect.at(0).contains(mousePoint)) {
|
||||
pressedArea[0] = true;
|
||||
} else if (pressedRect.at(1).contains(mousePoint)) {
|
||||
pressedArea[1] = true;
|
||||
} else if (pressedRect.at(2).contains(mousePoint)) {
|
||||
pressedArea[2] = true;
|
||||
} else if (pressedRect.at(3).contains(mousePoint)) {
|
||||
pressedArea[3] = true;
|
||||
} else if (pressedRect.at(4).contains(mousePoint)) {
|
||||
pressedArea[4] = true;
|
||||
} else if (pressedRect.at(5).contains(mousePoint)) {
|
||||
pressedArea[5] = true;
|
||||
} else if (pressedRect.at(6).contains(mousePoint)) {
|
||||
pressedArea[6] = true;
|
||||
} else if (pressedRect.at(7).contains(mousePoint)) {
|
||||
pressedArea[7] = true;
|
||||
} else {
|
||||
mousePressed = true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
//改成用HoverMove识别
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
//恢复所有
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
mousePressed = false;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea[i] = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessWidget::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == this) {
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
doWindowStateChange(event);
|
||||
} else {
|
||||
doResizeEvent(event);
|
||||
}
|
||||
} else if (watched == titleBar) {
|
||||
//双击标题栏发出双击信号给主界面
|
||||
//下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏
|
||||
#ifndef Q_OS_WIN
|
||||
if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
} else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) {
|
||||
emit titleDblClick();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||
#else
|
||||
bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
#endif
|
||||
{
|
||||
if (eventType == "windows_generic_MSG") {
|
||||
#ifdef Q_OS_WIN
|
||||
MSG *msg = static_cast<MSG *>(message);
|
||||
//qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message;
|
||||
|
||||
//不同的消息类型和参数进行不同的处理
|
||||
if (msg->message == WM_NCCALCSIZE) {
|
||||
*result = 0;
|
||||
return true;
|
||||
} else if (msg->message == WM_NCHITTEST) {
|
||||
//计算鼠标对应的屏幕坐标
|
||||
//这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题
|
||||
//官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest
|
||||
long x = GET_X_LPARAM(msg->lParam);
|
||||
long y = GET_Y_LPARAM(msg->lParam);
|
||||
QPoint pos = mapFromGlobal(QPoint(x, y));
|
||||
|
||||
//判断当前鼠标位置在哪个区域
|
||||
bool left = pos.x() < padding;
|
||||
bool right = pos.x() > width() - padding;
|
||||
bool top = pos.y() < padding;
|
||||
bool bottom = pos.y() > height() - padding;
|
||||
|
||||
//鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
|
||||
*result = 0;
|
||||
if (resizeEnable) {
|
||||
if (left && top) {
|
||||
*result = HTTOPLEFT;
|
||||
} else if (left && bottom) {
|
||||
*result = HTBOTTOMLEFT;
|
||||
} else if (right && top) {
|
||||
*result = HTTOPRIGHT;
|
||||
} else if (right && bottom) {
|
||||
*result = HTBOTTOMRIGHT;
|
||||
} else if (left) {
|
||||
*result = HTLEFT;
|
||||
} else if (right) {
|
||||
*result = HTRIGHT;
|
||||
} else if (top) {
|
||||
*result = HTTOP;
|
||||
} else if (bottom) {
|
||||
*result = HTBOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
//先处理掉拉伸
|
||||
if (0 != *result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//识别标题栏拖动产生半屏全屏效果
|
||||
if (titleBar != 0 && titleBar->rect().contains(pos)) {
|
||||
QWidget *child = titleBar->childAt(pos);
|
||||
if (!child) {
|
||||
*result = HTCAPTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) {
|
||||
//系统休眠的时候自动最小化可以规避程序可能出现的问题
|
||||
this->showMinimized();
|
||||
} else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) {
|
||||
//休眠唤醒后自动打开
|
||||
this->showNormal();
|
||||
}
|
||||
#endif
|
||||
} else if (eventType == "NSEvent") {
|
||||
#ifdef Q_OS_MACOS
|
||||
#endif
|
||||
} else if (eventType == "xcb_generic_event_t") {
|
||||
#ifdef Q_OS_LINUX
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool FramelessWidget::winEvent(MSG *message, long *result)
|
||||
{
|
||||
return nativeEvent("windows_generic_MSG", message, result);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void FramelessWidget::setPadding(int padding)
|
||||
{
|
||||
this->padding = padding;
|
||||
}
|
||||
|
||||
void FramelessWidget::setMoveEnable(bool moveEnable)
|
||||
{
|
||||
this->moveEnable = moveEnable;
|
||||
}
|
||||
|
||||
void FramelessWidget::setResizeEnable(bool resizeEnable)
|
||||
{
|
||||
this->resizeEnable = resizeEnable;
|
||||
}
|
||||
|
||||
void FramelessWidget::setTitleBar(QWidget *titleBar)
|
||||
{
|
||||
this->titleBar = titleBar;
|
||||
this->titleBar->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
96
widget/framelesswidget/framelesscore/framelesswidget.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef FRAMELESSWIDGET_H
|
||||
#define FRAMELESSWIDGET_H
|
||||
|
||||
/**
|
||||
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27
|
||||
* 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。
|
||||
* 2. 同时支持mingw、msvc、gcc等。
|
||||
* 3. 同时支持windows、linux、mac。
|
||||
* 4. 同时支持QMainWindow、QWidget、QDialog。
|
||||
* 5. 使用方法极其简单,只需要将继承类修改即可。
|
||||
* 6. 自动识别双击标题栏响应。
|
||||
* 7. 无边框拉伸在windows下不抖动。
|
||||
* 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。
|
||||
* 9. 解决mac系统上无边框最小化最大化失效的BUG。
|
||||
* 10. 解决系统休眠后再次启动程序懵逼的BUG。
|
||||
* 11. 解决有时候窗体重新显示的时候假死不刷新的BUG。
|
||||
* 12. 轻量级,1个代码文件,核心代码行数不到300行。
|
||||
* 13. 注释详细,示例完美,非常适合阅读和学习。
|
||||
* 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT FramelessWidget : public QWidget
|
||||
#else
|
||||
class FramelessWidget : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FramelessWidget(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
//窗体显示的时候触发
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
//事件过滤器识别拖动拉伸等
|
||||
void doWindowStateChange(QEvent *event);
|
||||
void doResizeEvent(QEvent *event);
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
//拦截系统事件用于修复系统休眠后唤醒程序的BUG
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
|
||||
#else
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||
#endif
|
||||
|
||||
//Qt4的写法
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#ifdef Q_OS_WIN
|
||||
bool winEvent(MSG *message, long *result);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
//边距+可移动+可拉伸
|
||||
int padding;
|
||||
bool moveEnable;
|
||||
bool resizeEnable;
|
||||
|
||||
//标题栏控件
|
||||
QWidget *titleBar;
|
||||
|
||||
//鼠标是否按下+按下坐标+按下时窗体区域
|
||||
bool mousePressed;
|
||||
QPoint mousePoint;
|
||||
QRect mouseRect;
|
||||
|
||||
//鼠标是否按下某个区域+按下区域的大小
|
||||
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
|
||||
QList<bool> pressedArea;
|
||||
QList<QRect> pressedRect;
|
||||
|
||||
//记录是否最小化
|
||||
bool isMin;
|
||||
//存储窗体默认的属性
|
||||
Qt::WindowFlags flags;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置边距+可拖动+可拉伸
|
||||
void setPadding(int padding);
|
||||
void setMoveEnable(bool moveEnable);
|
||||
void setResizeEnable(bool resizeEnable);
|
||||
|
||||
//设置标题栏控件
|
||||
void setTitleBar(QWidget *titleBar);
|
||||
|
||||
Q_SIGNALS:
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
};
|
||||
|
||||
#endif // FRAMELESSWIDGET_H
|
||||
69
widget/framelesswidget/framelessform/dialog.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "dialog.h"
|
||||
#include "ui_dialog.h"
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
Dialog::Dialog(QWidget *parent) : FramelessDialog(parent), ui(new Ui::Dialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Dialog::initForm()
|
||||
{
|
||||
//设置标题栏控件
|
||||
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
|
||||
this->setWindowTitle(ui->labTitle->text());
|
||||
this->setTitleBar(ui->labTitle);
|
||||
|
||||
//关联信号
|
||||
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
|
||||
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
|
||||
|
||||
//设置样式表
|
||||
QStringList list;
|
||||
list << "#titleBar{background:#BBBBBB;}";
|
||||
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
|
||||
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
|
||||
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
|
||||
this->setStyleSheet(list.join(""));
|
||||
}
|
||||
|
||||
void Dialog::titleDblClick()
|
||||
{
|
||||
on_btnMenu_Max_clicked();
|
||||
}
|
||||
|
||||
void Dialog::windowStateChange(bool max)
|
||||
{
|
||||
ui->btnMenu_Max->setText(max ? "还原" : "最大");
|
||||
}
|
||||
|
||||
void Dialog::on_btnMenu_Min_clicked()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
#endif
|
||||
this->showMinimized();
|
||||
}
|
||||
|
||||
void Dialog::on_btnMenu_Max_clicked()
|
||||
{
|
||||
if (this->isMaximized()) {
|
||||
this->showNormal();
|
||||
ui->btnMenu_Max->setText("最大");
|
||||
} else {
|
||||
this->showMaximized();
|
||||
ui->btnMenu_Max->setText("还原");
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::on_btnMenu_Close_clicked()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
32
widget/framelesswidget/framelessform/dialog.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef DIALOG_H
|
||||
#define DIALOG_H
|
||||
|
||||
#include "framelessdialog.h"
|
||||
|
||||
namespace Ui {
|
||||
class Dialog;
|
||||
}
|
||||
|
||||
class Dialog : public FramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Dialog(QWidget *parent = 0);
|
||||
~Dialog();
|
||||
|
||||
private:
|
||||
Ui::Dialog *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
|
||||
private slots:
|
||||
void on_btnMenu_Min_clicked();
|
||||
void on_btnMenu_Max_clicked();
|
||||
void on_btnMenu_Close_clicked();
|
||||
};
|
||||
|
||||
#endif // DIALOG_H
|
||||
223
widget/framelesswidget/framelessform/dialog.ui
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="FramelessDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="titleBar" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labTitle">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMenu" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Min">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>最小化</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最小</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Max">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最大</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Close">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMain" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FramelessDialog</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>framelessdialog.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
14
widget/framelesswidget/framelessform/framelessform.pri
Normal file
@@ -0,0 +1,14 @@
|
||||
FORMS += \
|
||||
$$PWD/dialog.ui \
|
||||
$$PWD/mainwindow.ui \
|
||||
$$PWD/widget.ui
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/dialog.h \
|
||||
$$PWD/mainwindow.h \
|
||||
$$PWD/widget.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/dialog.cpp \
|
||||
$$PWD/mainwindow.cpp \
|
||||
$$PWD/widget.cpp
|
||||
68
widget/framelesswidget/framelessform/mainwindow.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent), ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::initForm()
|
||||
{
|
||||
//设置标题栏控件
|
||||
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
|
||||
this->setWindowTitle(ui->labTitle->text());
|
||||
this->setTitleBar(ui->labTitle);
|
||||
|
||||
//关联信号
|
||||
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
|
||||
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
|
||||
|
||||
//设置样式表
|
||||
QStringList list;
|
||||
list << "#titleBar{background:#BBBBBB;}";
|
||||
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
|
||||
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
|
||||
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
|
||||
this->setStyleSheet(list.join(""));
|
||||
}
|
||||
|
||||
void MainWindow::titleDblClick()
|
||||
{
|
||||
on_btnMenu_Max_clicked();
|
||||
}
|
||||
|
||||
void MainWindow::windowStateChange(bool max)
|
||||
{
|
||||
ui->btnMenu_Max->setText(max ? "还原" : "最大");
|
||||
}
|
||||
|
||||
void MainWindow::on_btnMenu_Min_clicked()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
#endif
|
||||
this->showMinimized();
|
||||
}
|
||||
|
||||
void MainWindow::on_btnMenu_Max_clicked()
|
||||
{
|
||||
if (this->isMaximized()) {
|
||||
this->showNormal();
|
||||
ui->btnMenu_Max->setText("最大");
|
||||
} else {
|
||||
this->showMaximized();
|
||||
ui->btnMenu_Max->setText("还原");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_btnMenu_Close_clicked()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
32
widget/framelesswidget/framelessform/mainwindow.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "framelessmainwindow.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public FramelessMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
|
||||
private slots:
|
||||
void on_btnMenu_Min_clicked();
|
||||
void on_btnMenu_Max_clicked();
|
||||
void on_btnMenu_Close_clicked();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
233
widget/framelesswidget/framelessform/mainwindow.ui
Normal file
@@ -0,0 +1,233 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>207</width>
|
||||
<height>59</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="titleBar" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labTitle">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMenu" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Min">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>最小化</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最小</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Max">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最大</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Close">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMain" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FramelessMainWindow</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>framelessmainwindow.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
68
widget/framelesswidget/framelessform/widget.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "widget.h"
|
||||
#include "ui_widget.h"
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent), ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Widget::initForm()
|
||||
{
|
||||
//设置标题栏控件
|
||||
ui->labTitle->setText("无边框窗体示例-支持win、linux、mac等系统 (QQ: 517216493 WX: feiyangqingyun)");
|
||||
this->setWindowTitle(ui->labTitle->text());
|
||||
this->setTitleBar(ui->labTitle);
|
||||
|
||||
//关联信号
|
||||
connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick()));
|
||||
connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool)));
|
||||
|
||||
//设置样式表
|
||||
QStringList list;
|
||||
list << "#titleBar{background:#BBBBBB;}";
|
||||
list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}";
|
||||
list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}";
|
||||
//list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}";
|
||||
this->setStyleSheet(list.join(""));
|
||||
}
|
||||
|
||||
void Widget::titleDblClick()
|
||||
{
|
||||
on_btnMenu_Max_clicked();
|
||||
}
|
||||
|
||||
void Widget::windowStateChange(bool max)
|
||||
{
|
||||
ui->btnMenu_Max->setText(max ? "还原" : "最大");
|
||||
}
|
||||
|
||||
void Widget::on_btnMenu_Min_clicked()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
#endif
|
||||
this->showMinimized();
|
||||
}
|
||||
|
||||
void Widget::on_btnMenu_Max_clicked()
|
||||
{
|
||||
if (this->isMaximized()) {
|
||||
this->showNormal();
|
||||
ui->btnMenu_Max->setText("最大");
|
||||
} else {
|
||||
this->showMaximized();
|
||||
ui->btnMenu_Max->setText("还原");
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::on_btnMenu_Close_clicked()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
32
widget/framelesswidget/framelessform/widget.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
|
||||
#include "framelesswidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class Widget;
|
||||
}
|
||||
|
||||
class Widget : public FramelessWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Widget(QWidget *parent = 0);
|
||||
~Widget();
|
||||
|
||||
private:
|
||||
Ui::Widget *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void titleDblClick();
|
||||
void windowStateChange(bool max);
|
||||
|
||||
private slots:
|
||||
void on_btnMenu_Min_clicked();
|
||||
void on_btnMenu_Max_clicked();
|
||||
void on_btnMenu_Close_clicked();
|
||||
};
|
||||
|
||||
#endif // WIDGET_H
|
||||
223
widget/framelesswidget/framelessform/widget.ui
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget</class>
|
||||
<widget class="FramelessWidget" name="Widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="titleBar" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labTitle">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMenu" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Min">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>最小化</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最小</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Max">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>最大</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMenu_Close">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>ArrowCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetMain" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FramelessWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>framelesswidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
23
widget/framelesswidget/framelesswidget.pro
Normal file
@@ -0,0 +1,23 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = framelesswidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmframelesswidget.cpp
|
||||
SOURCES += framelesswidget2.cpp
|
||||
|
||||
HEADERS += frmframelesswidget.h
|
||||
HEADERS += framelesswidget2.h
|
||||
|
||||
FORMS += frmframelesswidget.ui
|
||||
|
||||
INCLUDEPATH += $$PWD/framelesscore
|
||||
INCLUDEPATH += $$PWD/framelessform
|
||||
|
||||
include ($$PWD/framelesscore/framelesscore.pri)
|
||||
include ($$PWD/framelessform/framelessform.pri)
|
||||
226
widget/framelesswidget/framelesswidget2.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "framelesswidget2.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
FramelessWidget2::FramelessWidget2(QObject *parent) : QObject(parent)
|
||||
{
|
||||
padding = 8;
|
||||
moveEnable = true;
|
||||
resizeEnable = true;
|
||||
widget = 0;
|
||||
|
||||
mousePressed = false;
|
||||
mousePoint = QPoint(0, 0);
|
||||
mouseRect = QRect(0, 0, 0, 0);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea << false;
|
||||
pressedRect << QRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
//如果父类是窗体则直接设置
|
||||
if (parent->isWidgetType()) {
|
||||
setWidget((QWidget *)parent);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessWidget2::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (widget != 0 && watched == widget) {
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
//解决mac系统上无边框最小化失效的BUG
|
||||
#ifdef Q_OS_MACOS
|
||||
if (widget->windowState() & Qt::WindowMinimized) {
|
||||
isMin = true;
|
||||
} else {
|
||||
if (isMin) {
|
||||
//设置无边框属性
|
||||
widget->setWindowFlags(flags | Qt::FramelessWindowHint);
|
||||
widget->setVisible(true);
|
||||
isMin = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (event->type() == QEvent::Resize) {
|
||||
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
|
||||
int width = widget->width();
|
||||
int height = widget->height();
|
||||
|
||||
//左侧描点区域
|
||||
pressedRect[0] = QRect(0, padding, padding, height - padding * 2);
|
||||
//右侧描点区域
|
||||
pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2);
|
||||
//上侧描点区域
|
||||
pressedRect[2] = QRect(padding, 0, width - padding * 2, padding);
|
||||
//下侧描点区域
|
||||
pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding);
|
||||
|
||||
//左上角描点区域
|
||||
pressedRect[4] = QRect(0, 0, padding, padding);
|
||||
//右上角描点区域
|
||||
pressedRect[5] = QRect(width - padding, 0, padding, padding);
|
||||
//左下角描点区域
|
||||
pressedRect[6] = QRect(0, height - padding, padding, padding);
|
||||
//右下角描点区域
|
||||
pressedRect[7] = QRect(width - padding, height - padding, padding, padding);
|
||||
} else if (event->type() == QEvent::HoverMove) {
|
||||
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
|
||||
QHoverEvent *hoverEvent = (QHoverEvent *)event;
|
||||
QPoint point = hoverEvent->pos();
|
||||
if (resizeEnable) {
|
||||
if (pressedRect.at(0).contains(point)) {
|
||||
widget->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(1).contains(point)) {
|
||||
widget->setCursor(Qt::SizeHorCursor);
|
||||
} else if (pressedRect.at(2).contains(point)) {
|
||||
widget->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(3).contains(point)) {
|
||||
widget->setCursor(Qt::SizeVerCursor);
|
||||
} else if (pressedRect.at(4).contains(point)) {
|
||||
widget->setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (pressedRect.at(5).contains(point)) {
|
||||
widget->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(6).contains(point)) {
|
||||
widget->setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (pressedRect.at(7).contains(point)) {
|
||||
widget->setCursor(Qt::SizeFDiagCursor);
|
||||
} else {
|
||||
widget->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
//根据当前鼠标位置,计算XY轴移动了多少
|
||||
int offsetX = point.x() - mousePoint.x();
|
||||
int offsetY = point.y() - mousePoint.y();
|
||||
|
||||
//根据按下处的位置判断是否是移动控件还是拉伸控件
|
||||
if (moveEnable && mousePressed) {
|
||||
widget->move(widget->x() + offsetX, widget->y() + offsetY);
|
||||
}
|
||||
|
||||
if (resizeEnable) {
|
||||
int rectX = mouseRect.x();
|
||||
int rectY = mouseRect.y();
|
||||
int rectW = mouseRect.width();
|
||||
int rectH = mouseRect.height();
|
||||
|
||||
if (pressedArea.at(0)) {
|
||||
int resizeW = widget->width() - offsetX;
|
||||
if (widget->minimumWidth() <= resizeW) {
|
||||
widget->setGeometry(widget->x() + offsetX, rectY, resizeW, rectH);
|
||||
}
|
||||
} else if (pressedArea.at(1)) {
|
||||
widget->setGeometry(rectX, rectY, rectW + offsetX, rectH);
|
||||
} else if (pressedArea.at(2)) {
|
||||
int resizeH = widget->height() - offsetY;
|
||||
if (widget->minimumHeight() <= resizeH) {
|
||||
widget->setGeometry(rectX, widget->y() + offsetY, rectW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(3)) {
|
||||
widget->setGeometry(rectX, rectY, rectW, rectH + offsetY);
|
||||
} else if (pressedArea.at(4)) {
|
||||
int resizeW = widget->width() - offsetX;
|
||||
int resizeH = widget->height() - offsetY;
|
||||
if (widget->minimumWidth() <= resizeW) {
|
||||
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
|
||||
}
|
||||
if (widget->minimumHeight() <= resizeH) {
|
||||
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(5)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = widget->height() - offsetY;
|
||||
if (widget->minimumHeight() <= resizeH) {
|
||||
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(6)) {
|
||||
int resizeW = widget->width() - offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
if (widget->minimumWidth() <= resizeW) {
|
||||
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
|
||||
}
|
||||
if (widget->minimumHeight() <= resizeH) {
|
||||
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
|
||||
}
|
||||
} else if (pressedArea.at(7)) {
|
||||
int resizeW = rectW + offsetX;
|
||||
int resizeH = rectH + offsetY;
|
||||
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
//记住鼠标按下的坐标+窗体区域
|
||||
QMouseEvent *mouseEvent = (QMouseEvent *)event;
|
||||
mousePoint = mouseEvent->pos();
|
||||
mouseRect = widget->geometry();
|
||||
|
||||
//判断按下的手柄的区域位置
|
||||
if (pressedRect.at(0).contains(mousePoint)) {
|
||||
pressedArea[0] = true;
|
||||
} else if (pressedRect.at(1).contains(mousePoint)) {
|
||||
pressedArea[1] = true;
|
||||
} else if (pressedRect.at(2).contains(mousePoint)) {
|
||||
pressedArea[2] = true;
|
||||
} else if (pressedRect.at(3).contains(mousePoint)) {
|
||||
pressedArea[3] = true;
|
||||
} else if (pressedRect.at(4).contains(mousePoint)) {
|
||||
pressedArea[4] = true;
|
||||
} else if (pressedRect.at(5).contains(mousePoint)) {
|
||||
pressedArea[5] = true;
|
||||
} else if (pressedRect.at(6).contains(mousePoint)) {
|
||||
pressedArea[6] = true;
|
||||
} else if (pressedRect.at(7).contains(mousePoint)) {
|
||||
pressedArea[7] = true;
|
||||
} else {
|
||||
mousePressed = true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
//改成用HoverMove识别
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
//恢复所有
|
||||
widget->setCursor(Qt::ArrowCursor);
|
||||
mousePressed = false;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pressedArea[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void FramelessWidget2::setPadding(int padding)
|
||||
{
|
||||
this->padding = padding;
|
||||
}
|
||||
|
||||
void FramelessWidget2::setMoveEnable(bool moveEnable)
|
||||
{
|
||||
this->moveEnable = moveEnable;
|
||||
}
|
||||
|
||||
void FramelessWidget2::setResizeEnable(bool resizeEnable)
|
||||
{
|
||||
this->resizeEnable = resizeEnable;
|
||||
}
|
||||
|
||||
void FramelessWidget2::setMousePressed(bool mousePressed)
|
||||
{
|
||||
this->mousePressed = mousePressed;
|
||||
}
|
||||
|
||||
void FramelessWidget2::setWidget(QWidget *widget)
|
||||
{
|
||||
if (this->widget == 0) {
|
||||
this->widget = widget;
|
||||
//设置鼠标追踪为真
|
||||
this->widget->setMouseTracking(true);
|
||||
//绑定事件过滤器
|
||||
this->widget->installEventFilter(this);
|
||||
//设置悬停为真,必须设置这个,不然当父窗体里边还有子窗体全部遮挡了识别不到MouseMove,需要识别HoverMove
|
||||
this->widget->setAttribute(Qt::WA_Hover, true);
|
||||
|
||||
isMin = false;
|
||||
flags = widget->windowFlags();
|
||||
}
|
||||
}
|
||||
66
widget/framelesswidget/framelesswidget2.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef FRAMELESSWIDGET2_H
|
||||
#define FRAMELESSWIDGET2_H
|
||||
|
||||
/**
|
||||
* 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2019-10-03
|
||||
* 1. 可以指定需要无边框的widget。
|
||||
* 2. 边框四周八个方位都可以自由拉伸。
|
||||
* 3. 可设置对应位置的边距,以便识别更大区域。
|
||||
* 4. 可设置是否允许拖动。
|
||||
* 5. 可设置是否允许拉伸。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT FramelessWidget2 : public QObject
|
||||
#else
|
||||
class FramelessWidget2 : public QObject
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FramelessWidget2(QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
private:
|
||||
//边距+可移动+可拉伸
|
||||
int padding;
|
||||
bool moveEnable;
|
||||
bool resizeEnable;
|
||||
|
||||
//无边框窗体
|
||||
QWidget *widget;
|
||||
|
||||
//鼠标是否按下+按下坐标+按下时窗体区域
|
||||
bool mousePressed;
|
||||
QPoint mousePoint;
|
||||
QRect mouseRect;
|
||||
|
||||
//鼠标是否按下某个区域+按下区域的大小
|
||||
//依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧
|
||||
QList<bool> pressedArea;
|
||||
QList<QRect> pressedRect;
|
||||
|
||||
//记录是否最小化
|
||||
bool isMin;
|
||||
//存储窗体默认的属性
|
||||
Qt::WindowFlags flags;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置边距
|
||||
void setPadding(int padding);
|
||||
//设置是否可拖动+拉伸
|
||||
void setMoveEnable(bool moveEnable);
|
||||
void setResizeEnable(bool resizeEnable);
|
||||
//修复部分控件不能自动识别 MouseButtonRelease 的BUG
|
||||
void setMousePressed(bool mousePressed);
|
||||
|
||||
//设置要无边框的窗体
|
||||
void setWidget(QWidget *widget);
|
||||
};
|
||||
|
||||
#endif // FRAMELESSWIDGET2_H
|
||||
110
widget/framelesswidget/frmframelesswidget.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmframelesswidget.h"
|
||||
#include "ui_frmframelesswidget.h"
|
||||
#include "qpushbutton.h"
|
||||
#include "qcheckbox.h"
|
||||
#include "qdebug.h"
|
||||
#include "framelesswidget2.h"
|
||||
|
||||
#ifndef Q_CC_MSVC
|
||||
#include "framelessform/dialog.h"
|
||||
#include "framelessform/widget.h"
|
||||
#include "framelessform/mainwindow.h"
|
||||
#endif
|
||||
|
||||
frmFramelessWidget::frmFramelessWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmFramelessWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
frmFramelessWidget::~frmFramelessWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmFramelessWidget::initForm()
|
||||
{
|
||||
widget = 0;
|
||||
frameless = 0;
|
||||
|
||||
connect(ui->btnDialog, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
|
||||
connect(ui->btnWidget, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
|
||||
connect(ui->btnMainWindow, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
|
||||
}
|
||||
|
||||
void frmFramelessWidget::initWidget(QWidget *w)
|
||||
{
|
||||
//设置无边框属性
|
||||
w->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
|
||||
//w->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
|
||||
w->setWindowTitle("自由拉伸无边框窗体");
|
||||
w->setMinimumSize(200, 120);
|
||||
w->resize(480, 320);
|
||||
|
||||
//设置下背景颜色区别看
|
||||
QPalette palette = w->palette();
|
||||
palette.setBrush(QPalette::Window, QColor(162, 121, 197));
|
||||
w->setPalette(palette);
|
||||
|
||||
QPushButton *btn = new QPushButton(w);
|
||||
btn->setText("关闭");
|
||||
btn->setGeometry(10, 10, 130, 25);
|
||||
connect(btn, SIGNAL(clicked(bool)), w, SLOT(close()));
|
||||
|
||||
QCheckBox *cboxMove = new QCheckBox(w);
|
||||
cboxMove->setText("可移动");
|
||||
cboxMove->setChecked(true);
|
||||
cboxMove->setGeometry(10, 40, 70, 25);
|
||||
connect(cboxMove, SIGNAL(stateChanged(int)), this, SLOT(stateChanged1(int)));
|
||||
|
||||
QCheckBox *cboxResize = new QCheckBox(w);
|
||||
cboxResize->setText("可拉伸");
|
||||
cboxResize->setChecked(true);
|
||||
cboxResize->setGeometry(80, 40, 70, 25);
|
||||
connect(cboxResize, SIGNAL(stateChanged(int)), this, SLOT(stateChanged2(int)));
|
||||
}
|
||||
|
||||
void frmFramelessWidget::on_pushButton_clicked()
|
||||
{
|
||||
if (widget == 0) {
|
||||
widget = new QWidget;
|
||||
this->initWidget(widget);
|
||||
frameless = new FramelessWidget2(widget);
|
||||
frameless->setWidget(widget);
|
||||
}
|
||||
|
||||
widget->show();
|
||||
}
|
||||
|
||||
void frmFramelessWidget::stateChanged1(int arg1)
|
||||
{
|
||||
if (frameless != 0) {
|
||||
frameless->setMoveEnable(arg1 != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void frmFramelessWidget::stateChanged2(int arg1)
|
||||
{
|
||||
if (frameless != 0) {
|
||||
frameless->setResizeEnable(arg1 != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void frmFramelessWidget::buttonClicked()
|
||||
{
|
||||
#ifndef Q_CC_MSVC
|
||||
QString objName = sender()->objectName();
|
||||
if (objName == "btnDialog") {
|
||||
Dialog dialog;
|
||||
dialog.exec();
|
||||
} else if (objName == "btnWidget") {
|
||||
Widget *widget = new Widget;
|
||||
widget->show();
|
||||
} else if (objName == "btnMainWindow") {
|
||||
MainWindow *window = new MainWindow;
|
||||
window->show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
33
widget/framelesswidget/frmframelesswidget.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef FRMFRAMELESSWIDGET_H
|
||||
#define FRMFRAMELESSWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
class FramelessWidget2;
|
||||
|
||||
namespace Ui {
|
||||
class frmFramelessWidget;
|
||||
}
|
||||
|
||||
class frmFramelessWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmFramelessWidget(QWidget *parent = 0);
|
||||
~frmFramelessWidget();
|
||||
|
||||
private:
|
||||
Ui::frmFramelessWidget *ui;
|
||||
QWidget *widget;
|
||||
FramelessWidget2 *frameless;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void initWidget(QWidget *w);
|
||||
void on_pushButton_clicked();
|
||||
void stateChanged1(int arg1);
|
||||
void stateChanged2(int arg1);
|
||||
void buttonClicked();
|
||||
};
|
||||
|
||||
#endif // FRMFRAMELESSWIDGET_H
|
||||
59
widget/framelesswidget/frmframelesswidget.ui
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmFramelessWidget</class>
|
||||
<widget class="QWidget" name="frmFramelessWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>491</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>弹出</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDialog">
|
||||
<property name="text">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnWidget">
|
||||
<property name="text">
|
||||
<string>Widget</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMainWindow">
|
||||
<property name="text">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
35
widget/framelesswidget/main.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmframelesswidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
|
||||
#endif
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmFramelessWidget w;
|
||||
w.setWindowTitle("无边框窗体");
|
||||
w.resize(800, 600);
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
20
widget/gifwidget/frmgifwidget.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "frmgifwidget.h"
|
||||
#include "ui_frmgifwidget.h"
|
||||
#include "gifwidget.h"
|
||||
|
||||
frmGifWidget::frmGifWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmGifWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
frmGifWidget::~frmGifWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmGifWidget::on_pushButton_clicked()
|
||||
{
|
||||
//设置截图窗口置顶显示
|
||||
GifWidget::Instance()->setWindowFlags(GifWidget::Instance()->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
GifWidget::Instance()->show();
|
||||
}
|
||||
25
widget/gifwidget/frmgifwidget.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FRMGIFWIDGET_H
|
||||
#define FRMGIFWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmGifWidget;
|
||||
}
|
||||
|
||||
class frmGifWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmGifWidget(QWidget *parent = 0);
|
||||
~frmGifWidget();
|
||||
|
||||
private slots:
|
||||
void on_pushButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::frmGifWidget *ui;
|
||||
};
|
||||
|
||||
#endif // FRMGIFWIDGET_H
|
||||
32
widget/gifwidget/frmgifwidget.ui
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmGifWidget</class>
|
||||
<widget class="QWidget" name="frmGifWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>92</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>弹出</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
795
widget/gifwidget/gif.h
Normal file
@@ -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
|
||||
382
widget/gifwidget/gifwidget.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "gifwidget.h"
|
||||
#include "qmutex.h"
|
||||
#include "qlabel.h"
|
||||
#include "qlineedit.h"
|
||||
#include "qpushbutton.h"
|
||||
#include "qlayout.h"
|
||||
#include "qpainter.h"
|
||||
#include "qevent.h"
|
||||
#include "qstyle.h"
|
||||
#include "qpixmap.h"
|
||||
#include "qtimer.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qapplication.h"
|
||||
#include "qdesktopservices.h"
|
||||
#include "qfiledialog.h"
|
||||
#include "qurl.h"
|
||||
#include "qtextcodec.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
#include "qscreen.h"
|
||||
#define deskGeometry qApp->primaryScreen()->geometry()
|
||||
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
|
||||
#else
|
||||
#include "qdesktopwidget.h"
|
||||
#define deskGeometry qApp->desktop()->geometry()
|
||||
#define deskGeometry2 qApp->desktop()->availableGeometry()
|
||||
#endif
|
||||
|
||||
QScopedPointer<GifWidget> GifWidget::self;
|
||||
GifWidget *GifWidget::Instance()
|
||||
{
|
||||
if (self.isNull()) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
if (self.isNull()) {
|
||||
self.reset(new GifWidget);
|
||||
}
|
||||
}
|
||||
|
||||
return self.data();
|
||||
}
|
||||
|
||||
GifWidget::GifWidget(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
this->initControl();
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
bool GifWidget::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
static QPoint mousePoint;
|
||||
static bool mousePressed = false;
|
||||
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (mouseEvent->type() == QEvent::MouseButtonPress) {
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
mousePressed = true;
|
||||
mousePoint = mouseEvent->globalPos() - this->pos();
|
||||
return true;
|
||||
}
|
||||
} else if (mouseEvent->type() == QEvent::MouseButtonRelease) {
|
||||
mousePressed = false;
|
||||
return true;
|
||||
} else if (mouseEvent->type() == QEvent::MouseMove) {
|
||||
if (mousePressed) {
|
||||
this->move(mouseEvent->globalPos() - mousePoint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void GifWidget::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
//拉动右下角改变大小自动赋值
|
||||
txtWidth->setText(QString::number(widgetMain->width()));
|
||||
txtHeight->setText(QString::number(widgetMain->height()));
|
||||
QDialog::resizeEvent(e);
|
||||
}
|
||||
|
||||
void GifWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
int width = txtWidth->text().toInt();
|
||||
int height = txtHeight->text().toInt();
|
||||
rectGif = QRect(borderWidth, widgetTop->height(), width - (borderWidth * 2), height);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(bgColor);
|
||||
painter.drawRoundedRect(this->rect(), 5, 5);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Clear);
|
||||
painter.fillRect(rectGif, Qt::SolidPattern);
|
||||
}
|
||||
|
||||
int GifWidget::getBorderWidth() const
|
||||
{
|
||||
return this->borderWidth;
|
||||
}
|
||||
|
||||
QColor GifWidget::getBgColor() const
|
||||
{
|
||||
return this->bgColor;
|
||||
}
|
||||
|
||||
void GifWidget::initControl()
|
||||
{
|
||||
this->setObjectName("GifWidget");
|
||||
this->resize(800, 600);
|
||||
this->setSizeGripEnabled(true);
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
|
||||
verticalLayout->setSpacing(0);
|
||||
verticalLayout->setContentsMargins(11, 11, 11, 11);
|
||||
verticalLayout->setObjectName("verticalLayout");
|
||||
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
widgetTop = new QWidget(this);
|
||||
widgetTop->setObjectName("widgetTop");
|
||||
widgetTop->setMinimumSize(QSize(0, 35));
|
||||
widgetTop->setMaximumSize(QSize(16777215, 35));
|
||||
|
||||
QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop);
|
||||
layoutTop->setSpacing(0);
|
||||
layoutTop->setContentsMargins(11, 11, 11, 11);
|
||||
layoutTop->setObjectName("layoutTop");
|
||||
layoutTop->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QPushButton *btnIcon = new QPushButton(widgetTop);
|
||||
btnIcon->setObjectName("btnIcon");
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(btnIcon->sizePolicy().hasHeightForWidth());
|
||||
btnIcon->setSizePolicy(sizePolicy);
|
||||
btnIcon->setMinimumSize(QSize(35, 0));
|
||||
btnIcon->setFlat(true);
|
||||
layoutTop->addWidget(btnIcon);
|
||||
|
||||
QLabel *labTitle = new QLabel(widgetTop);
|
||||
labTitle->setObjectName("labTitle");
|
||||
layoutTop->addWidget(labTitle);
|
||||
|
||||
QSpacerItem *horizontalSpacer = new QSpacerItem(87, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
layoutTop->addItem(horizontalSpacer);
|
||||
|
||||
QPushButton *btnClose = new QPushButton(widgetTop);
|
||||
btnClose->setObjectName("btnClose");
|
||||
sizePolicy.setHeightForWidth(btnClose->sizePolicy().hasHeightForWidth());
|
||||
btnClose->setSizePolicy(sizePolicy);
|
||||
btnClose->setMinimumSize(QSize(35, 0));
|
||||
btnClose->setFocusPolicy(Qt::NoFocus);
|
||||
btnClose->setFlat(true);
|
||||
layoutTop->addWidget(btnClose);
|
||||
verticalLayout->addWidget(widgetTop);
|
||||
|
||||
widgetMain = new QWidget(this);
|
||||
widgetMain->setObjectName("widgetMain");
|
||||
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
sizePolicy1.setHorizontalStretch(0);
|
||||
sizePolicy1.setVerticalStretch(0);
|
||||
sizePolicy1.setHeightForWidth(widgetMain->sizePolicy().hasHeightForWidth());
|
||||
widgetMain->setSizePolicy(sizePolicy1);
|
||||
verticalLayout->addWidget(widgetMain);
|
||||
|
||||
widgetBottom = new QWidget(this);
|
||||
widgetBottom->setObjectName("widgetBottom");
|
||||
widgetBottom->setMinimumSize(QSize(0, 45));
|
||||
widgetBottom->setMaximumSize(QSize(16777215, 45));
|
||||
|
||||
QHBoxLayout *layoutBottom = new QHBoxLayout(widgetBottom);
|
||||
layoutBottom->setSpacing(6);
|
||||
layoutBottom->setContentsMargins(11, 11, 11, 11);
|
||||
layoutBottom->setObjectName("layoutBottom");
|
||||
layoutBottom->setContentsMargins(9, 9, -1, -1);
|
||||
|
||||
QLabel *labFps = new QLabel(widgetBottom);
|
||||
labFps->setObjectName("labFps");
|
||||
layoutBottom->addWidget(labFps);
|
||||
|
||||
txtFps = new QLineEdit(widgetBottom);
|
||||
txtFps->setObjectName("txtFps");
|
||||
txtFps->setMaximumSize(QSize(50, 16777215));
|
||||
txtFps->setAlignment(Qt::AlignCenter);
|
||||
layoutBottom->addWidget(txtFps);
|
||||
|
||||
QLabel *labWidth = new QLabel(widgetBottom);
|
||||
labWidth->setObjectName("labWidth");
|
||||
layoutBottom->addWidget(labWidth);
|
||||
|
||||
txtWidth = new QLineEdit(widgetBottom);
|
||||
txtWidth->setObjectName("txtWidth");
|
||||
txtWidth->setEnabled(true);
|
||||
txtWidth->setMaximumSize(QSize(50, 16777215));
|
||||
txtWidth->setAlignment(Qt::AlignCenter);
|
||||
layoutBottom->addWidget(txtWidth);
|
||||
|
||||
QLabel *labHeight = new QLabel(widgetBottom);
|
||||
labHeight->setObjectName("labHeight");
|
||||
layoutBottom->addWidget(labHeight);
|
||||
|
||||
txtHeight = new QLineEdit(widgetBottom);
|
||||
txtHeight->setObjectName("txtHeight");
|
||||
txtHeight->setEnabled(true);
|
||||
txtHeight->setMaximumSize(QSize(50, 16777215));
|
||||
txtHeight->setAlignment(Qt::AlignCenter);
|
||||
layoutBottom->addWidget(txtHeight);
|
||||
|
||||
labStatus = new QLabel(widgetBottom);
|
||||
labStatus->setObjectName("labStatus");
|
||||
QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
sizePolicy2.setHorizontalStretch(0);
|
||||
sizePolicy2.setVerticalStretch(0);
|
||||
sizePolicy2.setHeightForWidth(labStatus->sizePolicy().hasHeightForWidth());
|
||||
labStatus->setSizePolicy(sizePolicy2);
|
||||
labStatus->setAlignment(Qt::AlignCenter);
|
||||
layoutBottom->addWidget(labStatus);
|
||||
|
||||
btnStart = new QPushButton(widgetBottom);
|
||||
btnStart->setObjectName("btnStart");
|
||||
sizePolicy.setHeightForWidth(btnStart->sizePolicy().hasHeightForWidth());
|
||||
btnStart->setSizePolicy(sizePolicy);
|
||||
layoutBottom->addWidget(btnStart);
|
||||
verticalLayout->addWidget(widgetBottom);
|
||||
|
||||
labTitle->setText("GIF录屏工具(QQ:517216493)");
|
||||
labFps->setText("帧率");
|
||||
labWidth->setText("宽度");
|
||||
labHeight->setText("高度");
|
||||
btnStart->setText("开始");
|
||||
this->setWindowTitle(labTitle->text());
|
||||
|
||||
btnIcon->setIcon(style()->standardIcon(QStyle::SP_ComputerIcon));
|
||||
btnClose->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
||||
|
||||
connect(btnClose, SIGNAL(clicked(bool)), this, SLOT(closeAll()));
|
||||
connect(btnStart, SIGNAL(clicked(bool)), this, SLOT(record()));
|
||||
connect(txtWidth, SIGNAL(editingFinished()), this, SLOT(resizeForm()));
|
||||
connect(txtHeight, SIGNAL(editingFinished()), this, SLOT(resizeForm()));
|
||||
}
|
||||
|
||||
void GifWidget::initForm()
|
||||
{
|
||||
borderWidth = 3;
|
||||
bgColor = QColor(34, 163, 169);
|
||||
|
||||
fps = 10;
|
||||
txtFps->setText(QString::number(fps));
|
||||
gifWriter = 0;
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(100);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(saveImage()));
|
||||
|
||||
this->setAttribute(Qt::WA_TranslucentBackground);
|
||||
this->setWindowFlags(Qt::FramelessWindowHint);
|
||||
this->installEventFilter(this);
|
||||
|
||||
QStringList qss;
|
||||
qss.append("QLabel{color:#ffffff;}");
|
||||
qss.append("#btnClose,#btnIcon{border:none;border-radius:0px;}");
|
||||
qss.append("#btnClose:hover{background-color:#ff0000;}");
|
||||
qss.append("#btnClose{border-top-right-radius:5px;}");
|
||||
qss.append("#labTitle{font:bold 16px;}");
|
||||
qss.append("#labStatus{font:15px;}");
|
||||
this->setStyleSheet(qss.join(""));
|
||||
}
|
||||
|
||||
void GifWidget::saveImage()
|
||||
{
|
||||
if (!gifWriter) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
QScreen *screen = QApplication::primaryScreen();
|
||||
QPixmap pix = screen->grabWindow(0, x() + rectGif.x(), y() + rectGif.y(), rectGif.width(), rectGif.height());
|
||||
QImage image = pix.toImage().convertToFormat(QImage::Format_RGBA8888);
|
||||
#else
|
||||
//由于qt4没有RGBA8888,采用最接近RGBA8888的是ARGB32,颜色会有点偏差
|
||||
QPixmap pix = QPixmap::grabWindow(0, x() + rectGif.x(), y() + rectGif.y(), rectGif.width(), rectGif.height());
|
||||
QImage image = pix.toImage().convertToFormat(QImage::Format_ARGB32);
|
||||
#endif
|
||||
|
||||
gif.GifWriteFrame(gifWriter, image.bits(), rectGif.width(), rectGif.height(), fps);
|
||||
count++;
|
||||
labStatus->setText(QString("正在录制 第 %1 帧").arg(count));
|
||||
}
|
||||
|
||||
void GifWidget::record()
|
||||
{
|
||||
if (btnStart->text() == "开始") {
|
||||
if (0 != gifWriter) {
|
||||
delete gifWriter;
|
||||
gifWriter = 0;
|
||||
}
|
||||
|
||||
//先弹出文件保存对话框
|
||||
//fileName = qApp->applicationDirPath() + "/" + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss.gif");
|
||||
fileName = QFileDialog::getSaveFileName(this, "选择保存位置", qApp->applicationDirPath() + "/", "gif图片(*.gif)");
|
||||
if (fileName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = txtWidth->text().toInt();
|
||||
int height = txtHeight->text().toInt();
|
||||
fps = txtFps->text().toInt();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//windows上需要先转码
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
QTextCodec *code = QTextCodec::codecForName("utf-8");
|
||||
#else
|
||||
QTextCodec *code = QTextCodec::codecForName("gbk");
|
||||
#endif
|
||||
const char *name = code->fromUnicode(fileName).constData();
|
||||
#else
|
||||
const char *name = fileName.toUtf8().constData();
|
||||
#endif
|
||||
|
||||
gifWriter = new Gif::GifWriter;
|
||||
bool ok = gif.GifBegin(gifWriter, name, width, height, fps);
|
||||
if (!ok) {
|
||||
delete gifWriter;
|
||||
gifWriter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
labStatus->setText("开始录制...");
|
||||
btnStart->setText("停止");
|
||||
//延时启动
|
||||
timer->setInterval(1000 / fps);
|
||||
QTimer::singleShot(1000, timer, SLOT(start()));
|
||||
//saveImage();
|
||||
} else {
|
||||
timer->stop();
|
||||
gif.GifEnd(gifWriter);
|
||||
|
||||
delete gifWriter;
|
||||
gifWriter = 0;
|
||||
|
||||
labStatus->setText(QString("录制完成 共 %1 帧").arg(count));
|
||||
btnStart->setText("开始");
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
void GifWidget::closeAll()
|
||||
{
|
||||
if (0 != gifWriter) {
|
||||
delete gifWriter;
|
||||
gifWriter = 0;
|
||||
}
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
void GifWidget::resizeForm()
|
||||
{
|
||||
int width = txtWidth->text().toInt();
|
||||
int height = txtHeight->text().toInt();
|
||||
this->resize(width, height + widgetTop->height() + widgetBottom->height());
|
||||
}
|
||||
|
||||
void GifWidget::setBorderWidth(int borderWidth)
|
||||
{
|
||||
if (this->borderWidth != borderWidth) {
|
||||
this->borderWidth = borderWidth;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void GifWidget::setBgColor(const QColor &bgColor)
|
||||
{
|
||||
if (this->bgColor != bgColor) {
|
||||
this->bgColor = bgColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
80
widget/gifwidget/gifwidget.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef GIFWIDGET_H
|
||||
#define GIFWIDGET_H
|
||||
|
||||
/**
|
||||
* GIF录屏控件 作者:feiyangqingyun(QQ:517216493) 2019-04-03
|
||||
* 1. 可设置要录制屏幕的宽高,支持右下角直接拉动改变。
|
||||
* 2. 可设置变宽的宽度。
|
||||
* 3. 可设置录屏控件的背景颜色。
|
||||
* 4. 可设置录制的帧数。
|
||||
* 5. 录制区域可自由拖动选择。
|
||||
*/
|
||||
|
||||
#include <QDialog>
|
||||
#include "gif.h"
|
||||
|
||||
class QLineEdit;
|
||||
class QLabel;
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT GifWidget : public QDialog
|
||||
#else
|
||||
class GifWidget : public QDialog
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth)
|
||||
Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
|
||||
|
||||
public:
|
||||
static GifWidget *Instance();
|
||||
explicit GifWidget(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
void resizeEvent(QResizeEvent *);
|
||||
void paintEvent(QPaintEvent *);
|
||||
|
||||
private:
|
||||
static QScopedPointer<GifWidget> self;
|
||||
QWidget *widgetTop; //标题栏
|
||||
QWidget *widgetMain; //中间部分
|
||||
QWidget *widgetBottom; //底部栏
|
||||
QLineEdit *txtFps; //帧率输入框
|
||||
QLineEdit *txtWidth; //宽度输入框
|
||||
QLineEdit *txtHeight; //高度输入框
|
||||
QPushButton *btnStart; //开始按钮
|
||||
QLabel *labStatus; //显示状态信息
|
||||
|
||||
int fps; //帧数 100为1s
|
||||
int borderWidth; //边框宽度
|
||||
QColor bgColor; //背景颜色
|
||||
|
||||
int count; //帧数计数
|
||||
QString fileName; //保存文件名称
|
||||
QRect rectGif; //截屏区域
|
||||
QTimer *timer; //截屏定时器
|
||||
|
||||
Gif gif; //gif类对象
|
||||
Gif::GifWriter *gifWriter; //gif写入对象
|
||||
|
||||
public:
|
||||
int getBorderWidth() const;
|
||||
QColor getBgColor() const;
|
||||
|
||||
private slots:
|
||||
void initControl();
|
||||
void initForm();
|
||||
void saveImage();
|
||||
void record();
|
||||
void closeAll();
|
||||
void resizeForm();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setBorderWidth(int borderWidth);
|
||||
void setBgColor(const QColor &bgColor);
|
||||
};
|
||||
|
||||
#endif // GIFWIDGET_H
|
||||
19
widget/gifwidget/gifwidget.pro
Normal file
@@ -0,0 +1,19 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = gifwidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmgifwidget.cpp
|
||||
SOURCES += gifwidget.cpp
|
||||
|
||||
HEADERS += gifwidget.h
|
||||
HEADERS += frmgifwidget.h
|
||||
HEADERS += gif.h
|
||||
|
||||
FORMS += frmgifwidget.ui
|
||||
RESOURCES += main.qrc
|
||||
BIN
widget/gifwidget/image/gifwidget.ico
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
widget/gifwidget/image/gifwidget.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
37
widget/gifwidget/main.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmgifwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
#include <QIcon>
|
||||
#include <QDebug>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
|
||||
#endif
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
a.setWindowIcon(QIcon(":/image/gifwidget.ico"));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmGifWidget w;
|
||||
w.setWindowTitle("GIF录屏");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
5
widget/gifwidget/main.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>image/gifwidget.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
BIN
widget/lunarcalendarwidget/font/fontawesome-webfont.ttf
Normal file
38
widget/lunarcalendarwidget/frmlunarcalendarwidget.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "frmlunarcalendarwidget.h"
|
||||
#include "ui_frmlunarcalendarwidget.h"
|
||||
|
||||
frmLunarCalendarWidget::frmLunarCalendarWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmLunarCalendarWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
frmLunarCalendarWidget::~frmLunarCalendarWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmLunarCalendarWidget::initForm()
|
||||
{
|
||||
ui->cboxWeekNameFormat->setCurrentIndex(2);
|
||||
}
|
||||
|
||||
void frmLunarCalendarWidget::on_cboxCalendarStyle_currentIndexChanged(int index)
|
||||
{
|
||||
ui->lunarCalendarWidget->setCalendarStyle((LunarCalendarWidget::CalendarStyle)index);
|
||||
}
|
||||
|
||||
void frmLunarCalendarWidget::on_cboxSelectType_currentIndexChanged(int index)
|
||||
{
|
||||
ui->lunarCalendarWidget->setSelectType((LunarCalendarWidget::SelectType)index);
|
||||
}
|
||||
|
||||
void frmLunarCalendarWidget::on_cboxWeekNameFormat_currentIndexChanged(int index)
|
||||
{
|
||||
ui->lunarCalendarWidget->setWeekNameFormat((LunarCalendarWidget::WeekNameFormat)index);
|
||||
}
|
||||
|
||||
void frmLunarCalendarWidget::on_ckShowLunar_stateChanged(int arg1)
|
||||
{
|
||||
ui->lunarCalendarWidget->setShowLunar(arg1 != 0);
|
||||
}
|
||||
29
widget/lunarcalendarwidget/frmlunarcalendarwidget.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef FRMLUNARCALENDARWIDGET_H
|
||||
#define FRMLUNARCALENDARWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmLunarCalendarWidget;
|
||||
}
|
||||
|
||||
class frmLunarCalendarWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmLunarCalendarWidget(QWidget *parent = 0);
|
||||
~frmLunarCalendarWidget();
|
||||
|
||||
private:
|
||||
Ui::frmLunarCalendarWidget *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void on_cboxCalendarStyle_currentIndexChanged(int index);
|
||||
void on_cboxSelectType_currentIndexChanged(int index);
|
||||
void on_cboxWeekNameFormat_currentIndexChanged(int index);
|
||||
void on_ckShowLunar_stateChanged(int arg1);
|
||||
};
|
||||
|
||||
#endif // FRMLUNARCALENDARWIDGET_H
|
||||
176
widget/lunarcalendarwidget/frmlunarcalendarwidget.ui
Normal file
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmLunarCalendarWidget</class>
|
||||
<widget class="QWidget" name="frmLunarCalendarWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="LunarCalendarWidget" name="lunarCalendarWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetBottom" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labCalendarStyle">
|
||||
<property name="text">
|
||||
<string>整体样式</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboxCalendarStyle">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>红色风格</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labSelectType">
|
||||
<property name="text">
|
||||
<string>选中样式</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboxSelectType">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>矩形背景</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>圆形背景</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>角标背景</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>图片背景</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labWeekNameFormat">
|
||||
<property name="text">
|
||||
<string>星期格式</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboxWeekNameFormat">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>短名称</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>普通名称</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>长名称</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>英文名称</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ckShowLunar">
|
||||
<property name="text">
|
||||
<string>显示农历</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LunarCalendarWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>lunarcalendarwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
BIN
widget/lunarcalendarwidget/image/bg_calendar.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
796
widget/lunarcalendarwidget/lunarcalendarinfo.cpp
Normal file
@@ -0,0 +1,796 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "lunarcalendarinfo.h"
|
||||
#include "qmutex.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#define year_2099
|
||||
|
||||
QScopedPointer<LunarCalendarInfo> LunarCalendarInfo::self;
|
||||
LunarCalendarInfo *LunarCalendarInfo::Instance()
|
||||
{
|
||||
if (self.isNull()) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
if (self.isNull()) {
|
||||
self.reset(new LunarCalendarInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return self.data();
|
||||
}
|
||||
|
||||
LunarCalendarInfo::LunarCalendarInfo(QObject *parent) : QObject(parent)
|
||||
{
|
||||
//农历查表
|
||||
lunarCalendarTable << 0x04AE53 << 0x0A5748 << 0x5526BD << 0x0D2650 << 0x0D9544 << 0x46AAB9 << 0x056A4D << 0x09AD42 << 0x24AEB6 << 0x04AE4A; //1901-1910
|
||||
lunarCalendarTable << 0x6A4DBE << 0x0A4D52 << 0x0D2546 << 0x5D52BA << 0x0B544E << 0x0D6A43 << 0x296D37 << 0x095B4B << 0x749BC1 << 0x049754; //1911-1920
|
||||
lunarCalendarTable << 0x0A4B48 << 0x5B25BC << 0x06A550 << 0x06D445 << 0x4ADAB8 << 0x02B64D << 0x095742 << 0x2497B7 << 0x04974A << 0x664B3E; //1921-1930
|
||||
lunarCalendarTable << 0x0D4A51 << 0x0EA546 << 0x56D4BA << 0x05AD4E << 0x02B644 << 0x393738 << 0x092E4B << 0x7C96BF << 0x0C9553 << 0x0D4A48; //1931-1940
|
||||
lunarCalendarTable << 0x6DA53B << 0x0B554F << 0x056A45 << 0x4AADB9 << 0x025D4D << 0x092D42 << 0x2C95B6 << 0x0A954A << 0x7B4ABD << 0x06CA51; //1941-1950
|
||||
lunarCalendarTable << 0x0B5546 << 0x555ABB << 0x04DA4E << 0x0A5B43 << 0x352BB8 << 0x052B4C << 0x8A953F << 0x0E9552 << 0x06AA48 << 0x6AD53C; //1951-1960
|
||||
lunarCalendarTable << 0x0AB54F << 0x04B645 << 0x4A5739 << 0x0A574D << 0x052642 << 0x3E9335 << 0x0D9549 << 0x75AABE << 0x056A51 << 0x096D46; //1961-1970
|
||||
lunarCalendarTable << 0x54AEBB << 0x04AD4F << 0x0A4D43 << 0x4D26B7 << 0x0D254B << 0x8D52BF << 0x0B5452 << 0x0B6A47 << 0x696D3C << 0x095B50; //1971-1980
|
||||
lunarCalendarTable << 0x049B45 << 0x4A4BB9 << 0x0A4B4D << 0xAB25C2 << 0x06A554 << 0x06D449 << 0x6ADA3D << 0x0AB651 << 0x093746 << 0x5497BB; //1981-1990
|
||||
lunarCalendarTable << 0x04974F << 0x064B44 << 0x36A537 << 0x0EA54A << 0x86B2BF << 0x05AC53 << 0x0AB647 << 0x5936BC << 0x092E50 << 0x0C9645; //1991-2000
|
||||
lunarCalendarTable << 0x4D4AB8 << 0x0D4A4C << 0x0DA541 << 0x25AAB6 << 0x056A49 << 0x7AADBD << 0x025D52 << 0x092D47 << 0x5C95BA << 0x0A954E; //2001-2010
|
||||
lunarCalendarTable << 0x0B4A43 << 0x4B5537 << 0x0AD54A << 0x955ABF << 0x04BA53 << 0x0A5B48 << 0x652BBC << 0x052B50 << 0x0A9345 << 0x474AB9; //2011-2020
|
||||
lunarCalendarTable << 0x06AA4C << 0x0AD541 << 0x24DAB6 << 0x04B64A << 0x69573D << 0x0A4E51 << 0x0D2646 << 0x5E933A << 0x0D534D << 0x05AA43; //2021-2030
|
||||
lunarCalendarTable << 0x36B537 << 0x096D4B << 0xB4AEBF << 0x04AD53 << 0x0A4D48 << 0x6D25BC << 0x0D254F << 0x0D5244 << 0x5DAA38 << 0x0B5A4C; //2031-2040
|
||||
lunarCalendarTable << 0x056D41 << 0x24ADB6 << 0x049B4A << 0x7A4BBE << 0x0A4B51 << 0x0AA546 << 0x5B52BA << 0x06D24E << 0x0ADA42 << 0x355B37; //2041-2050
|
||||
lunarCalendarTable << 0x09374B << 0x8497C1 << 0x049753 << 0x064B48 << 0x66A53C << 0x0EA54F << 0x06B244 << 0x4AB638 << 0x0AAE4C << 0x092E42; //2051-2060
|
||||
lunarCalendarTable << 0x3C9735 << 0x0C9649 << 0x7D4ABD << 0x0D4A51 << 0x0DA545 << 0x55AABA << 0x056A4E << 0x0A6D43 << 0x452EB7 << 0x052D4B; //2061-2070
|
||||
lunarCalendarTable << 0x8A95BF << 0x0A9553 << 0x0B4A47 << 0x6B553B << 0x0AD54F << 0x055A45 << 0x4A5D38 << 0x0A5B4C << 0x052B42 << 0x3A93B6; //2071-2080
|
||||
lunarCalendarTable << 0x069349 << 0x7729BD << 0x06AA51 << 0x0AD546 << 0x54DABA << 0x04B64E << 0x0A5743 << 0x452738 << 0x0D264A << 0x8E933E; //2081-2090
|
||||
lunarCalendarTable << 0x0D5252 << 0x0DAA47 << 0x66B53B << 0x056D4F << 0x04AE45 << 0x4A4EB9 << 0x0A4D4C << 0x0D1541 << 0x2D92B5; //2091-2099
|
||||
|
||||
//每年春节对应的公历日期
|
||||
springFestival << 130 << 217 << 206; // 1968 1969 1970
|
||||
springFestival << 127 << 215 << 203 << 123 << 211 << 131 << 218 << 207 << 128 << 216; // 1971--1980
|
||||
springFestival << 205 << 125 << 213 << 202 << 220 << 209 << 219 << 217 << 206 << 127; // 1981--1990
|
||||
springFestival << 215 << 204 << 123 << 210 << 131 << 219 << 207 << 128 << 216 << 205; // 1991--2000
|
||||
springFestival << 124 << 212 << 201 << 122 << 209 << 129 << 218 << 207 << 126 << 214; // 2001--2010
|
||||
springFestival << 203 << 123 << 210 << 131 << 219 << 208 << 128 << 216 << 205 << 125; // 2011--2020
|
||||
springFestival << 212 << 201 << 122 << 210 << 129 << 217 << 206 << 126 << 213 << 203; // 2021--2030
|
||||
springFestival << 123 << 211 << 131 << 219 << 208 << 128 << 215 << 204 << 124 << 212; // 2031--2040
|
||||
|
||||
//16--18位表示闰几月 0--12位表示农历每月的数据 高位表示1月 低位表示12月(农历闰月就会多一个月)
|
||||
lunarData << 461653 << 1386 << 2413; // 1968 1969 1970
|
||||
lunarData << 330077 << 1197 << 2637 << 268877 << 3365 << 531109 << 2900 << 2922 << 398042 << 2395; // 1971--1980
|
||||
lunarData << 1179 << 267415 << 2635 << 661067 << 1701 << 1748 << 398772 << 2742 << 2391 << 330031; // 1981--1990
|
||||
lunarData << 1175 << 1611 << 200010 << 3749 << 527717 << 1452 << 2742 << 332397 << 2350 << 3222; // 1991--2000
|
||||
lunarData << 268949 << 3402 << 3493 << 133973 << 1386 << 464219 << 605 << 2349 << 334123 << 2709; // 2001--2010
|
||||
lunarData << 2890 << 267946 << 2773 << 592565 << 1210 << 2651 << 395863 << 1323 << 2707 << 265877; // 2011--2020
|
||||
lunarData << 1706 << 2773 << 133557 << 1206 << 398510 << 2638 << 3366 << 335142 << 3411 << 1450; // 2021--2030
|
||||
lunarData << 200042 << 2413 << 723293 << 1197 << 2637 << 399947 << 3365 << 3410 << 334676 << 2906; // 2031--2040
|
||||
|
||||
//二十四节气表
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1970
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x79 << 0x69 << 0x78 << 0x77; // 1971
|
||||
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1972
|
||||
chineseTwentyFourData << 0xA5 << 0xB5 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1973
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1974
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1975
|
||||
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x89 << 0x88 << 0x78 << 0x87 << 0x87; // 1976
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1977
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 1978
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1979
|
||||
chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1980
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x77 << 0x87; // 1981
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1982
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1983
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1984
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1985
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1986
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x79 << 0x78 << 0x69 << 0x78 << 0x87; // 1987
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1988
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1989
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1990
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x86 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1991
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1992
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1993
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1994
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x76 << 0x78 << 0x69 << 0x78 << 0x87; // 1995
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1996
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1997
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1998
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1999
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2000
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2001
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2002
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2003
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2004
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2005
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2006
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2007
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2008
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2009
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2010
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2011
|
||||
chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2012
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2013
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2014
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2015
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2016
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2017
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2018
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2019
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2020
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2021
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2022
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2023
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2024
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2025
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2026
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2027
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2028
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2029
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2030
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2031
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2032
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2033
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x78 << 0x88 << 0x78 << 0x87 << 0x87; // 2034
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2035
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2036
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2037
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2038
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2039
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2040
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2041
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2042
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2043
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2044
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2045
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2046
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2047
|
||||
chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2048
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2049
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2050
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2051
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2052
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2053
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2054
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2055
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2056
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2057
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2058
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2059
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2060
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2061
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2062
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2063
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2064
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2065
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2066
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2067
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2068
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2069
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2070
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2071
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2072
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2073
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2074
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2075
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2076
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2077
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2078
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2079
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2080
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2081
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2082
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2083
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2084
|
||||
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2085
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2086
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2087
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2088
|
||||
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x96 << 0x96; // 2089
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2090
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2091
|
||||
chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2092
|
||||
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x87 << 0x96 << 0x96; // 2093
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2094
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2095
|
||||
chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2096
|
||||
chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x97 << 0x87 << 0x87 << 0x96 << 0x96; // 2097
|
||||
chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2098
|
||||
chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2099
|
||||
|
||||
//公历每月前面的天数
|
||||
monthAdd << 0 << 31 << 59 << 90 << 120 << 151 << 181 << 212 << 243 << 273 << 304 << 334;
|
||||
|
||||
//农历日期名称
|
||||
listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十"
|
||||
<< "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十"
|
||||
<< "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十";
|
||||
|
||||
//农历月份名称
|
||||
listMonthName << "*" << "正月" << "二月" << "三月" << "四月" << "五月" << "六月" << "七月" << "八月" << "九月" << "十月" << "冬月" << "腊月";
|
||||
|
||||
//二十四节气名称
|
||||
listSolarTerm << "小寒" << "大寒" << "立春" << "雨水" << "惊蛰" << "春分" << "清明" << "谷雨"
|
||||
<< "立夏" << "小满" << "芒种" << "夏至" << "小暑" << "大暑" << "立秋" << "处暑"
|
||||
<< "白露" << "秋分" << "寒露" << "霜降" << "立冬" << "小雪" << "大雪" << "冬至";
|
||||
|
||||
//天干
|
||||
listTianGan << "甲" << "乙" << "丙" << "丁" << "戊" << "己" << "庚" << "辛" << "壬" << "癸";
|
||||
|
||||
//地支
|
||||
listDiZhi << "子" << "丑" << "寅" << "卯" << "辰" << "巳" << "午" << "未" << "申" << "酉" << "戌" << "亥";
|
||||
|
||||
//属相
|
||||
listShuXiang << "鼠" << "牛" << "虎" << "兔" << "龙" << "蛇" << "马" << "羊" << "猴" << "鸡" << "狗" << "猪";
|
||||
}
|
||||
|
||||
//计算是否闰年
|
||||
bool LunarCalendarInfo::isLoopYear(int year)
|
||||
{
|
||||
return (((0 == (year % 4)) && (0 != (year % 100))) || (0 == (year % 400)));
|
||||
}
|
||||
|
||||
//计算指定年月该月共多少天
|
||||
int LunarCalendarInfo::getMonthDays(int year, int month)
|
||||
{
|
||||
int countDay = 0;
|
||||
int loopDay = isLoopYear(year) ? 1 : 0;
|
||||
|
||||
switch (month) {
|
||||
case 1:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 2:
|
||||
countDay = 28 + loopDay;
|
||||
break;
|
||||
case 3:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 4:
|
||||
countDay = 30;
|
||||
break;
|
||||
case 5:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 6:
|
||||
countDay = 30;
|
||||
break;
|
||||
case 7:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 8:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 9:
|
||||
countDay = 30;
|
||||
break;
|
||||
case 10:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 11:
|
||||
countDay = 30;
|
||||
break;
|
||||
case 12:
|
||||
countDay = 31;
|
||||
break;
|
||||
default:
|
||||
countDay = 30;
|
||||
break;
|
||||
}
|
||||
|
||||
return countDay;
|
||||
}
|
||||
|
||||
//计算指定年月对应到该月共多少天
|
||||
int LunarCalendarInfo::getTotalMonthDays(int year, int month)
|
||||
{
|
||||
int countDay = 0;
|
||||
int loopDay = isLoopYear(year) ? 1 : 0;
|
||||
|
||||
switch (month) {
|
||||
case 1:
|
||||
countDay = 0;
|
||||
break;
|
||||
case 2:
|
||||
countDay = 31;
|
||||
break;
|
||||
case 3:
|
||||
countDay = 59 + loopDay;
|
||||
break;
|
||||
case 4:
|
||||
countDay = 90 + loopDay;
|
||||
break;
|
||||
case 5:
|
||||
countDay = 120 + loopDay;
|
||||
break;
|
||||
case 6:
|
||||
countDay = 151 + loopDay;
|
||||
break;
|
||||
case 7:
|
||||
countDay = 181 + loopDay;
|
||||
break;
|
||||
case 8:
|
||||
countDay = 212 + loopDay;
|
||||
break;
|
||||
case 9:
|
||||
countDay = 243 + loopDay;
|
||||
break;
|
||||
case 10:
|
||||
countDay = 273 + loopDay;
|
||||
break;
|
||||
case 11:
|
||||
countDay = 304 + loopDay;
|
||||
break;
|
||||
case 12:
|
||||
countDay = 334 + loopDay;
|
||||
break;
|
||||
default:
|
||||
countDay = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return countDay;
|
||||
}
|
||||
|
||||
//计算指定年月对应星期几
|
||||
int LunarCalendarInfo::getFirstDayOfWeek(int year, int month)
|
||||
{
|
||||
int week = 0;
|
||||
week = (year + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400) % 7;
|
||||
week += getTotalMonthDays(year, month);
|
||||
week = week % 7;
|
||||
return week;
|
||||
}
|
||||
|
||||
//计算国际节日
|
||||
QString LunarCalendarInfo::getHoliday(int month, int day)
|
||||
{
|
||||
int temp = (month << 8) | day;
|
||||
QString strHoliday;
|
||||
|
||||
switch (temp) {
|
||||
case 0x0101:
|
||||
strHoliday = "元旦";
|
||||
break;
|
||||
case 0x020E:
|
||||
strHoliday = "情人节";
|
||||
break;
|
||||
case 0x0303:
|
||||
strHoliday = "爱耳日";
|
||||
break;
|
||||
case 0x0305:
|
||||
strHoliday = "志愿者服务日";
|
||||
break;
|
||||
case 0x0308:
|
||||
strHoliday = "妇女节";
|
||||
break;
|
||||
case 0x0309:
|
||||
strHoliday = "保护母亲河";
|
||||
break;
|
||||
case 0x030C:
|
||||
strHoliday = "植树节";
|
||||
break;
|
||||
case 0x030F:
|
||||
strHoliday = "消费者权益日";
|
||||
break;
|
||||
case 0x0401:
|
||||
strHoliday = "愚人节";
|
||||
break;
|
||||
case 0x0501:
|
||||
strHoliday = "劳动节";
|
||||
break;
|
||||
case 0x0504:
|
||||
strHoliday = "青年节";
|
||||
break;
|
||||
case 0x0601:
|
||||
strHoliday = "儿童节";
|
||||
break;
|
||||
case 0x0606:
|
||||
strHoliday = "全国爱眼日";
|
||||
break;
|
||||
case 0x0701:
|
||||
strHoliday = "建党节";
|
||||
break;
|
||||
case 0x0707:
|
||||
strHoliday = "抗战纪念日";
|
||||
break;
|
||||
case 0x0801:
|
||||
strHoliday = "建军节";
|
||||
break;
|
||||
case 0x090A:
|
||||
strHoliday = "教师节";
|
||||
break;
|
||||
case 0x0910:
|
||||
strHoliday = "脑健康日";
|
||||
break;
|
||||
case 0x0914:
|
||||
strHoliday = "爱牙日";
|
||||
break;
|
||||
case 0x0A01:
|
||||
strHoliday = "国庆节";
|
||||
break;
|
||||
case 0x0A0A:
|
||||
strHoliday = "高血压日";
|
||||
break;
|
||||
case 0x0A1C:
|
||||
strHoliday = "男性健康日";
|
||||
break;
|
||||
case 0x0B08:
|
||||
strHoliday = "记者节";
|
||||
break;
|
||||
case 0x0B09:
|
||||
strHoliday = "消防宣传日";
|
||||
break;
|
||||
case 0x0C04:
|
||||
strHoliday = "法制宣传日";
|
||||
break;
|
||||
case 0x0C18:
|
||||
strHoliday = "平安夜";
|
||||
break;
|
||||
case 0x0C19:
|
||||
strHoliday = "圣诞节";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return strHoliday;
|
||||
}
|
||||
|
||||
//计算二十四节气
|
||||
QString LunarCalendarInfo::getSolarTerms(int year, int month, int day)
|
||||
{
|
||||
QString strSolarTerms;
|
||||
int dayTemp = 0;
|
||||
//24节气对应表在1970年以后指定?
|
||||
int index = (year - 1970) * 12 + month - 1;
|
||||
if (index < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (day < 15) {
|
||||
dayTemp = 15 - day;
|
||||
if ((chineseTwentyFourData.at(index) >> 4) == dayTemp) {
|
||||
strSolarTerms = listSolarTerm.at(2 * (month - 1));
|
||||
}
|
||||
} else if (day > 15) {
|
||||
dayTemp = day - 15;
|
||||
if ((chineseTwentyFourData.at(index) & 0x0f) == dayTemp) {
|
||||
strSolarTerms = listSolarTerm.at(2 * (month - 1) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return strSolarTerms;
|
||||
}
|
||||
|
||||
//计算农历节日(必须传入农历年份月份)
|
||||
QString LunarCalendarInfo::getLunarFestival(int month, int day)
|
||||
{
|
||||
int temp = (month << 8) | day;
|
||||
QString strFestival;
|
||||
|
||||
switch (temp) {
|
||||
case 0x0101:
|
||||
strFestival = "春节";
|
||||
break;
|
||||
case 0x010F:
|
||||
strFestival = "元宵节";
|
||||
break;
|
||||
case 0x0202:
|
||||
strFestival = "龙抬头";
|
||||
break;
|
||||
case 0x0505:
|
||||
strFestival = "端午节";
|
||||
break;
|
||||
case 0x0707:
|
||||
strFestival = "七夕节";
|
||||
break;
|
||||
case 0x080F:
|
||||
strFestival = "中秋节";
|
||||
break;
|
||||
case 0x0909:
|
||||
strFestival = "重阳节";
|
||||
break;
|
||||
case 0x0C08:
|
||||
strFestival = "腊八节";
|
||||
break;
|
||||
case 0x0C1E:
|
||||
strFestival = "除夕";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return strFestival;
|
||||
}
|
||||
|
||||
//计算农历年 天干+地支+生肖
|
||||
QString LunarCalendarInfo::getLunarYear(int year)
|
||||
{
|
||||
QString strYear;
|
||||
if (year > 1924) {
|
||||
int temp = year - 1924;
|
||||
strYear.append(listTianGan.at(temp % 10));
|
||||
strYear.append(listDiZhi.at(temp % 12));
|
||||
strYear.append(listShuXiang.at(temp % 12));
|
||||
}
|
||||
|
||||
return strYear;
|
||||
}
|
||||
|
||||
void LunarCalendarInfo::getLunarCalendarInfo(int year, int month, int day,
|
||||
QString &strHoliday,
|
||||
QString &strSolarTerms,
|
||||
QString &strLunarFestival,
|
||||
QString &strLunarYear,
|
||||
QString &strLunarMonth,
|
||||
QString &strLunarDay)
|
||||
{
|
||||
//过滤不在范围内的年月日
|
||||
if (year < 1901 || year > 2099 || month < 1 || month > 12 || day < 1 || day > 31) {
|
||||
return;
|
||||
}
|
||||
|
||||
strHoliday = getHoliday(month, day);
|
||||
strSolarTerms = getSolarTerms(year, month, day);
|
||||
|
||||
#ifndef year_2099
|
||||
//现在计算农历:获得当年春节的公历日期(比如:2015年春节日期为(2月19日))
|
||||
//以此为分界点,2.19前面的农历是2014年农历(用2014年农历数据来计算)
|
||||
//2.19以及之后的日期,农历为2015年农历(用2015年农历数据来计算)
|
||||
int temp, tempYear, tempMonth, isEnd, k, n;
|
||||
tempMonth = year - 1968;
|
||||
int springFestivalMonth = springFestival.at(tempMonth) / 100;
|
||||
int springFestivalDaty = springFestival.at(tempMonth) % 100;
|
||||
|
||||
if (month < springFestivalMonth) {
|
||||
tempMonth--;
|
||||
tempYear = 365 * 1 + day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
|
||||
|
||||
if ((!(year % 4)) && (month > 2)) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
|
||||
if ((!((year - 1) % 4))) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
} else if (month == springFestivalMonth) {
|
||||
if (day < springFestivalDaty) {
|
||||
tempMonth--;
|
||||
tempYear = 365 * 1 + day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
|
||||
|
||||
if ((!(year % 4)) && (month > 2)) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
|
||||
if ((!((year - 1) % 4))) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
} else {
|
||||
tempYear = day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
|
||||
|
||||
if ((!(year % 4)) && (month > 2)) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tempYear = day + monthAdd.at(month - 1) - 31 * ((springFestival.at(tempMonth) / 100) - 1) - springFestival.at(tempMonth) % 100 + 1;
|
||||
|
||||
if ((!(year % 4)) && (month > 2)) {
|
||||
tempYear = tempYear + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//计算农历天干地支月日
|
||||
isEnd = 0;
|
||||
while (isEnd != 1) {
|
||||
if (lunarData.at(tempMonth) < 4095) {
|
||||
k = 11;
|
||||
} else {
|
||||
k = 12;
|
||||
}
|
||||
|
||||
n = k;
|
||||
|
||||
while (n >= 0) {
|
||||
temp = lunarData.at(tempMonth);
|
||||
temp = temp >> n;
|
||||
temp = temp % 2;
|
||||
|
||||
if (tempYear <= (29 + temp)) {
|
||||
isEnd = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
tempYear = tempYear - 29 - temp;
|
||||
n = n - 1;
|
||||
}
|
||||
|
||||
if (isEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
tempMonth = tempMonth + 1;
|
||||
}
|
||||
|
||||
//农历的年月日
|
||||
year = 1969 + tempMonth - 1;
|
||||
month = k - n + 1;
|
||||
day = tempYear;
|
||||
|
||||
if (k == 12) {
|
||||
if (month == (lunarData.at(tempMonth) / 65536) + 1) {
|
||||
month = 1 - month;
|
||||
} else if (month > (lunarData.at(tempMonth) / 65536) + 1) {
|
||||
month = month - 1;
|
||||
}
|
||||
}
|
||||
|
||||
strLunarYear = getLunarYear(year);
|
||||
|
||||
if (month < 1 && (1 == day)) {
|
||||
month = month * -1;
|
||||
strLunarMonth = "闰" + listMonthName.at(month);
|
||||
} else {
|
||||
strLunarMonth = listMonthName.at(month);
|
||||
}
|
||||
|
||||
strLunarDay = listDayName.at(day);
|
||||
strLunarFestival = getLunarFestival(month, day);
|
||||
#else
|
||||
//记录春节离当年元旦的天数
|
||||
int springOffset = 0;
|
||||
//记录阳历日离当年元旦的天数
|
||||
int newYearOffset = 0;
|
||||
//记录大小月的天数 29或30
|
||||
int monthCount = 0;
|
||||
|
||||
if (((lunarCalendarTable.at(year - 1901) & 0x0060) >> 5) == 1) {
|
||||
springOffset = (lunarCalendarTable.at(year - 1901) & 0x001F) - 1;
|
||||
} else {
|
||||
springOffset = (lunarCalendarTable.at(year - 1901) & 0x001F) - 1 + 31;
|
||||
}
|
||||
|
||||
//如果是不闰年且不是2月份 +1
|
||||
newYearOffset = monthAdd.at(month - 1) + day - 1;
|
||||
if ((!(year % 4)) && (month > 2)) {
|
||||
newYearOffset++;
|
||||
}
|
||||
|
||||
//记录从哪个月开始来计算
|
||||
int index = 0;
|
||||
//用来对闰月的特殊处理
|
||||
int flag = 0;
|
||||
|
||||
//判断阳历日在春节前还是春节后,计算农历的月/日
|
||||
if (newYearOffset >= springOffset) {
|
||||
newYearOffset -= springOffset;
|
||||
month = 1;
|
||||
index = 1;
|
||||
flag = 0;
|
||||
|
||||
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
|
||||
monthCount = 29;
|
||||
} else {
|
||||
monthCount = 30;
|
||||
}
|
||||
|
||||
while (newYearOffset >= monthCount) {
|
||||
newYearOffset -= monthCount;
|
||||
index++;
|
||||
if (month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) {
|
||||
flag = ~flag;
|
||||
if (flag == 0) {
|
||||
month++;
|
||||
}
|
||||
} else {
|
||||
month++;
|
||||
}
|
||||
|
||||
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
|
||||
monthCount = 29;
|
||||
} else {
|
||||
monthCount = 30;
|
||||
}
|
||||
}
|
||||
|
||||
day = newYearOffset + 1;
|
||||
} else {
|
||||
springOffset -= newYearOffset;
|
||||
year--;
|
||||
month = 12;
|
||||
flag = 0;
|
||||
|
||||
if (((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20) == 0) {
|
||||
index = 12;
|
||||
} else {
|
||||
index = 13;
|
||||
}
|
||||
|
||||
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
|
||||
monthCount = 29;
|
||||
} else {
|
||||
monthCount = 30;
|
||||
}
|
||||
|
||||
while (springOffset > monthCount) {
|
||||
springOffset -= monthCount;
|
||||
index--;
|
||||
|
||||
if (flag == 0) {
|
||||
month--;
|
||||
}
|
||||
|
||||
if (month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) {
|
||||
flag = ~flag;
|
||||
}
|
||||
|
||||
if ((lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) {
|
||||
monthCount = 29;
|
||||
} else {
|
||||
monthCount = 30;
|
||||
}
|
||||
}
|
||||
|
||||
day = monthCount - springOffset + 1;
|
||||
}
|
||||
|
||||
//计算农历的索引配置
|
||||
int temp = 0;
|
||||
temp |= day;
|
||||
temp |= (month << 6);
|
||||
|
||||
//转换农历的年月
|
||||
month = (temp & 0x3C0) >> 6;
|
||||
day = temp & 0x3F;
|
||||
|
||||
strLunarYear = getLunarYear(year);
|
||||
|
||||
if ((month == ((lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) && (1 == day)) {
|
||||
strLunarMonth = "闰" + listMonthName.at(month);
|
||||
} else {
|
||||
strLunarMonth = listMonthName.at(month);
|
||||
}
|
||||
|
||||
strLunarDay = listDayName.at(day);
|
||||
strLunarFestival = getLunarFestival(month, day);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString LunarCalendarInfo::getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo)
|
||||
{
|
||||
QString strHoliday, strSolarTerms, strLunarFestival, strLunarYear, strLunarMonth, strLunarDay;
|
||||
|
||||
LunarCalendarInfo::Instance()->getLunarCalendarInfo(year, month, day,
|
||||
strHoliday, strSolarTerms, strLunarFestival,
|
||||
strLunarYear, strLunarMonth, strLunarDay);
|
||||
|
||||
//农历节日优先,其次农历节气,然后公历节日,最后才是农历月份名称
|
||||
if (!strLunarFestival.isEmpty()) {
|
||||
strLunarDay = strLunarFestival;
|
||||
} else if (!strSolarTerms.isEmpty()) {
|
||||
strLunarDay = strSolarTerms;
|
||||
} else if (!strHoliday.isEmpty()) {
|
||||
strLunarDay = strHoliday;
|
||||
}
|
||||
|
||||
QString info = QString("%1%2%3")
|
||||
.arg(yearInfo ? strLunarYear + "年" : "")
|
||||
.arg(monthInfo ? strLunarMonth : "")
|
||||
.arg(dayInfo ? strLunarDay : "");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
QString LunarCalendarInfo::getLunarYearMonthDay(int year, int month, int day)
|
||||
{
|
||||
return getLunarInfo(year, month, day, true, true, true);
|
||||
}
|
||||
|
||||
QString LunarCalendarInfo::getLunarMonthDay(int year, int month, int day)
|
||||
{
|
||||
return getLunarInfo(year, month, day, false, true, true);
|
||||
}
|
||||
|
||||
QString LunarCalendarInfo::getLunarDay(int year, int month, int day)
|
||||
{
|
||||
return getLunarInfo(year, month, day, false, false, true);
|
||||
}
|
||||
84
widget/lunarcalendarwidget/lunarcalendarinfo.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef LUNARCALENDARINFO_H
|
||||
#define LUNARCALENDARINFO_H
|
||||
|
||||
/**
|
||||
* 农历信息类 作者:倪大侠 整理:feiyangqingyun(QQ:517216493) 2016-12-10
|
||||
* 1. 计算是否闰年。
|
||||
* 2. 计算国际节日。
|
||||
* 3. 计算二十四节气。
|
||||
* 4. 计算农历年 天干、地支、生肖。
|
||||
* 5. 计算指定年月日农历信息,包括公历节日和农历节日及二十四节气。
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT LunarCalendarInfo : public QObject
|
||||
#else
|
||||
class LunarCalendarInfo : public QObject
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static LunarCalendarInfo *Instance();
|
||||
explicit LunarCalendarInfo(QObject *parent = 0);
|
||||
|
||||
//计算是否闰年
|
||||
bool isLoopYear(int year);
|
||||
|
||||
//计算指定年月该月共多少天
|
||||
int getMonthDays(int year, int month);
|
||||
|
||||
//计算指定年月对应到该月共多少天
|
||||
int getTotalMonthDays(int year, int month);
|
||||
|
||||
//计算指定年月对应星期几
|
||||
int getFirstDayOfWeek(int year, int month);
|
||||
|
||||
//计算国际节日
|
||||
QString getHoliday(int month, int day);
|
||||
|
||||
//计算二十四节气
|
||||
QString getSolarTerms(int year, int month, int day);
|
||||
|
||||
//计算农历节日(必须传入农历年份月份)
|
||||
QString getLunarFestival(int month, int day);
|
||||
|
||||
//计算农历年 天干+地支+生肖
|
||||
QString getLunarYear(int year);
|
||||
|
||||
//计算指定年月日农历信息,包括公历节日和农历节日及二十四节气
|
||||
void getLunarCalendarInfo(int year, int month, int day,
|
||||
QString &strHoliday,
|
||||
QString &strSolarTerms,
|
||||
QString &strLunarFestival,
|
||||
QString &strLunarYear,
|
||||
QString &strLunarMonth,
|
||||
QString &strLunarDay);
|
||||
|
||||
//获取指定年月日农历信息
|
||||
QString getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo);
|
||||
QString getLunarYearMonthDay(int year, int month, int day);
|
||||
QString getLunarMonthDay(int year, int month, int day);
|
||||
QString getLunarDay(int year, int month, int day);
|
||||
|
||||
private:
|
||||
static QScopedPointer<LunarCalendarInfo> self;
|
||||
|
||||
QList<int> lunarCalendarTable; //农历年表
|
||||
QList<int> springFestival; //春节公历日期
|
||||
QList<int> lunarData; //农历每月数据
|
||||
QList<int> chineseTwentyFourData; //农历二十四节气数据
|
||||
QList<int> monthAdd; //公历每月前面的天数
|
||||
|
||||
QList<QString> listDayName; //农历日期名称集合
|
||||
QList<QString> listMonthName; //农历月份名称集合
|
||||
QList<QString> listSolarTerm; //二十四节气名称集合
|
||||
|
||||
QList<QString> listTianGan; //天干名称集合
|
||||
QList<QString> listDiZhi; //地支名称集合
|
||||
QList<QString> listShuXiang; //属相名称集合
|
||||
};
|
||||
|
||||
#endif // LUNARCALENDARINFO_H
|
||||
550
widget/lunarcalendarwidget/lunarcalendaritem.cpp
Normal file
@@ -0,0 +1,550 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "lunarcalendaritem.h"
|
||||
#include "qpainter.h"
|
||||
#include "qevent.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
LunarCalendarItem::LunarCalendarItem(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
hover = false;
|
||||
pressed = false;
|
||||
listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十"
|
||||
<< "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十"
|
||||
<< "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十";
|
||||
|
||||
select = false;
|
||||
showLunar = true;
|
||||
bgImage = ":/image/bg_calendar.png";
|
||||
selectType = SelectType_Rect;
|
||||
|
||||
date = QDate::currentDate();
|
||||
lunar = "初一";
|
||||
dayType = DayType_MonthCurrent;
|
||||
|
||||
borderColor = QColor(180, 180, 180);
|
||||
weekColor = QColor(255, 0, 0);
|
||||
superColor = QColor(255, 129, 6);
|
||||
lunarColor = QColor(55, 156, 238);
|
||||
|
||||
currentTextColor = QColor(0, 0, 0);
|
||||
otherTextColor = QColor(200, 200, 200);
|
||||
selectTextColor = QColor(255, 255, 255);
|
||||
hoverTextColor = QColor(250, 250, 250);
|
||||
|
||||
currentLunarColor = QColor(150, 150, 150);
|
||||
otherLunarColor = QColor(200, 200, 200);
|
||||
selectLunarColor = QColor(255, 255, 255);
|
||||
hoverLunarColor = QColor(250, 250, 250);
|
||||
|
||||
currentBgColor = QColor(255, 255, 255);
|
||||
otherBgColor = QColor(240, 240, 240);
|
||||
selectBgColor = QColor(208, 47, 18);
|
||||
hoverBgColor = QColor(204, 183, 180);
|
||||
}
|
||||
|
||||
void LunarCalendarItem::enterEvent(QEvent *)
|
||||
{
|
||||
hover = true;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::leaveEvent(QEvent *)
|
||||
{
|
||||
hover = false;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::mousePressEvent(QMouseEvent *)
|
||||
{
|
||||
pressed = true;
|
||||
this->update();
|
||||
|
||||
emit clicked(date, dayType);
|
||||
}
|
||||
|
||||
void LunarCalendarItem::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
pressed = false;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::paintEvent(QPaintEvent *)
|
||||
{
|
||||
//绘制准备工作,启用反锯齿
|
||||
QPainter painter(this);
|
||||
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
|
||||
|
||||
//绘制背景和边框
|
||||
drawBg(&painter);
|
||||
|
||||
//优先绘制选中状态,其次绘制悬停状态
|
||||
if (select) {
|
||||
drawBgCurrent(&painter, selectBgColor);
|
||||
} else if (hover) {
|
||||
drawBgCurrent(&painter, hoverBgColor);
|
||||
}
|
||||
|
||||
//绘制日期
|
||||
drawDay(&painter);
|
||||
|
||||
//绘制农历信息
|
||||
drawLunar(&painter);
|
||||
}
|
||||
|
||||
void LunarCalendarItem::drawBg(QPainter *painter)
|
||||
{
|
||||
painter->save();
|
||||
|
||||
//根据当前类型选择对应的颜色
|
||||
QColor bgColor = currentBgColor;
|
||||
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
|
||||
bgColor = otherBgColor;
|
||||
}
|
||||
|
||||
painter->setPen(borderColor);
|
||||
painter->setBrush(bgColor);
|
||||
painter->drawRect(rect());
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::drawBgCurrent(QPainter *painter, const QColor &color)
|
||||
{
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
int side = qMin(width, height);
|
||||
|
||||
painter->save();
|
||||
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(color);
|
||||
|
||||
//根据设定绘制背景样式
|
||||
if (selectType == SelectType_Rect) {
|
||||
painter->drawRect(rect());
|
||||
} else if (selectType == SelectType_Circle) {
|
||||
int radius = side / 2 - 3;
|
||||
painter->drawEllipse(QPointF(width / 2, height / 2), radius, radius);
|
||||
} else if (selectType == SelectType_Triangle) {
|
||||
int radius = side / 3;
|
||||
QPolygon pts;
|
||||
pts.setPoints(3, 1, 1, radius, 1, 1, radius);
|
||||
painter->drawRect(rect());
|
||||
painter->setBrush(superColor);
|
||||
painter->drawConvexPolygon(pts);
|
||||
} else if (selectType == SelectType_Image) {
|
||||
//等比例缩放居中绘制
|
||||
QImage img(bgImage);
|
||||
if (!img.isNull()) {
|
||||
img = img.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
int x = (width - img.width()) / 2;
|
||||
int y = (height - img.height()) / 2;
|
||||
painter->drawImage(x, y, img);
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::drawDay(QPainter *painter)
|
||||
{
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
int side = qMin(width, height);
|
||||
|
||||
painter->save();
|
||||
|
||||
//根据当前类型选择对应的颜色
|
||||
QColor color = currentTextColor;
|
||||
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
|
||||
color = otherTextColor;
|
||||
} else if (dayType == DayType_WeekEnd) {
|
||||
color = weekColor;
|
||||
}
|
||||
|
||||
if (select) {
|
||||
color = selectTextColor;
|
||||
} else if (hover) {
|
||||
color = hoverTextColor;
|
||||
}
|
||||
|
||||
painter->setPen(color);
|
||||
|
||||
if (showLunar) {
|
||||
QFont font;
|
||||
font.setPixelSize(side / 2.7);
|
||||
painter->setFont(font);
|
||||
|
||||
QRect dayRect = QRect(0, 0, width, height / 1.7);
|
||||
painter->drawText(dayRect, Qt::AlignHCenter | Qt::AlignBottom, QString::number(date.day()));
|
||||
} else {
|
||||
QFont font;
|
||||
font.setPixelSize(side / 2);
|
||||
painter->setFont(font);
|
||||
|
||||
QRect dayRect = QRect(0, 0, width, height);
|
||||
painter->drawText(dayRect, Qt::AlignCenter, QString::number(date.day()));
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::drawLunar(QPainter *painter)
|
||||
{
|
||||
if (!showLunar) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
int side = qMin(width, height);
|
||||
|
||||
painter->save();
|
||||
|
||||
//判断当前农历文字是否节日,是节日且是当月则用农历节日颜色显示
|
||||
bool exist = (!listDayName.contains(lunar) && dayType != DayType_MonthPre && dayType != DayType_MonthNext);
|
||||
|
||||
//根据当前类型选择对应的颜色
|
||||
QColor color = currentLunarColor;
|
||||
if (dayType == DayType_MonthPre || dayType == DayType_MonthNext) {
|
||||
color = otherLunarColor;
|
||||
}
|
||||
|
||||
if (select) {
|
||||
color = selectTextColor;
|
||||
} else if (hover) {
|
||||
color = hoverTextColor;
|
||||
} else if (exist) {
|
||||
color = lunarColor;
|
||||
}
|
||||
|
||||
painter->setPen(color);
|
||||
|
||||
QFont font;
|
||||
font.setPixelSize(side / 5);
|
||||
painter->setFont(font);
|
||||
|
||||
QRect lunarRect(0, height / 2, width, height / 2);
|
||||
painter->drawText(lunarRect, Qt::AlignCenter, lunar);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool LunarCalendarItem::getSelect() const
|
||||
{
|
||||
return this->select;
|
||||
}
|
||||
|
||||
bool LunarCalendarItem::getShowLunar() const
|
||||
{
|
||||
return this->showLunar;
|
||||
}
|
||||
|
||||
QString LunarCalendarItem::getBgImage() const
|
||||
{
|
||||
return this->bgImage;
|
||||
}
|
||||
|
||||
LunarCalendarItem::SelectType LunarCalendarItem::getSelectType() const
|
||||
{
|
||||
return this->selectType;
|
||||
}
|
||||
|
||||
QDate LunarCalendarItem::getDate() const
|
||||
{
|
||||
return this->date;
|
||||
}
|
||||
|
||||
QString LunarCalendarItem::getLunar() const
|
||||
{
|
||||
return this->lunar;
|
||||
}
|
||||
|
||||
LunarCalendarItem::DayType LunarCalendarItem::getDayType() const
|
||||
{
|
||||
return this->dayType;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getBorderColor() const
|
||||
{
|
||||
return this->borderColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getWeekColor() const
|
||||
{
|
||||
return this->weekColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getSuperColor() const
|
||||
{
|
||||
return this->superColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getLunarColor() const
|
||||
{
|
||||
return this->lunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getCurrentTextColor() const
|
||||
{
|
||||
return this->currentTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getOtherTextColor() const
|
||||
{
|
||||
return this->otherTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getSelectTextColor() const
|
||||
{
|
||||
return this->selectTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getHoverTextColor() const
|
||||
{
|
||||
return this->hoverTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getCurrentLunarColor() const
|
||||
{
|
||||
return this->currentLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getOtherLunarColor() const
|
||||
{
|
||||
return this->otherLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getSelectLunarColor() const
|
||||
{
|
||||
return this->selectLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getHoverLunarColor() const
|
||||
{
|
||||
return this->hoverLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getCurrentBgColor() const
|
||||
{
|
||||
return this->currentBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getOtherBgColor() const
|
||||
{
|
||||
return this->otherBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getSelectBgColor() const
|
||||
{
|
||||
return this->selectBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarItem::getHoverBgColor() const
|
||||
{
|
||||
return this->hoverBgColor;
|
||||
}
|
||||
|
||||
QSize LunarCalendarItem::sizeHint() const
|
||||
{
|
||||
return QSize(100, 100);
|
||||
}
|
||||
|
||||
QSize LunarCalendarItem::minimumSizeHint() const
|
||||
{
|
||||
return QSize(20, 20);
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSelect(bool select)
|
||||
{
|
||||
if (this->select != select) {
|
||||
this->select = select;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setShowLunar(bool showLunar)
|
||||
{
|
||||
if (this->showLunar != showLunar) {
|
||||
this->showLunar = showLunar;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setBgImage(const QString &bgImage)
|
||||
{
|
||||
if (this->bgImage != bgImage) {
|
||||
this->bgImage = bgImage;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSelectType(const LunarCalendarItem::SelectType &selectType)
|
||||
{
|
||||
if (this->selectType != selectType) {
|
||||
this->selectType = selectType;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setDate(const QDate &date)
|
||||
{
|
||||
if (this->date != date) {
|
||||
this->date = date;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setLunar(const QString &lunar)
|
||||
{
|
||||
if (this->lunar != lunar) {
|
||||
this->lunar = lunar;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setDayType(const LunarCalendarItem::DayType &dayType)
|
||||
{
|
||||
if (this->dayType != dayType) {
|
||||
this->dayType = dayType;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setDate(const QDate &date, const QString &lunar, const DayType &dayType)
|
||||
{
|
||||
this->date = date;
|
||||
this->lunar = lunar;
|
||||
this->dayType = dayType;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setBorderColor(const QColor &borderColor)
|
||||
{
|
||||
if (this->borderColor != borderColor) {
|
||||
this->borderColor = borderColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setWeekColor(const QColor &weekColor)
|
||||
{
|
||||
if (this->weekColor != weekColor) {
|
||||
this->weekColor = weekColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSuperColor(const QColor &superColor)
|
||||
{
|
||||
if (this->superColor != superColor) {
|
||||
this->superColor = superColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setLunarColor(const QColor &lunarColor)
|
||||
{
|
||||
if (this->lunarColor != lunarColor) {
|
||||
this->lunarColor = lunarColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setCurrentTextColor(const QColor ¤tTextColor)
|
||||
{
|
||||
if (this->currentTextColor != currentTextColor) {
|
||||
this->currentTextColor = currentTextColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setOtherTextColor(const QColor &otherTextColor)
|
||||
{
|
||||
if (this->otherTextColor != otherTextColor) {
|
||||
this->otherTextColor = otherTextColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSelectTextColor(const QColor &selectTextColor)
|
||||
{
|
||||
if (this->selectTextColor != selectTextColor) {
|
||||
this->selectTextColor = selectTextColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setHoverTextColor(const QColor &hoverTextColor)
|
||||
{
|
||||
if (this->hoverTextColor != hoverTextColor) {
|
||||
this->hoverTextColor = hoverTextColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setCurrentLunarColor(const QColor ¤tLunarColor)
|
||||
{
|
||||
if (this->currentLunarColor != currentLunarColor) {
|
||||
this->currentLunarColor = currentLunarColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setOtherLunarColor(const QColor &otherLunarColor)
|
||||
{
|
||||
if (this->otherLunarColor != otherLunarColor) {
|
||||
this->otherLunarColor = otherLunarColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSelectLunarColor(const QColor &selectLunarColor)
|
||||
{
|
||||
if (this->selectLunarColor != selectLunarColor) {
|
||||
this->selectLunarColor = selectLunarColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setHoverLunarColor(const QColor &hoverLunarColor)
|
||||
{
|
||||
if (this->hoverLunarColor != hoverLunarColor) {
|
||||
this->hoverLunarColor = hoverLunarColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setCurrentBgColor(const QColor ¤tBgColor)
|
||||
{
|
||||
if (this->currentBgColor != currentBgColor) {
|
||||
this->currentBgColor = currentBgColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setOtherBgColor(const QColor &otherBgColor)
|
||||
{
|
||||
if (this->otherBgColor != otherBgColor) {
|
||||
this->otherBgColor = otherBgColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setSelectBgColor(const QColor &selectBgColor)
|
||||
{
|
||||
if (this->selectBgColor != selectBgColor) {
|
||||
this->selectBgColor = selectBgColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarItem::setHoverBgColor(const QColor &hoverBgColor)
|
||||
{
|
||||
if (this->hoverBgColor != hoverBgColor) {
|
||||
this->hoverBgColor = hoverBgColor;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
201
widget/lunarcalendarwidget/lunarcalendaritem.h
Normal file
@@ -0,0 +1,201 @@
|
||||
#ifndef LUNARCALENDARITEM_H
|
||||
#define LUNARCALENDARITEM_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDate>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT LunarCalendarItem : public QWidget
|
||||
#else
|
||||
class LunarCalendarItem : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(DayType)
|
||||
Q_ENUMS(SelectType)
|
||||
|
||||
Q_PROPERTY(bool select READ getSelect WRITE setSelect)
|
||||
Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar)
|
||||
Q_PROPERTY(QString bgImage READ getBgImage WRITE setBgImage)
|
||||
Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType)
|
||||
|
||||
Q_PROPERTY(QDate date READ getDate WRITE setDate)
|
||||
Q_PROPERTY(QString lunar READ getLunar WRITE setLunar)
|
||||
Q_PROPERTY(DayType dayType READ getDayType WRITE setDayType)
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor)
|
||||
Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor)
|
||||
Q_PROPERTY(QColor superColor READ getSuperColor WRITE setSuperColor)
|
||||
Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor)
|
||||
|
||||
Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor)
|
||||
Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor)
|
||||
Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor)
|
||||
Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor)
|
||||
|
||||
Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor)
|
||||
Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor)
|
||||
Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor)
|
||||
Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor)
|
||||
|
||||
Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor)
|
||||
Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor)
|
||||
Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor)
|
||||
Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor)
|
||||
|
||||
public:
|
||||
enum DayType {
|
||||
DayType_MonthPre = 0, //上月剩余天数
|
||||
DayType_MonthNext = 1, //下个月的天数
|
||||
DayType_MonthCurrent = 2, //当月天数
|
||||
DayType_WeekEnd = 3 //周末
|
||||
};
|
||||
|
||||
enum SelectType {
|
||||
SelectType_Rect = 0, //矩形背景
|
||||
SelectType_Circle = 1, //圆形背景
|
||||
SelectType_Triangle = 2, //带三角标
|
||||
SelectType_Image = 3 //图片背景
|
||||
};
|
||||
|
||||
explicit LunarCalendarItem(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEvent *);
|
||||
void leaveEvent(QEvent *);
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
void mouseReleaseEvent(QMouseEvent *);
|
||||
void paintEvent(QPaintEvent *);
|
||||
void drawBg(QPainter *painter);
|
||||
void drawBgCurrent(QPainter *painter, const QColor &color);
|
||||
void drawDay(QPainter *painter);
|
||||
void drawLunar(QPainter *painter);
|
||||
|
||||
private:
|
||||
bool hover; //鼠标是否悬停
|
||||
bool pressed; //鼠标是否按下
|
||||
QStringList listDayName; //农历日期
|
||||
|
||||
bool select; //是否选中
|
||||
bool showLunar; //显示农历
|
||||
QString bgImage; //背景图片
|
||||
SelectType selectType; //选中模式
|
||||
|
||||
QDate date; //当前日期
|
||||
QString lunar; //农历信息
|
||||
DayType dayType; //当前日类型
|
||||
|
||||
QColor borderColor; //边框颜色
|
||||
QColor weekColor; //周末颜色
|
||||
QColor superColor; //角标颜色
|
||||
QColor lunarColor; //农历节日颜色
|
||||
|
||||
QColor currentTextColor; //当前月文字颜色
|
||||
QColor otherTextColor; //其他月文字颜色
|
||||
QColor selectTextColor; //选中日期文字颜色
|
||||
QColor hoverTextColor; //悬停日期文字颜色
|
||||
|
||||
QColor currentLunarColor; //当前月农历文字颜色
|
||||
QColor otherLunarColor; //其他月农历文字颜色
|
||||
QColor selectLunarColor; //选中日期农历文字颜色
|
||||
QColor hoverLunarColor; //悬停日期农历文字颜色
|
||||
|
||||
QColor currentBgColor; //当前月背景颜色
|
||||
QColor otherBgColor; //其他月背景颜色
|
||||
QColor selectBgColor; //选中日期背景颜色
|
||||
QColor hoverBgColor; //悬停日期背景颜色
|
||||
|
||||
public:
|
||||
bool getSelect() const;
|
||||
bool getShowLunar() const;
|
||||
QString getBgImage() const;
|
||||
SelectType getSelectType() const;
|
||||
|
||||
QDate getDate() const;
|
||||
QString getLunar() const;
|
||||
DayType getDayType() const;
|
||||
|
||||
QColor getBorderColor() const;
|
||||
QColor getWeekColor() const;
|
||||
QColor getSuperColor() const;
|
||||
QColor getLunarColor() const;
|
||||
|
||||
QColor getCurrentTextColor() const;
|
||||
QColor getOtherTextColor() const;
|
||||
QColor getSelectTextColor() const;
|
||||
QColor getHoverTextColor() const;
|
||||
|
||||
QColor getCurrentLunarColor() const;
|
||||
QColor getOtherLunarColor() const;
|
||||
QColor getSelectLunarColor() const;
|
||||
QColor getHoverLunarColor() const;
|
||||
|
||||
QColor getCurrentBgColor() const;
|
||||
QColor getOtherBgColor() const;
|
||||
QColor getSelectBgColor() const;
|
||||
QColor getHoverBgColor() const;
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置是否选中
|
||||
void setSelect(bool select);
|
||||
//设置是否显示农历信息
|
||||
void setShowLunar(bool showLunar);
|
||||
//设置背景图片
|
||||
void setBgImage(const QString &bgImage);
|
||||
//设置选中背景样式
|
||||
void setSelectType(const SelectType &selectType);
|
||||
|
||||
//设置日期
|
||||
void setDate(const QDate &date);
|
||||
//设置农历
|
||||
void setLunar(const QString &lunar);
|
||||
//设置类型
|
||||
void setDayType(const DayType &dayType);
|
||||
//设置日期/农历/类型
|
||||
void setDate(const QDate &date, const QString &lunar, const DayType &dayType);
|
||||
|
||||
//设置边框颜色
|
||||
void setBorderColor(const QColor &borderColor);
|
||||
//设置周末颜色
|
||||
void setWeekColor(const QColor &weekColor);
|
||||
//设置角标颜色
|
||||
void setSuperColor(const QColor &superColor);
|
||||
//设置农历节日颜色
|
||||
void setLunarColor(const QColor &lunarColor);
|
||||
|
||||
//设置当前月文字颜色
|
||||
void setCurrentTextColor(const QColor ¤tTextColor);
|
||||
//设置其他月文字颜色
|
||||
void setOtherTextColor(const QColor &otherTextColor);
|
||||
//设置选中日期文字颜色
|
||||
void setSelectTextColor(const QColor &selectTextColor);
|
||||
//设置悬停日期文字颜色
|
||||
void setHoverTextColor(const QColor &hoverTextColor);
|
||||
|
||||
//设置当前月农历文字颜色
|
||||
void setCurrentLunarColor(const QColor ¤tLunarColor);
|
||||
//设置其他月农历文字颜色
|
||||
void setOtherLunarColor(const QColor &otherLunarColor);
|
||||
//设置选中日期农历文字颜色
|
||||
void setSelectLunarColor(const QColor &selectLunarColor);
|
||||
//设置悬停日期农历文字颜色
|
||||
void setHoverLunarColor(const QColor &hoverLunarColor);
|
||||
|
||||
//设置当前月背景颜色
|
||||
void setCurrentBgColor(const QColor ¤tBgColor);
|
||||
//设置其他月背景颜色
|
||||
void setOtherBgColor(const QColor &otherBgColor);
|
||||
//设置选中日期背景颜色
|
||||
void setSelectBgColor(const QColor &selectBgColor);
|
||||
//设置悬停日期背景颜色
|
||||
void setHoverBgColor(const QColor &hoverBgColor);
|
||||
|
||||
Q_SIGNALS:
|
||||
void clicked(const QDate &date, const LunarCalendarItem::DayType &dayType);
|
||||
};
|
||||
|
||||
#endif // LUNARCALENDARITEM_H
|
||||
835
widget/lunarcalendarwidget/lunarcalendarwidget.cpp
Normal file
@@ -0,0 +1,835 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "lunarcalendarwidget.h"
|
||||
#include "qfontdatabase.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qlayout.h"
|
||||
#include "qlabel.h"
|
||||
#include "qpushbutton.h"
|
||||
#include "qtoolbutton.h"
|
||||
#include "qcombobox.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
LunarCalendarWidget::LunarCalendarWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
//判断图形字体是否存在,不存在则加入
|
||||
QFontDatabase fontDb;
|
||||
if (!fontDb.families().contains("FontAwesome")) {
|
||||
int fontId = fontDb.addApplicationFont(":/font/fontawesome-webfont.ttf");
|
||||
QStringList fontName = fontDb.applicationFontFamilies(fontId);
|
||||
if (fontName.count() == 0) {
|
||||
qDebug() << "load fontawesome-webfont.ttf error";
|
||||
}
|
||||
}
|
||||
|
||||
if (fontDb.families().contains("FontAwesome")) {
|
||||
iconFont = QFont("FontAwesome");
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))
|
||||
iconFont.setHintingPreference(QFont::PreferNoHinting);
|
||||
#endif
|
||||
}
|
||||
|
||||
btnClick = false;
|
||||
|
||||
calendarStyle = CalendarStyle_Red;
|
||||
weekNameFormat = WeekNameFormat_Short;
|
||||
date = QDate::currentDate();
|
||||
|
||||
weekTextColor = QColor(255, 255, 255);
|
||||
weekBgColor = QColor(22, 160, 134);
|
||||
|
||||
showLunar = true;
|
||||
bgImage = ":/image/bg_calendar.png";
|
||||
selectType = SelectType_Rect;
|
||||
|
||||
borderColor = QColor(180, 180, 180);
|
||||
weekColor = QColor(255, 0, 0);
|
||||
superColor = QColor(255, 129, 6);
|
||||
lunarColor = QColor(55, 156, 238);
|
||||
|
||||
currentTextColor = QColor(0, 0, 0);
|
||||
otherTextColor = QColor(200, 200, 200);
|
||||
selectTextColor = QColor(255, 255, 255);
|
||||
hoverTextColor = QColor(250, 250, 250);
|
||||
|
||||
currentLunarColor = QColor(150, 150, 150);
|
||||
otherLunarColor = QColor(200, 200, 200);
|
||||
selectLunarColor = QColor(255, 255, 255);
|
||||
hoverLunarColor = QColor(250, 250, 250);
|
||||
|
||||
currentBgColor = QColor(255, 255, 255);
|
||||
otherBgColor = QColor(240, 240, 240);
|
||||
selectBgColor = QColor(208, 47, 18);
|
||||
hoverBgColor = QColor(204, 183, 180);
|
||||
|
||||
initWidget();
|
||||
initStyle();
|
||||
initDate();
|
||||
}
|
||||
|
||||
LunarCalendarWidget::~LunarCalendarWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::initWidget()
|
||||
{
|
||||
setObjectName("lunarCalendarWidget");
|
||||
|
||||
//顶部widget
|
||||
QWidget *widgetTop = new QWidget;
|
||||
widgetTop->setObjectName("widgetTop");
|
||||
widgetTop->setMinimumHeight(35);
|
||||
|
||||
//上一年按钮
|
||||
QToolButton *btnPrevYear = new QToolButton;
|
||||
btnPrevYear->setObjectName("btnPrevYear");
|
||||
btnPrevYear->setFixedWidth(35);
|
||||
btnPrevYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
btnPrevYear->setFont(iconFont);
|
||||
btnPrevYear->setText(QChar(0xf060));
|
||||
|
||||
//下一年按钮
|
||||
QToolButton *btnNextYear = new QToolButton;
|
||||
btnNextYear->setObjectName("btnNextYear");
|
||||
btnNextYear->setFixedWidth(35);
|
||||
btnNextYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
btnNextYear->setFont(iconFont);
|
||||
btnNextYear->setText(QChar(0xf061));
|
||||
|
||||
//上个月按钮
|
||||
QToolButton *btnPrevMonth = new QToolButton;
|
||||
btnPrevMonth->setObjectName("btnPrevMonth");
|
||||
btnPrevMonth->setFixedWidth(35);
|
||||
btnPrevMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
btnPrevMonth->setFont(iconFont);
|
||||
btnPrevMonth->setText(QChar(0xf060));
|
||||
|
||||
//下个月按钮
|
||||
QToolButton *btnNextMonth = new QToolButton;
|
||||
btnNextMonth->setObjectName("btnNextMonth");
|
||||
btnNextMonth->setFixedWidth(35);
|
||||
btnNextMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
btnNextMonth->setFont(iconFont);
|
||||
btnNextMonth->setText(QChar(0xf061));
|
||||
|
||||
//转到今天
|
||||
QPushButton *btnToday = new QPushButton;
|
||||
btnToday->setObjectName("btnToday");
|
||||
btnToday->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
btnToday->setText("转到今天");
|
||||
|
||||
//年份下拉框
|
||||
cboxYear = new QComboBox;
|
||||
cboxYear->setObjectName("cboxYear");
|
||||
for (int i = 1901; i <= 2099; i++) {
|
||||
cboxYear->addItem(QString("%1年").arg(i));
|
||||
}
|
||||
|
||||
//月份下拉框
|
||||
cboxMonth = new QComboBox;
|
||||
cboxMonth->setObjectName("cboxMonth");
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
cboxMonth->addItem(QString("%1月").arg(i));
|
||||
}
|
||||
|
||||
//中间用个空widget隔开
|
||||
QWidget *widgetBlank1 = new QWidget;
|
||||
widgetBlank1->setFixedWidth(5);
|
||||
QWidget *widgetBlank2 = new QWidget;
|
||||
widgetBlank2->setFixedWidth(5);
|
||||
|
||||
//顶部横向布局
|
||||
QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop);
|
||||
layoutTop->setContentsMargins(0, 0, 0, 9);
|
||||
layoutTop->addWidget(btnPrevYear);
|
||||
layoutTop->addWidget(cboxYear);
|
||||
layoutTop->addWidget(btnNextYear);
|
||||
layoutTop->addWidget(widgetBlank1);
|
||||
|
||||
layoutTop->addWidget(btnPrevMonth);
|
||||
layoutTop->addWidget(cboxMonth);
|
||||
layoutTop->addWidget(btnNextMonth);
|
||||
layoutTop->addWidget(widgetBlank2);
|
||||
layoutTop->addWidget(btnToday);
|
||||
|
||||
//星期widget
|
||||
QWidget *widgetWeek = new QWidget;
|
||||
widgetWeek->setObjectName("widgetWeek");
|
||||
widgetWeek->setMinimumHeight(30);
|
||||
|
||||
//星期布局
|
||||
QHBoxLayout *layoutWeek = new QHBoxLayout(widgetWeek);
|
||||
layoutWeek->setContentsMargins(0, 0, 0, 0);
|
||||
layoutWeek->setSpacing(0);
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
QLabel *lab = new QLabel;
|
||||
lab->setAlignment(Qt::AlignCenter);
|
||||
layoutWeek->addWidget(lab);
|
||||
labWeeks.append(lab);
|
||||
}
|
||||
|
||||
setWeekNameFormat(WeekNameFormat_Long);
|
||||
|
||||
//日期标签widget
|
||||
QWidget *widgetBody = new QWidget;
|
||||
widgetBody->setObjectName("widgetBody");
|
||||
|
||||
//日期标签布局
|
||||
QGridLayout *layoutBody = new QGridLayout(widgetBody);
|
||||
layoutBody->setContentsMargins(1, 1, 1, 1);
|
||||
layoutBody->setHorizontalSpacing(0);
|
||||
layoutBody->setVerticalSpacing(0);
|
||||
|
||||
//逐个添加日标签
|
||||
for (int i = 0; i < 42; i++) {
|
||||
LunarCalendarItem *lab = new LunarCalendarItem;
|
||||
connect(lab, SIGNAL(clicked(QDate, LunarCalendarItem::DayType)), this, SLOT(clicked(QDate, LunarCalendarItem::DayType)));
|
||||
layoutBody->addWidget(lab, i / 7, i % 7);
|
||||
dayItems.append(lab);
|
||||
}
|
||||
|
||||
//主布局
|
||||
QVBoxLayout *verLayoutCalendar = new QVBoxLayout(this);
|
||||
verLayoutCalendar->setContentsMargins(0, 0, 0, 0);
|
||||
verLayoutCalendar->setSpacing(0);
|
||||
verLayoutCalendar->addWidget(widgetTop);
|
||||
verLayoutCalendar->addWidget(widgetWeek);
|
||||
verLayoutCalendar->addWidget(widgetBody, 1);
|
||||
|
||||
//绑定按钮和下拉框信号
|
||||
connect(btnPrevYear, SIGNAL(clicked(bool)), this, SLOT(showPreviousYear()));
|
||||
connect(btnNextYear, SIGNAL(clicked(bool)), this, SLOT(showNextYear()));
|
||||
connect(btnPrevMonth, SIGNAL(clicked(bool)), this, SLOT(showPreviousMonth()));
|
||||
connect(btnNextMonth, SIGNAL(clicked(bool)), this, SLOT(showNextMonth()));
|
||||
connect(btnToday, SIGNAL(clicked(bool)), this, SLOT(showToday()));
|
||||
connect(cboxYear, SIGNAL(currentIndexChanged(int)), this, SLOT(yearChanged(int)));
|
||||
connect(cboxMonth, SIGNAL(currentIndexChanged(int)), this, SLOT(monthChanged(int)));
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::initStyle()
|
||||
{
|
||||
//设置样式
|
||||
QStringList qss;
|
||||
|
||||
//星期名称样式
|
||||
qss.append(QString("QLabel{background:%1;color:%2;}").arg(weekBgColor.name()).arg(weekTextColor.name()));
|
||||
|
||||
//边框
|
||||
qss.append(QString("QWidget#widgetBody{border:1px solid %1;}").arg(borderColor.name()));
|
||||
|
||||
//顶部下拉框
|
||||
qss.append(QString("QToolButton{padding:0px;background:none;border:none;border-radius:5px;}"));
|
||||
qss.append(QString("QToolButton:hover{background:#16A085;color:#FFFFFF;}"));
|
||||
|
||||
//转到今天
|
||||
qss.append(QString("QPushButton{background:#16A085;color:#FFFFFF;border-radius:5px;}"));
|
||||
|
||||
//自定义日控件颜色
|
||||
QString strSelectType;
|
||||
if (selectType == SelectType_Rect) {
|
||||
strSelectType = "SelectType_Rect";
|
||||
} else if (selectType == SelectType_Circle) {
|
||||
strSelectType = "SelectType_Circle";
|
||||
} else if (selectType == SelectType_Triangle) {
|
||||
strSelectType = "SelectType_Triangle";
|
||||
} else if (selectType == SelectType_Image) {
|
||||
strSelectType = "SelectType_Image";
|
||||
}
|
||||
|
||||
qss.append(QString("LunarCalendarItem{qproperty-showLunar:%1;}").arg(showLunar));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-bgImage:%1;}").arg(bgImage));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-selectType:%1;}").arg(strSelectType));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-borderColor:%1;}").arg(borderColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-weekColor:%1;}").arg(weekColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-superColor:%1;}").arg(superColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-lunarColor:%1;}").arg(lunarColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-currentTextColor:%1;}").arg(currentTextColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-otherTextColor:%1;}").arg(otherTextColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-selectTextColor:%1;}").arg(selectTextColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-hoverTextColor:%1;}").arg(hoverTextColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-currentLunarColor:%1;}").arg(currentLunarColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-otherLunarColor:%1;}").arg(otherLunarColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-selectLunarColor:%1;}").arg(selectLunarColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-hoverLunarColor:%1;}").arg(hoverLunarColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-currentBgColor:%1;}").arg(currentBgColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-otherBgColor:%1;}").arg(otherBgColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-selectBgColor:%1;}").arg(selectBgColor.name()));
|
||||
qss.append(QString("LunarCalendarItem{qproperty-hoverBgColor:%1;}").arg(hoverBgColor.name()));
|
||||
|
||||
this->setStyleSheet(qss.join(""));
|
||||
}
|
||||
|
||||
//初始化日期面板
|
||||
void LunarCalendarWidget::initDate()
|
||||
{
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
|
||||
//设置为今天,设置变量防止重复触发
|
||||
btnClick = true;
|
||||
cboxYear->setCurrentIndex(cboxYear->findText(QString("%1年").arg(year)));
|
||||
cboxMonth->setCurrentIndex(cboxMonth->findText(QString("%1月").arg(month)));
|
||||
btnClick = false;
|
||||
|
||||
//首先判断当前月的第一天是星期几
|
||||
int week = LunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month);
|
||||
//当前月天数
|
||||
int countDay = LunarCalendarInfo::Instance()->getMonthDays(year, month);
|
||||
//上月天数
|
||||
int countDayPre = LunarCalendarInfo::Instance()->getMonthDays(1 == month ? year - 1 : year, 1 == month ? 12 : month - 1);
|
||||
|
||||
//如果上月天数上月刚好一周则另外处理
|
||||
int startPre, endPre, startNext, endNext, index, tempYear, tempMonth, tempDay;
|
||||
if (0 == week) {
|
||||
startPre = 0;
|
||||
endPre = 7;
|
||||
startNext = 0;
|
||||
endNext = 42 - (countDay + 7);
|
||||
} else {
|
||||
startPre = 0;
|
||||
endPre = week;
|
||||
startNext = week + countDay;
|
||||
endNext = 42;
|
||||
}
|
||||
|
||||
//纠正1月份前面部分偏差,1月份前面部分是上一年12月份
|
||||
tempYear = year;
|
||||
tempMonth = month - 1;
|
||||
if (tempMonth < 1) {
|
||||
tempYear--;
|
||||
tempMonth = 12;
|
||||
}
|
||||
|
||||
//显示上月天数
|
||||
for (int i = startPre; i < endPre; i++) {
|
||||
index = i;
|
||||
tempDay = countDayPre - endPre + i + 1;
|
||||
|
||||
QDate date(tempYear, tempMonth, tempDay);
|
||||
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
|
||||
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthPre);
|
||||
}
|
||||
|
||||
//纠正12月份后面部分偏差,12月份后面部分是下一年1月份
|
||||
tempYear = year;
|
||||
tempMonth = month + 1;
|
||||
if (tempMonth > 12) {
|
||||
tempYear++;
|
||||
tempMonth = 1;
|
||||
}
|
||||
|
||||
//显示下月天数
|
||||
for (int i = startNext; i < endNext; i++) {
|
||||
index = 42 - endNext + i;
|
||||
tempDay = i - startNext + 1;
|
||||
|
||||
QDate date(tempYear, tempMonth, tempDay);
|
||||
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
|
||||
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthNext);
|
||||
}
|
||||
|
||||
//重新置为当前年月
|
||||
tempYear = year;
|
||||
tempMonth = month;
|
||||
|
||||
//显示当前月
|
||||
for (int i = week; i < (countDay + week); i++) {
|
||||
index = (0 == week ? (i + 7) : i);
|
||||
tempDay = i - week + 1;
|
||||
|
||||
QDate date(tempYear, tempMonth, tempDay);
|
||||
QString lunar = LunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
|
||||
if (0 == (i % 7) || 6 == (i % 7)) {
|
||||
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_WeekEnd);
|
||||
} else {
|
||||
dayItems.at(index)->setDate(date, lunar, LunarCalendarItem::DayType_MonthCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
dayChanged(this->date);
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::yearChanged(int)
|
||||
{
|
||||
//如果是单击按钮切换的日期变动则不需要触发
|
||||
if (btnClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString arg1 = cboxYear->currentText();
|
||||
int year = arg1.mid(0, arg1.length() - 1).toInt();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::monthChanged(int)
|
||||
{
|
||||
//如果是单击按钮切换的日期变动则不需要触发
|
||||
if (btnClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString arg1 = cboxMonth->currentText();
|
||||
int year = date.year();
|
||||
int month = arg1.mid(0, arg1.length() - 1).toInt();
|
||||
int day = date.day();
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::clicked(const QDate &date, const LunarCalendarItem::DayType &dayType)
|
||||
{
|
||||
if (LunarCalendarItem::DayType_MonthPre == dayType) {
|
||||
showPreviousMonth();
|
||||
} else if (LunarCalendarItem::DayType_MonthNext == dayType) {
|
||||
showNextMonth();
|
||||
} else {
|
||||
this->date = date;
|
||||
dayChanged(this->date);
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::dayChanged(const QDate &date)
|
||||
{
|
||||
//计算星期几,当前天对应标签索引=日期+星期几-1
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
int week = LunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month);
|
||||
//qDebug() << QString("%1-%2-%3").arg(year).arg(month).arg(day);
|
||||
|
||||
//选中当前日期,其他日期恢复,这里还有优化空间,比方说类似单选框机制
|
||||
for (int i = 0; i < 42; i++) {
|
||||
//当月第一天是星期天要另外计算
|
||||
int index = day + week - 1;
|
||||
if (week == 0) {
|
||||
index = day + 6;
|
||||
}
|
||||
|
||||
dayItems.at(i)->setSelect(i == index);
|
||||
}
|
||||
|
||||
//发送日期单击信号
|
||||
emit clicked(date);
|
||||
//发送日期更新信号
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::dateChanged(int year, int month, int day)
|
||||
{
|
||||
//如果原有天大于28则设置为1,防止出错
|
||||
date.setDate(year, month, day > 28 ? 1 : day);
|
||||
initDate();
|
||||
}
|
||||
|
||||
LunarCalendarWidget::CalendarStyle LunarCalendarWidget::getCalendarStyle() const
|
||||
{
|
||||
return this->calendarStyle;
|
||||
}
|
||||
|
||||
LunarCalendarWidget::WeekNameFormat LunarCalendarWidget::getWeekNameFormat() const
|
||||
{
|
||||
return this->weekNameFormat;
|
||||
}
|
||||
|
||||
QDate LunarCalendarWidget::getDate() const
|
||||
{
|
||||
return this->date;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getWeekTextColor() const
|
||||
{
|
||||
return this->weekTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getWeekBgColor() const
|
||||
{
|
||||
return this->weekBgColor;
|
||||
}
|
||||
|
||||
bool LunarCalendarWidget::getShowLunar() const
|
||||
{
|
||||
return this->showLunar;
|
||||
}
|
||||
|
||||
QString LunarCalendarWidget::getBgImage() const
|
||||
{
|
||||
return this->bgImage;
|
||||
}
|
||||
|
||||
LunarCalendarWidget::SelectType LunarCalendarWidget::getSelectType() const
|
||||
{
|
||||
return this->selectType;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getBorderColor() const
|
||||
{
|
||||
return this->borderColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getWeekColor() const
|
||||
{
|
||||
return this->weekColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getSuperColor() const
|
||||
{
|
||||
return this->superColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getLunarColor() const
|
||||
{
|
||||
return this->lunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getCurrentTextColor() const
|
||||
{
|
||||
return this->currentTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getOtherTextColor() const
|
||||
{
|
||||
return this->otherTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getSelectTextColor() const
|
||||
{
|
||||
return this->selectTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getHoverTextColor() const
|
||||
{
|
||||
return this->hoverTextColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getCurrentLunarColor() const
|
||||
{
|
||||
return this->currentLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getOtherLunarColor() const
|
||||
{
|
||||
return this->otherLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getSelectLunarColor() const
|
||||
{
|
||||
return this->selectLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getHoverLunarColor() const
|
||||
{
|
||||
return this->hoverLunarColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getCurrentBgColor() const
|
||||
{
|
||||
return this->currentBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getOtherBgColor() const
|
||||
{
|
||||
return this->otherBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getSelectBgColor() const
|
||||
{
|
||||
return this->selectBgColor;
|
||||
}
|
||||
|
||||
QColor LunarCalendarWidget::getHoverBgColor() const
|
||||
{
|
||||
return this->hoverBgColor;
|
||||
}
|
||||
|
||||
QSize LunarCalendarWidget::sizeHint() const
|
||||
{
|
||||
return QSize(600, 500);
|
||||
}
|
||||
|
||||
QSize LunarCalendarWidget::minimumSizeHint() const
|
||||
{
|
||||
return QSize(200, 150);
|
||||
}
|
||||
|
||||
//显示上一年
|
||||
void LunarCalendarWidget::showPreviousYear()
|
||||
{
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
if (year <= 1901) {
|
||||
return;
|
||||
}
|
||||
|
||||
year--;
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
//显示下一年
|
||||
void LunarCalendarWidget::showNextYear()
|
||||
{
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
if (year >= 2099) {
|
||||
return;
|
||||
}
|
||||
|
||||
year++;
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
//显示上月日期
|
||||
void LunarCalendarWidget::showPreviousMonth()
|
||||
{
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
if (year <= 1901 && month == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
month--;
|
||||
if (month < 1) {
|
||||
month = 12;
|
||||
year--;
|
||||
}
|
||||
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
//显示下月日期
|
||||
void LunarCalendarWidget::showNextMonth()
|
||||
{
|
||||
int year = date.year();
|
||||
int month = date.month();
|
||||
int day = date.day();
|
||||
if (year >= 2099 && month == 12) {
|
||||
return;
|
||||
}
|
||||
|
||||
month++;
|
||||
if (month > 12) {
|
||||
month = 1;
|
||||
year++;
|
||||
}
|
||||
|
||||
dateChanged(year, month, day);
|
||||
}
|
||||
|
||||
//转到今天
|
||||
void LunarCalendarWidget::showToday()
|
||||
{
|
||||
date = QDate::currentDate();
|
||||
initDate();
|
||||
dayChanged(date);
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setCalendarStyle(const LunarCalendarWidget::CalendarStyle &calendarStyle)
|
||||
{
|
||||
if (this->calendarStyle != calendarStyle) {
|
||||
this->calendarStyle = calendarStyle;
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setWeekNameFormat(const LunarCalendarWidget::WeekNameFormat &weekNameFormat)
|
||||
{
|
||||
if (this->weekNameFormat != weekNameFormat) {
|
||||
this->weekNameFormat = weekNameFormat;
|
||||
|
||||
QStringList listWeek;
|
||||
if (weekNameFormat == WeekNameFormat_Short) {
|
||||
listWeek << "日" << "一" << "二" << "三" << "四" << "五" << "六";
|
||||
} else if (weekNameFormat == WeekNameFormat_Normal) {
|
||||
listWeek << "周日" << "周一" << "周二" << "周三" << "周四" << "周五" << "周六";
|
||||
} else if (weekNameFormat == WeekNameFormat_Long) {
|
||||
listWeek << "星期天" << "星期一" << "星期二" << "星期三" << "星期四" << "星期五" << "星期六";
|
||||
} else if (weekNameFormat == WeekNameFormat_En) {
|
||||
listWeek << "Sun" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat";
|
||||
}
|
||||
|
||||
//逐个添加日期文字
|
||||
for (int i = 0; i < 7; i++) {
|
||||
labWeeks.at(i)->setText(listWeek.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setDate(const QDate &date)
|
||||
{
|
||||
if (this->date != date) {
|
||||
this->date = date;
|
||||
initDate();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setWeekTextColor(const QColor &weekTextColor)
|
||||
{
|
||||
if (this->weekTextColor != weekTextColor) {
|
||||
this->weekTextColor = weekTextColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setWeekBgColor(const QColor &weekBgColor)
|
||||
{
|
||||
if (this->weekBgColor != weekBgColor) {
|
||||
this->weekBgColor = weekBgColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setShowLunar(bool showLunar)
|
||||
{
|
||||
if (this->showLunar != showLunar) {
|
||||
this->showLunar = showLunar;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setBgImage(const QString &bgImage)
|
||||
{
|
||||
if (this->bgImage != bgImage) {
|
||||
this->bgImage = bgImage;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setSelectType(const LunarCalendarWidget::SelectType &selectType)
|
||||
{
|
||||
if (this->selectType != selectType) {
|
||||
this->selectType = selectType;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setBorderColor(const QColor &borderColor)
|
||||
{
|
||||
if (this->borderColor != borderColor) {
|
||||
this->borderColor = borderColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setWeekColor(const QColor &weekColor)
|
||||
{
|
||||
if (this->weekColor != weekColor) {
|
||||
this->weekColor = weekColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setSuperColor(const QColor &superColor)
|
||||
{
|
||||
if (this->superColor != superColor) {
|
||||
this->superColor = superColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setLunarColor(const QColor &lunarColor)
|
||||
{
|
||||
if (this->lunarColor != lunarColor) {
|
||||
this->lunarColor = lunarColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setCurrentTextColor(const QColor ¤tTextColor)
|
||||
{
|
||||
if (this->currentTextColor != currentTextColor) {
|
||||
this->currentTextColor = currentTextColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setOtherTextColor(const QColor &otherTextColor)
|
||||
{
|
||||
if (this->otherTextColor != otherTextColor) {
|
||||
this->otherTextColor = otherTextColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setSelectTextColor(const QColor &selectTextColor)
|
||||
{
|
||||
if (this->selectTextColor != selectTextColor) {
|
||||
this->selectTextColor = selectTextColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setHoverTextColor(const QColor &hoverTextColor)
|
||||
{
|
||||
if (this->hoverTextColor != hoverTextColor) {
|
||||
this->hoverTextColor = hoverTextColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setCurrentLunarColor(const QColor ¤tLunarColor)
|
||||
{
|
||||
if (this->currentLunarColor != currentLunarColor) {
|
||||
this->currentLunarColor = currentLunarColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setOtherLunarColor(const QColor &otherLunarColor)
|
||||
{
|
||||
if (this->otherLunarColor != otherLunarColor) {
|
||||
this->otherLunarColor = otherLunarColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setSelectLunarColor(const QColor &selectLunarColor)
|
||||
{
|
||||
if (this->selectLunarColor != selectLunarColor) {
|
||||
this->selectLunarColor = selectLunarColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setHoverLunarColor(const QColor &hoverLunarColor)
|
||||
{
|
||||
if (this->hoverLunarColor != hoverLunarColor) {
|
||||
this->hoverLunarColor = hoverLunarColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setCurrentBgColor(const QColor ¤tBgColor)
|
||||
{
|
||||
if (this->currentBgColor != currentBgColor) {
|
||||
this->currentBgColor = currentBgColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setOtherBgColor(const QColor &otherBgColor)
|
||||
{
|
||||
if (this->otherBgColor != otherBgColor) {
|
||||
this->otherBgColor = otherBgColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setSelectBgColor(const QColor &selectBgColor)
|
||||
{
|
||||
if (this->selectBgColor != selectBgColor) {
|
||||
this->selectBgColor = selectBgColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void LunarCalendarWidget::setHoverBgColor(const QColor &hoverBgColor)
|
||||
{
|
||||
if (this->hoverBgColor != hoverBgColor) {
|
||||
this->hoverBgColor = hoverBgColor;
|
||||
initStyle();
|
||||
}
|
||||
}
|
||||
248
widget/lunarcalendarwidget/lunarcalendarwidget.h
Normal file
@@ -0,0 +1,248 @@
|
||||
#ifndef LUNARCALENDARWIDGET_H
|
||||
#define LUNARCALENDARWIDGET_H
|
||||
|
||||
/**
|
||||
* 自定义农历控件 作者:倪大侠 整理:feiyangqingyun(QQ:517216493) 2017-11-17
|
||||
* 1. 可设置边框颜色、周末颜色、角标颜色、农历节日颜色。
|
||||
* 2. 可设置当前月文字颜色、其他月文字颜色、选中日期文字颜色、悬停日期文字颜色。
|
||||
* 3. 可设置当前月农历文字颜色、其他月农历文字颜色、选中日期农历文字颜色、悬停日期农历文字颜色。
|
||||
* 4. 可设置当前月背景颜色、其他月背景颜色、选中日期背景颜色、悬停日期背景颜色。
|
||||
* 5. 可设置三种选中背景模式,矩形背景、圆形背景、图片背景。
|
||||
* 6. 可直接切换到上一年、下一年、上一月、下一月、转到今天。
|
||||
* 7. 可设置是否显示农历信息,不显示则当做正常的日历使用。
|
||||
* 8. 支持1901年-2099年范围。
|
||||
* 9. 很方便改成多选日期。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDate>
|
||||
|
||||
#include "lunarcalendarinfo.h"
|
||||
#include "lunarcalendaritem.h"
|
||||
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class LunarCalendarItem;
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT LunarCalendarWidget : public QWidget
|
||||
#else
|
||||
class LunarCalendarWidget : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(CalendarStyle)
|
||||
Q_ENUMS(WeekNameFormat)
|
||||
Q_ENUMS(SelectType)
|
||||
|
||||
Q_PROPERTY(CalendarStyle calendarStyle READ getCalendarStyle WRITE setCalendarStyle)
|
||||
Q_PROPERTY(WeekNameFormat weekNameFormat READ getWeekNameFormat WRITE setWeekNameFormat)
|
||||
Q_PROPERTY(QDate date READ getDate WRITE setDate)
|
||||
|
||||
Q_PROPERTY(QColor weekTextColor READ getWeekTextColor WRITE setWeekTextColor)
|
||||
Q_PROPERTY(QColor weekBgColor READ getWeekBgColor WRITE setWeekBgColor)
|
||||
|
||||
Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar)
|
||||
Q_PROPERTY(QString bgImage READ getBgImage WRITE setBgImage)
|
||||
Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType)
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor)
|
||||
Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor)
|
||||
Q_PROPERTY(QColor superColor READ getSuperColor WRITE setSuperColor)
|
||||
Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor)
|
||||
|
||||
Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor)
|
||||
Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor)
|
||||
Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor)
|
||||
Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor)
|
||||
|
||||
Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor)
|
||||
Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor)
|
||||
Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor)
|
||||
Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor)
|
||||
|
||||
Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor)
|
||||
Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor)
|
||||
Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor)
|
||||
Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor)
|
||||
|
||||
public:
|
||||
enum CalendarStyle {
|
||||
CalendarStyle_Red = 0
|
||||
};
|
||||
|
||||
enum WeekNameFormat {
|
||||
WeekNameFormat_Short = 0, //短名称
|
||||
WeekNameFormat_Normal = 1, //普通名称
|
||||
WeekNameFormat_Long = 2, //长名称
|
||||
WeekNameFormat_En = 3 //英文名称
|
||||
};
|
||||
|
||||
enum SelectType {
|
||||
SelectType_Rect = 0, //矩形背景
|
||||
SelectType_Circle = 1, //圆形背景
|
||||
SelectType_Triangle = 2, //带三角标
|
||||
SelectType_Image = 3 //图片背景
|
||||
};
|
||||
|
||||
explicit LunarCalendarWidget(QWidget *parent = 0);
|
||||
~LunarCalendarWidget();
|
||||
|
||||
private:
|
||||
QFont iconFont; //图形字体
|
||||
bool btnClick; //按钮单击,避开下拉选择重复触发
|
||||
QComboBox *cboxYear; //年份下拉框
|
||||
QComboBox *cboxMonth; //月份下拉框
|
||||
QList<QLabel *> labWeeks; //顶部星期名称
|
||||
QList<LunarCalendarItem *> dayItems;//日期元素
|
||||
|
||||
CalendarStyle calendarStyle; //整体样式
|
||||
WeekNameFormat weekNameFormat; //星期名称格式
|
||||
QDate date; //当前日期
|
||||
|
||||
QColor weekTextColor; //星期名称文字颜色
|
||||
QColor weekBgColor; //星期名称背景色
|
||||
|
||||
bool showLunar; //显示农历
|
||||
QString bgImage; //背景图片
|
||||
SelectType selectType; //选中模式
|
||||
|
||||
QColor borderColor; //边框颜色
|
||||
QColor weekColor; //周末颜色
|
||||
QColor superColor; //角标颜色
|
||||
QColor lunarColor; //农历节日颜色
|
||||
|
||||
QColor currentTextColor; //当前月文字颜色
|
||||
QColor otherTextColor; //其他月文字颜色
|
||||
QColor selectTextColor; //选中日期文字颜色
|
||||
QColor hoverTextColor; //悬停日期文字颜色
|
||||
|
||||
QColor currentLunarColor; //当前月农历文字颜色
|
||||
QColor otherLunarColor; //其他月农历文字颜色
|
||||
QColor selectLunarColor; //选中日期农历文字颜色
|
||||
QColor hoverLunarColor; //悬停日期农历文字颜色
|
||||
|
||||
QColor currentBgColor; //当前月背景颜色
|
||||
QColor otherBgColor; //其他月背景颜色
|
||||
QColor selectBgColor; //选中日期背景颜色
|
||||
QColor hoverBgColor; //悬停日期背景颜色
|
||||
|
||||
private slots:
|
||||
void initWidget();
|
||||
void initStyle();
|
||||
void initDate();
|
||||
void yearChanged(int);
|
||||
void monthChanged(int);
|
||||
void clicked(const QDate &date, const LunarCalendarItem::DayType &dayType);
|
||||
void dayChanged(const QDate &date);
|
||||
void dateChanged(int year, int month, int day);
|
||||
|
||||
public:
|
||||
CalendarStyle getCalendarStyle() const;
|
||||
WeekNameFormat getWeekNameFormat() const;
|
||||
QDate getDate() const;
|
||||
|
||||
QColor getWeekTextColor() const;
|
||||
QColor getWeekBgColor() const;
|
||||
|
||||
bool getShowLunar() const;
|
||||
QString getBgImage() const;
|
||||
SelectType getSelectType() const;
|
||||
|
||||
QColor getBorderColor() const;
|
||||
QColor getWeekColor() const;
|
||||
QColor getSuperColor() const;
|
||||
QColor getLunarColor() const;
|
||||
|
||||
QColor getCurrentTextColor() const;
|
||||
QColor getOtherTextColor() const;
|
||||
QColor getSelectTextColor() const;
|
||||
QColor getHoverTextColor() const;
|
||||
|
||||
QColor getCurrentLunarColor() const;
|
||||
QColor getOtherLunarColor() const;
|
||||
QColor getSelectLunarColor() const;
|
||||
QColor getHoverLunarColor() const;
|
||||
|
||||
QColor getCurrentBgColor() const;
|
||||
QColor getOtherBgColor() const;
|
||||
QColor getSelectBgColor() const;
|
||||
QColor getHoverBgColor() const;
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
//上一年,下一年
|
||||
void showPreviousYear();
|
||||
void showNextYear();
|
||||
|
||||
//上一月,下一月
|
||||
void showPreviousMonth();
|
||||
void showNextMonth();
|
||||
|
||||
//转到今天
|
||||
void showToday();
|
||||
|
||||
//设置整体样式
|
||||
void setCalendarStyle(const CalendarStyle &calendarStyle);
|
||||
//设置星期名称格式
|
||||
void setWeekNameFormat(const WeekNameFormat &weekNameFormat);
|
||||
|
||||
//设置日期
|
||||
void setDate(const QDate &date);
|
||||
|
||||
//设置顶部星期名称文字颜色+背景色
|
||||
void setWeekTextColor(const QColor &weekTextColor);
|
||||
void setWeekBgColor(const QColor &weekBgColor);
|
||||
|
||||
//设置是否显示农历信息
|
||||
void setShowLunar(bool showLunar);
|
||||
//设置背景图片
|
||||
void setBgImage(const QString &bgImage);
|
||||
//设置选中背景样式
|
||||
void setSelectType(const SelectType &selectType);
|
||||
|
||||
//设置边框颜色
|
||||
void setBorderColor(const QColor &borderColor);
|
||||
//设置周末颜色
|
||||
void setWeekColor(const QColor &weekColor);
|
||||
//设置角标颜色
|
||||
void setSuperColor(const QColor &superColor);
|
||||
//设置农历节日颜色
|
||||
void setLunarColor(const QColor &lunarColor);
|
||||
|
||||
//设置当前月文字颜色
|
||||
void setCurrentTextColor(const QColor ¤tTextColor);
|
||||
//设置其他月文字颜色
|
||||
void setOtherTextColor(const QColor &otherTextColor);
|
||||
//设置选中日期文字颜色
|
||||
void setSelectTextColor(const QColor &selectTextColor);
|
||||
//设置悬停日期文字颜色
|
||||
void setHoverTextColor(const QColor &hoverTextColor);
|
||||
|
||||
//设置当前月农历文字颜色
|
||||
void setCurrentLunarColor(const QColor ¤tLunarColor);
|
||||
//设置其他月农历文字颜色
|
||||
void setOtherLunarColor(const QColor &otherLunarColor);
|
||||
//设置选中日期农历文字颜色
|
||||
void setSelectLunarColor(const QColor &selectLunarColor);
|
||||
//设置悬停日期农历文字颜色
|
||||
void setHoverLunarColor(const QColor &hoverLunarColor);
|
||||
|
||||
//设置当前月背景颜色
|
||||
void setCurrentBgColor(const QColor ¤tBgColor);
|
||||
//设置其他月背景颜色
|
||||
void setOtherBgColor(const QColor &otherBgColor);
|
||||
//设置选中日期背景颜色
|
||||
void setSelectBgColor(const QColor &selectBgColor);
|
||||
//设置悬停日期背景颜色
|
||||
void setHoverBgColor(const QColor &hoverBgColor);
|
||||
|
||||
Q_SIGNALS:
|
||||
void clicked(const QDate &date);
|
||||
void selectionChanged();
|
||||
};
|
||||
|
||||
#endif // LUNARCALENDARWIDGET_H
|
||||
28
widget/lunarcalendarwidget/lunarcalendarwidget.pro
Normal file
@@ -0,0 +1,28 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = lunarcalendarwidget
|
||||
TEMPLATE = app
|
||||
MOC_DIR = temp/moc
|
||||
RCC_DIR = temp/rcc
|
||||
UI_DIR = temp/ui
|
||||
OBJECTS_DIR = temp/obj
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += qt warn_off
|
||||
RESOURCES += main.qrc
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmlunarcalendarwidget.cpp
|
||||
SOURCES += lunarcalendaritem.cpp
|
||||
SOURCES += lunarcalendarinfo.cpp
|
||||
SOURCES += lunarcalendarwidget.cpp
|
||||
|
||||
HEADERS += frmlunarcalendarwidget.h
|
||||
HEADERS += lunarcalendaritem.h
|
||||
HEADERS += lunarcalendarinfo.h
|
||||
HEADERS += lunarcalendarwidget.h
|
||||
|
||||
FORMS += frmlunarcalendarwidget.ui
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
31
widget/lunarcalendarwidget/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmlunarcalendarwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmLunarCalendarWidget w;
|
||||
w.setWindowTitle("农历控件");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
6
widget/lunarcalendarwidget/main.qrc
Normal file
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>image/bg_calendar.png</file>
|
||||
<file>font/fontawesome-webfont.ttf</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
34
widget/maskwidget/frmmaskwidget.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmmaskwidget.h"
|
||||
#include "ui_frmmaskwidget.h"
|
||||
#include "maskwidget.h"
|
||||
#include "qdialog.h"
|
||||
#include "qtimer.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
frmMaskWidget::frmMaskWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmMaskWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QTimer::singleShot(1000, this, SLOT(initForm()));
|
||||
}
|
||||
|
||||
frmMaskWidget::~frmMaskWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmMaskWidget::initForm()
|
||||
{
|
||||
MaskWidget::Instance()->setMainWidget(this->topLevelWidget());
|
||||
MaskWidget::Instance()->setDialogNames(QStringList() << "frmTest");
|
||||
}
|
||||
|
||||
void frmMaskWidget::on_pushButton_clicked()
|
||||
{
|
||||
QDialog d;
|
||||
d.setObjectName("frmTest");
|
||||
d.setWindowTitle("遮罩层弹出窗体");
|
||||
d.resize(400, 300);
|
||||
d.exec();
|
||||
}
|
||||
26
widget/maskwidget/frmmaskwidget.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef FRMMASKWIDGET_H
|
||||
#define FRMMASKWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmMaskWidget;
|
||||
}
|
||||
|
||||
class frmMaskWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmMaskWidget(QWidget *parent = 0);
|
||||
~frmMaskWidget();
|
||||
|
||||
private:
|
||||
Ui::frmMaskWidget *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
void on_pushButton_clicked();
|
||||
};
|
||||
|
||||
#endif // FRMMASKWIDGET_H
|
||||
32
widget/maskwidget/frmmaskwidget.ui
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmMaskWidget</class>
|
||||
<widget class="QWidget" name="frmMaskWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>92</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>弹出</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
widget/maskwidget/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmmaskwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmMaskWidget w;
|
||||
w.setWindowTitle("遮罩层窗体");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
104
widget/maskwidget/maskwidget.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "maskwidget.h"
|
||||
#include "qmutex.h"
|
||||
#include "qapplication.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
#include "qscreen.h"
|
||||
#define deskGeometry qApp->primaryScreen()->geometry()
|
||||
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
|
||||
#else
|
||||
#include "qdesktopwidget.h"
|
||||
#define deskGeometry qApp->desktop()->geometry()
|
||||
#define deskGeometry2 qApp->desktop()->availableGeometry()
|
||||
#endif
|
||||
|
||||
QScopedPointer<MaskWidget> MaskWidget::self;
|
||||
MaskWidget *MaskWidget::Instance()
|
||||
{
|
||||
if (self.isNull()) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
if (self.isNull()) {
|
||||
self.reset(new MaskWidget);
|
||||
}
|
||||
}
|
||||
|
||||
return self.data();
|
||||
}
|
||||
|
||||
MaskWidget::MaskWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mainWidget = 0;
|
||||
setOpacity(0.7);
|
||||
setBgColor(QColor(0, 0, 0));
|
||||
|
||||
//不设置主窗体则遮罩层大小为默认桌面大小
|
||||
this->setGeometry(deskGeometry);
|
||||
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
|
||||
|
||||
//绑定全局事件,过滤弹窗窗体进行处理
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
void MaskWidget::setMainWidget(QWidget *mainWidget)
|
||||
{
|
||||
if (this->mainWidget != mainWidget) {
|
||||
this->mainWidget = mainWidget;
|
||||
}
|
||||
}
|
||||
|
||||
void MaskWidget::setDialogNames(const QStringList &dialogNames)
|
||||
{
|
||||
if (this->dialogNames != dialogNames) {
|
||||
this->dialogNames = dialogNames;
|
||||
}
|
||||
}
|
||||
|
||||
void MaskWidget::setOpacity(double opacity)
|
||||
{
|
||||
this->setWindowOpacity(opacity);
|
||||
}
|
||||
|
||||
void MaskWidget::setBgColor(const QColor &bgColor)
|
||||
{
|
||||
QPalette palette = this->palette();
|
||||
palette.setBrush(QPalette::Window, bgColor);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
|
||||
void MaskWidget::showEvent(QShowEvent *)
|
||||
{
|
||||
if (mainWidget != 0) {
|
||||
this->setGeometry(mainWidget->geometry());
|
||||
}
|
||||
}
|
||||
|
||||
bool MaskWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Show) {
|
||||
if (dialogNames.contains(obj->objectName())) {
|
||||
this->show();
|
||||
this->activateWindow();
|
||||
QWidget *w = (QWidget *)obj;
|
||||
w->activateWindow();
|
||||
}
|
||||
} else if (event->type() == QEvent::Hide) {
|
||||
if (dialogNames.contains(obj->objectName())) {
|
||||
this->hide();
|
||||
}
|
||||
} else if (event->type() == QEvent::WindowActivate) {
|
||||
//当主窗体激活时,同时激活遮罩层
|
||||
if (mainWidget != 0) {
|
||||
if (obj->objectName() == mainWidget->objectName()) {
|
||||
if (this->isVisible()) {
|
||||
this->activateWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
51
widget/maskwidget/maskwidget.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef MASKWIDGET_H
|
||||
#define MASKWIDGET_H
|
||||
|
||||
/**
|
||||
* 弹窗遮罩层控件 作者:feiyangqingyun(QQ:517216493) 2016-12-26
|
||||
* 1. 可设置需要遮罩的主窗体,自动跟随主窗体位置显示遮罩面积。
|
||||
* 2. 只需要将弹窗窗体的名称一开始传入队列即可,足够简单。
|
||||
* 3. 可设置透明度。
|
||||
* 4. 可设置遮罩层颜色。
|
||||
* 5. 不阻塞消息循坏。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT MaskWidget : public QWidget
|
||||
#else
|
||||
class MaskWidget : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static MaskWidget *Instance();
|
||||
explicit MaskWidget(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *);
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
private:
|
||||
static QScopedPointer<MaskWidget> self;
|
||||
|
||||
//需要遮罩的主窗体
|
||||
QWidget *mainWidget;
|
||||
//需要弹窗的窗体对象名称集合链表
|
||||
QStringList dialogNames;
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置需要遮罩的主窗体
|
||||
void setMainWidget(QWidget *mainWidget);
|
||||
//设置需要弹窗的窗体对象名称集合链表
|
||||
void setDialogNames(const QStringList &dialogNames);
|
||||
|
||||
//设置遮罩颜色
|
||||
void setBgColor(const QColor &bgColor);
|
||||
//设置颜色透明度
|
||||
void setOpacity(double opacity);
|
||||
};
|
||||
|
||||
#endif // MASKWIDGET_H
|
||||
19
widget/maskwidget/maskwidget.pro
Normal file
@@ -0,0 +1,19 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = maskwidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += maskwidget.cpp
|
||||
SOURCES += frmmaskwidget.cpp
|
||||
|
||||
HEADERS += maskwidget.h
|
||||
HEADERS += frmmaskwidget.h
|
||||
|
||||
FORMS += frmmaskwidget.ui
|
||||
|
||||
|
||||
41
widget/movewidget/frmmovewidget.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmmovewidget.h"
|
||||
#include "ui_frmmovewidget.h"
|
||||
#include "qpushbutton.h"
|
||||
#include "qprogressbar.h"
|
||||
#include "movewidget.h"
|
||||
|
||||
frmMoveWidget::frmMoveWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmMoveWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
frmMoveWidget::~frmMoveWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmMoveWidget::initForm()
|
||||
{
|
||||
QPushButton *btn1 = new QPushButton(this);
|
||||
btn1->setGeometry(10, 10, 250, 25);
|
||||
btn1->setText("按住我拖动(仅限左键拖动)");
|
||||
MoveWidget *moveWidget1 = new MoveWidget(this);
|
||||
moveWidget1->setWidget(btn1);
|
||||
|
||||
QPushButton *btn2 = new QPushButton(this);
|
||||
btn2->setGeometry(10, 40, 250, 25);
|
||||
btn2->setText("按住我拖动(支持右键拖动)");
|
||||
MoveWidget *moveWidget2 = new MoveWidget(this);
|
||||
moveWidget2->setWidget(btn2);
|
||||
moveWidget2->setLeftButton(false);
|
||||
|
||||
QProgressBar *bar = new QProgressBar(this);
|
||||
bar->setGeometry(10, 70, 250, 25);
|
||||
bar->setRange(0, 0);
|
||||
bar->setTextVisible(false);
|
||||
MoveWidget *moveWidget3 = new MoveWidget(this);
|
||||
moveWidget3->setWidget(bar);
|
||||
}
|
||||
25
widget/movewidget/frmmovewidget.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FRMMOVEWIDGET_H
|
||||
#define FRMMOVEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmMoveWidget;
|
||||
}
|
||||
|
||||
class frmMoveWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmMoveWidget(QWidget *parent = 0);
|
||||
~frmMoveWidget();
|
||||
|
||||
private:
|
||||
Ui::frmMoveWidget *ui;
|
||||
|
||||
private slots:
|
||||
void initForm();
|
||||
};
|
||||
|
||||
#endif // FRMMOVEWIDGET_H
|
||||
19
widget/movewidget/frmmovewidget.ui
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmMoveWidget</class>
|
||||
<widget class="QWidget" name="frmMoveWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
widget/movewidget/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmmovewidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmMoveWidget w;
|
||||
w.setWindowTitle("通用移动类");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
74
widget/movewidget/movewidget.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "movewidget.h"
|
||||
#include "qevent.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
MoveWidget::MoveWidget(QObject *parent) : QObject(parent)
|
||||
{
|
||||
lastPoint = QPoint(0, 0);
|
||||
pressed = false;
|
||||
leftButton = true;
|
||||
inControl = true;
|
||||
widget = 0;
|
||||
}
|
||||
|
||||
bool MoveWidget::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (widget != 0 && watched == widget) {
|
||||
QMouseEvent *mouseEvent = (QMouseEvent *)event;
|
||||
if (mouseEvent->type() == QEvent::MouseButtonPress) {
|
||||
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
|
||||
if (leftButton && mouseEvent->button() != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//判断控件的区域是否包含了当前鼠标的坐标
|
||||
if (widget->rect().contains(mouseEvent->pos())) {
|
||||
lastPoint = mouseEvent->pos();
|
||||
pressed = true;
|
||||
}
|
||||
} else if (mouseEvent->type() == QEvent::MouseMove && pressed) {
|
||||
//计算坐标偏移值,调用move函数移动过去
|
||||
int offsetX = mouseEvent->pos().x() - lastPoint.x();
|
||||
int offsetY = mouseEvent->pos().y() - lastPoint.y();
|
||||
int x = widget->x() + offsetX;
|
||||
int y = widget->y() + offsetY;
|
||||
if (inControl) {
|
||||
//可以自行调整限定在容器中的范围,这里默认保留20个像素在里面
|
||||
int offset = 20;
|
||||
bool xyOut = (x + widget->width() < offset || y + widget->height() < offset);
|
||||
bool whOut = false;
|
||||
QWidget *w = (QWidget *)widget->parent();
|
||||
if (w != 0) {
|
||||
whOut = (w->width() - x < offset || w->height() - y < offset);
|
||||
}
|
||||
if (xyOut || whOut) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
widget->move(x, y);
|
||||
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) {
|
||||
pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void MoveWidget::setLeftButton(bool leftButton)
|
||||
{
|
||||
this->leftButton = leftButton;
|
||||
}
|
||||
|
||||
void MoveWidget::setInControl(bool inControl)
|
||||
{
|
||||
this->inControl = inControl;
|
||||
}
|
||||
|
||||
void MoveWidget::setWidget(QWidget *widget)
|
||||
{
|
||||
if (this->widget == 0) {
|
||||
this->widget = widget;
|
||||
this->widget->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
43
widget/movewidget/movewidget.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef MOVEWIDGET_H
|
||||
#define MOVEWIDGET_H
|
||||
|
||||
/**
|
||||
* 通用控件移动类 作者:feiyangqingyun(QQ:517216493) 2019-09-28
|
||||
* 1. 可以指定需要移动的widget。
|
||||
* 2. 可设置是否限定鼠标左键拖动。
|
||||
* 3. 支持任意widget控件。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT MoveWidget : public QObject
|
||||
#else
|
||||
class MoveWidget : public QObject
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MoveWidget(QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
private:
|
||||
QPoint lastPoint; //最后按下的坐标
|
||||
bool pressed; //鼠标是否按下
|
||||
bool leftButton; //限定鼠标左键
|
||||
bool inControl; //限定在容器内
|
||||
QWidget *widget; //移动的控件
|
||||
|
||||
public Q_SLOTS:
|
||||
//设置是否限定鼠标左键
|
||||
void setLeftButton(bool leftButton);
|
||||
//设置是否限定不能移出容器外面
|
||||
void setInControl(bool inControl);
|
||||
//设置要移动的控件
|
||||
void setWidget(QWidget *widget);
|
||||
};
|
||||
|
||||
#endif // MOVEWIDGET_H
|
||||
17
widget/movewidget/movewidget.pro
Normal file
@@ -0,0 +1,17 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = movewidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmmovewidget.cpp
|
||||
SOURCES += movewidget.cpp
|
||||
|
||||
HEADERS += frmmovewidget.h
|
||||
HEADERS += movewidget.h
|
||||
|
||||
FORMS += frmmovewidget.ui
|
||||
18
widget/screenwidget/frmscreenwidget.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "frmscreenwidget.h"
|
||||
#include "ui_frmscreenwidget.h"
|
||||
#include "screenwidget.h"
|
||||
|
||||
frmScreenWidget::frmScreenWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmScreenWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
frmScreenWidget::~frmScreenWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void frmScreenWidget::on_pushButton_clicked()
|
||||
{
|
||||
ScreenWidget::Instance()->showFullScreen();
|
||||
}
|
||||
25
widget/screenwidget/frmscreenwidget.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FRMSCREENWIDGET_H
|
||||
#define FRMSCREENWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class frmScreenWidget;
|
||||
}
|
||||
|
||||
class frmScreenWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit frmScreenWidget(QWidget *parent = 0);
|
||||
~frmScreenWidget();
|
||||
|
||||
private slots:
|
||||
void on_pushButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::frmScreenWidget *ui;
|
||||
};
|
||||
|
||||
#endif // FRMSCREENWIDGET_H
|
||||
32
widget/screenwidget/frmscreenwidget.ui
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>frmScreenWidget</class>
|
||||
<widget class="QWidget" name="frmScreenWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>92</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>弹出</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
widget/screenwidget/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmscreenwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
frmScreenWidget w;
|
||||
w.setWindowTitle("屏幕截图");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
332
widget/screenwidget/screenwidget.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "screenwidget.h"
|
||||
#include "qmutex.h"
|
||||
#include "qapplication.h"
|
||||
#include "qpainter.h"
|
||||
#include "qfiledialog.h"
|
||||
#include "qevent.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qstringlist.h"
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
#include "qscreen.h"
|
||||
#define deskGeometry qApp->primaryScreen()->geometry()
|
||||
#define deskGeometry2 qApp->primaryScreen()->availableGeometry()
|
||||
#else
|
||||
#include "qdesktopwidget.h"
|
||||
#define deskGeometry qApp->desktop()->geometry()
|
||||
#define deskGeometry2 qApp->desktop()->availableGeometry()
|
||||
#endif
|
||||
|
||||
#define STRDATETIME qPrintable (QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
||||
|
||||
Screen::Screen(QSize size)
|
||||
{
|
||||
maxWidth = size.width();
|
||||
maxHeight = size.height();
|
||||
|
||||
startPos = QPoint(-1, -1);
|
||||
endPos = startPos;
|
||||
leftUpPos = startPos;
|
||||
rightDownPos = startPos;
|
||||
status = SELECT;
|
||||
}
|
||||
|
||||
int Screen::width()
|
||||
{
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
int Screen::height()
|
||||
{
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
Screen::STATUS Screen::getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
void Screen::setStatus(STATUS status)
|
||||
{
|
||||
this->status = status;
|
||||
}
|
||||
|
||||
void Screen::setEnd(QPoint pos)
|
||||
{
|
||||
endPos = pos;
|
||||
leftUpPos = startPos;
|
||||
rightDownPos = endPos;
|
||||
cmpPoint(leftUpPos, rightDownPos);
|
||||
}
|
||||
|
||||
void Screen::setStart(QPoint pos)
|
||||
{
|
||||
startPos = pos;
|
||||
}
|
||||
|
||||
QPoint Screen::getEnd()
|
||||
{
|
||||
return endPos;
|
||||
}
|
||||
|
||||
QPoint Screen::getStart()
|
||||
{
|
||||
return startPos;
|
||||
}
|
||||
|
||||
QPoint Screen::getLeftUp()
|
||||
{
|
||||
return leftUpPos;
|
||||
}
|
||||
|
||||
QPoint Screen::getRightDown()
|
||||
{
|
||||
return rightDownPos;
|
||||
}
|
||||
|
||||
bool Screen::isInArea(QPoint pos)
|
||||
{
|
||||
if (pos.x() > leftUpPos.x() && pos.x() < rightDownPos.x() && pos.y() > leftUpPos.y() && pos.y() < rightDownPos.y()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Screen::move(QPoint p)
|
||||
{
|
||||
int lx = leftUpPos.x() + p.x();
|
||||
int ly = leftUpPos.y() + p.y();
|
||||
int rx = rightDownPos.x() + p.x();
|
||||
int ry = rightDownPos.y() + p.y();
|
||||
|
||||
if (lx < 0) {
|
||||
lx = 0;
|
||||
rx -= p.x();
|
||||
}
|
||||
|
||||
if (ly < 0) {
|
||||
ly = 0;
|
||||
ry -= p.y();
|
||||
}
|
||||
|
||||
if (rx > maxWidth) {
|
||||
rx = maxWidth;
|
||||
lx -= p.x();
|
||||
}
|
||||
|
||||
if (ry > maxHeight) {
|
||||
ry = maxHeight;
|
||||
ly -= p.y();
|
||||
}
|
||||
|
||||
leftUpPos = QPoint(lx, ly);
|
||||
rightDownPos = QPoint(rx, ry);
|
||||
startPos = leftUpPos;
|
||||
endPos = rightDownPos;
|
||||
}
|
||||
|
||||
void Screen::cmpPoint(QPoint &leftTop, QPoint &rightDown)
|
||||
{
|
||||
QPoint l = leftTop;
|
||||
QPoint r = rightDown;
|
||||
|
||||
if (l.x() <= r.x()) {
|
||||
if (l.y() <= r.y()) {
|
||||
;
|
||||
} else {
|
||||
leftTop.setY(r.y());
|
||||
rightDown.setY(l.y());
|
||||
}
|
||||
} else {
|
||||
if (l.y() < r.y()) {
|
||||
leftTop.setX(r.x());
|
||||
rightDown.setX(l.x());
|
||||
} else {
|
||||
QPoint tmp;
|
||||
tmp = leftTop;
|
||||
leftTop = rightDown;
|
||||
rightDown = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScopedPointer<ScreenWidget> ScreenWidget::self;
|
||||
ScreenWidget *ScreenWidget::Instance()
|
||||
{
|
||||
if (self.isNull()) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
if (self.isNull()) {
|
||||
self.reset(new ScreenWidget);
|
||||
}
|
||||
}
|
||||
|
||||
return self.data();
|
||||
}
|
||||
|
||||
ScreenWidget::ScreenWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
//this->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
|
||||
|
||||
menu = new QMenu(this);
|
||||
menu->addAction("保存当前截图", this, SLOT(saveScreen()));
|
||||
menu->addAction("保存全屏截图", this, SLOT(saveFullScreen()));
|
||||
menu->addAction("截图另存为", this, SLOT(saveScreenOther()));
|
||||
menu->addAction("全屏另存为", this, SLOT(saveFullOther()));
|
||||
menu->addAction("退出截图", this, SLOT(hide()));
|
||||
|
||||
//取得屏幕大小
|
||||
screen = new Screen(deskGeometry.size());
|
||||
//保存全屏图像
|
||||
fullScreen = new QPixmap();
|
||||
}
|
||||
|
||||
void ScreenWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
int x = screen->getLeftUp().x();
|
||||
int y = screen->getLeftUp().y();
|
||||
int w = screen->getRightDown().x() - x;
|
||||
int h = screen->getRightDown().y() - y;
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
QPen pen;
|
||||
pen.setColor(Qt::green);
|
||||
pen.setWidth(2);
|
||||
pen.setStyle(Qt::DotLine);
|
||||
painter.setPen(pen);
|
||||
painter.drawPixmap(0, 0, *bgScreen);
|
||||
|
||||
if (w != 0 && h != 0) {
|
||||
painter.drawPixmap(x, y, fullScreen->copy(x, y, w, h));
|
||||
}
|
||||
|
||||
painter.drawRect(x, y, w, h);
|
||||
|
||||
pen.setColor(Qt::yellow);
|
||||
painter.setPen(pen);
|
||||
painter.drawText(x + 2, y - 8, tr("截图范围:( %1 x %2 ) - ( %3 x %4 ) 图片大小:( %5 x %6 )")
|
||||
.arg(x).arg(y).arg(x + w).arg(y + h).arg(w).arg(h));
|
||||
}
|
||||
|
||||
void ScreenWidget::showEvent(QShowEvent *)
|
||||
{
|
||||
QPoint point(-1, -1);
|
||||
screen->setStart(point);
|
||||
screen->setEnd(point);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
||||
QScreen *pscreen = QApplication::primaryScreen();
|
||||
*fullScreen = pscreen->grabWindow(0, 0, 0, screen->width(), screen->height());
|
||||
#else
|
||||
*fullScreen = fullScreen->grabWindow(0, 0, 0, screen->width(), screen->height());
|
||||
#endif
|
||||
|
||||
//设置透明度实现模糊背景
|
||||
QPixmap pix(screen->width(), screen->height());
|
||||
pix.fill((QColor(160, 160, 160, 200)));
|
||||
bgScreen = new QPixmap(*fullScreen);
|
||||
QPainter p(bgScreen);
|
||||
p.drawPixmap(0, 0, pix);
|
||||
}
|
||||
|
||||
void ScreenWidget::saveScreen()
|
||||
{
|
||||
int x = screen->getLeftUp().x();
|
||||
int y = screen->getLeftUp().y();
|
||||
int w = screen->getRightDown().x() - x;
|
||||
int h = screen->getRightDown().y() - y;
|
||||
|
||||
QString fileName = QString("%1/screen_%2.png").arg(qApp->applicationDirPath()).arg(STRDATETIME);
|
||||
fullScreen->copy(x, y, w, h).save(fileName, "png");
|
||||
close();
|
||||
}
|
||||
|
||||
void ScreenWidget::saveFullScreen()
|
||||
{
|
||||
QString fileName = QString("%1/full_%2.png").arg(qApp->applicationDirPath()).arg(STRDATETIME);
|
||||
fullScreen->save(fileName, "png");
|
||||
close();
|
||||
}
|
||||
|
||||
void ScreenWidget::saveScreenOther()
|
||||
{
|
||||
QString name = QString("%1.png").arg(STRDATETIME);
|
||||
QString fileName = QFileDialog::getSaveFileName(this, "保存图片", name, "png Files (*.png)");
|
||||
if (!fileName.endsWith(".png")) {
|
||||
fileName += ".png";
|
||||
}
|
||||
|
||||
if (fileName.length() > 0) {
|
||||
int x = screen->getLeftUp().x();
|
||||
int y = screen->getLeftUp().y();
|
||||
int w = screen->getRightDown().x() - x;
|
||||
int h = screen->getRightDown().y() - y;
|
||||
fullScreen->copy(x, y, w, h).save(fileName, "png");
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenWidget::saveFullOther()
|
||||
{
|
||||
QString name = QString("%1.png").arg(STRDATETIME);
|
||||
QString fileName = QFileDialog::getSaveFileName(this, "保存图片", name, "png Files (*.png)");
|
||||
if (!fileName.endsWith(".png")) {
|
||||
fileName += ".png";
|
||||
}
|
||||
|
||||
if (fileName.length() > 0) {
|
||||
fullScreen->save(fileName, "png");
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenWidget::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (screen->getStatus() == Screen::SELECT) {
|
||||
screen->setEnd(e->pos());
|
||||
} else if (screen->getStatus() == Screen::MOV) {
|
||||
QPoint p(e->x() - movPos.x(), e->y() - movPos.y());
|
||||
screen->move(p);
|
||||
movPos = e->pos();
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ScreenWidget::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
int status = screen->getStatus();
|
||||
|
||||
if (status == Screen::SELECT) {
|
||||
screen->setStart(e->pos());
|
||||
} else if (status == Screen::MOV) {
|
||||
if (screen->isInArea(e->pos()) == false) {
|
||||
screen->setStart(e->pos());
|
||||
screen->setStatus(Screen::SELECT);
|
||||
} else {
|
||||
movPos = e->pos();
|
||||
this->setCursor(Qt::SizeAllCursor);
|
||||
}
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ScreenWidget::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
if (screen->getStatus() == Screen::SELECT) {
|
||||
screen->setStatus(Screen::MOV);
|
||||
} else if (screen->getStatus() == Screen::MOV) {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenWidget::contextMenuEvent(QContextMenuEvent *)
|
||||
{
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
menu->exec(cursor().pos());
|
||||
}
|
||||
94
widget/screenwidget/screenwidget.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#ifndef SCREENWIDGET_H
|
||||
#define SCREENWIDGET_H
|
||||
|
||||
/**
|
||||
* 全局截屏控件 作者:feiyangqingyun(QQ:517216493) 2016-11-11
|
||||
* 1. 鼠标右键弹出菜单。
|
||||
* 2. 支持全局截屏。
|
||||
* 3. 支持局部截屏。
|
||||
* 4. 支持截图区域拖动。
|
||||
* 5. 支持图片另存为。
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
enum STATUS {SELECT, MOV, SET_W_H};
|
||||
Screen() {}
|
||||
Screen(QSize size);
|
||||
|
||||
void setStart(QPoint pos);
|
||||
void setEnd(QPoint pos);
|
||||
QPoint getStart();
|
||||
QPoint getEnd();
|
||||
|
||||
QPoint getLeftUp();
|
||||
QPoint getRightDown();
|
||||
|
||||
STATUS getStatus();
|
||||
void setStatus(STATUS status);
|
||||
|
||||
int width();
|
||||
int height();
|
||||
|
||||
//检测坐标点是否在截图区域内
|
||||
bool isInArea(QPoint pos);
|
||||
//按坐标移动截图区域
|
||||
void move(QPoint p);
|
||||
|
||||
private:
|
||||
//记录 截图区域 左上角、右下角
|
||||
QPoint leftUpPos, rightDownPos;
|
||||
//记录 鼠标开始位置、结束位置
|
||||
QPoint startPos, endPos;
|
||||
//记录屏幕大小
|
||||
int maxWidth, maxHeight;
|
||||
//三个状态: 选择区域、移动区域、设置width height
|
||||
STATUS status;
|
||||
|
||||
//比较两位置,判断左上角、右下角
|
||||
void cmpPoint(QPoint &s, QPoint &e);
|
||||
};
|
||||
|
||||
#ifdef quc
|
||||
class Q_DECL_EXPORT ScreenWidget : public QWidget
|
||||
#else
|
||||
class ScreenWidget : public QWidget
|
||||
#endif
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ScreenWidget *Instance();
|
||||
explicit ScreenWidget(QWidget *parent = 0);
|
||||
|
||||
private:
|
||||
static QScopedPointer<ScreenWidget> self;
|
||||
QMenu *menu; //右键菜单对象
|
||||
Screen *screen; //截屏对象
|
||||
QPixmap *fullScreen; //保存全屏图像
|
||||
QPixmap *bgScreen; //模糊背景图
|
||||
QPoint movPos; //坐标
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *);
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
void mouseMoveEvent(QMouseEvent *);
|
||||
void mouseReleaseEvent(QMouseEvent *);
|
||||
void paintEvent(QPaintEvent *);
|
||||
void showEvent(QShowEvent *);
|
||||
|
||||
private slots:
|
||||
void saveScreen();
|
||||
void saveFullScreen();
|
||||
void saveScreenOther();
|
||||
void saveFullOther();
|
||||
};
|
||||
|
||||
#endif // SCREENWIDGET_H
|
||||
|
||||
17
widget/screenwidget/screenwidget.pro
Normal file
@@ -0,0 +1,17 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = screenwidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmscreenwidget.cpp
|
||||
SOURCES += screenwidget.cpp
|
||||
|
||||
HEADERS += screenwidget.h
|
||||
HEADERS += frmscreenwidget.h
|
||||
|
||||
FORMS += frmscreenwidget.ui
|
||||
8
widget/widget.pro
Normal file
@@ -0,0 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += colorwidget
|
||||
SUBDIRS += framelesswidget
|
||||
SUBDIRS += gifwidget
|
||||
SUBDIRS += lunarcalendarwidget
|
||||
SUBDIRS += maskwidget
|
||||
SUBDIRS += movewidget
|
||||
SUBDIRS += screenwidget
|
||||