├── .gitignore ├── CaptureStdPrint ├── .gitignore ├── CaptureStdPrint.pro └── main.cpp ├── InputMethodEventCatch ├── InputMethodEventCatch.pro ├── inputmethodeventcatch.cpp ├── inputmethodeventcatch.h └── main.cpp ├── LICENSE ├── N-order-BezierCurve ├── N-order-BezierCurve.pro ├── beziercurve.cpp ├── beziercurve.h └── main.cpp ├── README.md ├── SystemThemeDetection ├── .gitignore ├── SystemThemeDetection.pro └── main.cpp ├── TimerTask ├── .gitignore ├── TimerTask.pro └── main.cpp └── demonstrate ├── BezierCurve.gif ├── CaptureStdPrint.gif ├── InputMethodEventCatch.gif ├── SystemThemeDetection.gif └── demonstrate.md /.gitignore: -------------------------------------------------------------------------------- 1 | debug/ 2 | release/ 3 | *.user 4 | *.Debug 5 | *.Release 6 | Makefile 7 | *.stash 8 | *.rc 9 | *.exe 10 | *.qmlc 11 | *qmlcache.qrc 12 | .qtc_clangd/ -------------------------------------------------------------------------------- /CaptureStdPrint/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /CaptureStdPrint/CaptureStdPrint.pro: -------------------------------------------------------------------------------- 1 | QT += gui widgets 2 | 3 | CONFIG += c++11 4 | 5 | # You can make your code fail to compile if it uses deprecated APIs. 6 | # In order to do so, uncomment the following line. 7 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 8 | 9 | SOURCES += \ 10 | main.cpp 11 | 12 | # Default rules for deployment. 13 | qnx: target.path = /tmp/$${TARGET}/bin 14 | else: unix:!android: target.path = /opt/$${TARGET}/bin 15 | !isEmpty(target.path): INSTALLS += target 16 | -------------------------------------------------------------------------------- /CaptureStdPrint/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static void initializeDebugEnveriment() 10 | { 11 | static bool initialized = false; 12 | static QTextEdit *edit = new QTextEdit; 13 | static int lineCount = 0; 14 | static const QString stdoutFileDir = qApp->applicationDirPath() + "/cache"; 15 | 16 | static QTimer *watcher = new QTimer(qApp); 17 | static quint64 fileSize = 0; 18 | static QFile watchedStdoutFile(stdoutFileDir + "/stdout"); 19 | 20 | if (!initialized) { 21 | qRegisterMetaType("QTextCursor"); 22 | 23 | auto palette = edit->palette(); 24 | palette.setBrush(QPalette::Highlight, QColor(0, 120, 215)); 25 | edit->setPalette(palette); 26 | edit->setReadOnly(true); 27 | edit->setWindowTitle(QStringLiteral("调试窗口")); 28 | edit->setWindowFlag(Qt::WindowStaysOnTopHint); 29 | edit->resize(700, 500); 30 | edit->show(); 31 | 32 | if (!QDir().exists(stdoutFileDir)) QDir().mkpath(stdoutFileDir); 33 | 34 | std::freopen((stdoutFileDir + "/stdout").toLocal8Bit().data(), "w", stdout); 35 | watchedStdoutFile.open(QIODevice::ReadOnly); 36 | 37 | watcher->start(100); 38 | QObject::connect(watcher, &QTimer::timeout, watcher, []{ 39 | if (watchedStdoutFile.size() != fileSize) { 40 | fileSize = watchedStdoutFile.size(); 41 | auto watchedMsg = QString::fromLocal8Bit(watchedStdoutFile.readAll()); 42 | if (!watchedMsg.isEmpty()) { 43 | auto list = watchedMsg.split('\n'); 44 | for (auto msg: qAsConst(list)) { 45 | msg = msg.trimmed(); 46 | auto time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] "); 47 | if (!msg.isEmpty()) msg = time + msg; 48 | edit->append(msg); 49 | if (!edit->textCursor().hasSelection()) edit->moveCursor(QTextCursor::End); 50 | if (++lineCount > 50000) { 51 | lineCount = 0; 52 | edit->clear(); 53 | } 54 | } 55 | } 56 | } 57 | }); 58 | 59 | initialized = true; 60 | } 61 | 62 | static auto myMsgHandler = [](QtMsgType, const QMessageLogContext &, const QString &msg) -> void { 63 | auto time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] "); 64 | edit->append(time + msg); 65 | if (!edit->textCursor().hasSelection()) edit->moveCursor(QTextCursor::End); 66 | if (++lineCount > 50000) { 67 | lineCount = 0; 68 | edit->clear(); 69 | } 70 | }; 71 | 72 | qInstallMessageHandler(myMsgHandler); 73 | } 74 | 75 | int main(int argc, char *argv[]) 76 | { 77 | QApplication app(argc, argv); 78 | 79 | initializeDebugEnveriment(); 80 | 81 | QTimer timer; 82 | QObject::connect(&timer, &QTimer::timeout, &timer, []{ 83 | static int count = 1; 84 | qDebug() << "This is Qt Debug message! Count:" << count++; 85 | }); 86 | timer.start(1000); 87 | 88 | QTimer otherTimer; 89 | QObject::connect(&otherTimer, &QTimer::timeout, &otherTimer, []{ 90 | static int count = 1; 91 | printf("This is printf stdout message! Count: %d", count++); 92 | fflush(stdout); 93 | }); 94 | otherTimer.start(1000); 95 | 96 | return app.exec(); 97 | } 98 | -------------------------------------------------------------------------------- /InputMethodEventCatch/InputMethodEventCatch.pro: -------------------------------------------------------------------------------- 1 | QT += gui widgets 2 | 3 | CONFIG += c++11 4 | 5 | # You can make your code fail to compile if it uses deprecated APIs. 6 | # In order to do so, uncomment the following line. 7 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 8 | 9 | SOURCES += \ 10 | inputmethodeventcatch.cpp \ 11 | main.cpp 12 | 13 | # Default rules for deployment. 14 | qnx: target.path = /tmp/$${TARGET}/bin 15 | else: unix:!android: target.path = /opt/$${TARGET}/bin 16 | !isEmpty(target.path): INSTALLS += target 17 | 18 | HEADERS += \ 19 | inputmethodeventcatch.h 20 | -------------------------------------------------------------------------------- /InputMethodEventCatch/inputmethodeventcatch.cpp: -------------------------------------------------------------------------------- 1 | #include "inputmethodeventcatch.h" 2 | 3 | #include 4 | 5 | static int key2code(const QChar &key) 6 | { 7 | switch (key.toLatin1()) 8 | { 9 | case 'q': case 'Q': return Qt::Key_Q; 10 | case 'w': case 'W': return Qt::Key_W; 11 | case 'e': case 'E': return Qt::Key_E; 12 | case 'r': case 'R': return Qt::Key_R; 13 | case 't': case 'T': return Qt::Key_T; 14 | case 'y': case 'Y': return Qt::Key_Y; 15 | case 'u': case 'U': return Qt::Key_U; 16 | case 'i': case 'I': return Qt::Key_I; 17 | case 'o': case 'O': return Qt::Key_O; 18 | case 'p': case 'P': return Qt::Key_P; 19 | case 'a': case 'A': return Qt::Key_A; 20 | case 's': case 'S': return Qt::Key_S; 21 | case 'd': case 'D': return Qt::Key_D; 22 | case 'f': case 'F': return Qt::Key_F; 23 | case 'g': case 'G': return Qt::Key_G; 24 | case 'h': case 'H': return Qt::Key_H; 25 | case 'j': case 'J': return Qt::Key_J; 26 | case 'k': case 'K': return Qt::Key_K; 27 | case 'l': case 'L': return Qt::Key_L; 28 | case 'z': case 'Z': return Qt::Key_Z; 29 | case 'x': case 'X': return Qt::Key_X; 30 | case 'c': case 'C': return Qt::Key_C; 31 | case 'v': case 'V': return Qt::Key_V; 32 | case 'b': case 'B': return Qt::Key_B; 33 | case 'n': case 'N': return Qt::Key_N; 34 | case 'm': case 'M': return Qt::Key_M; 35 | } 36 | 37 | return Qt::Key_unknown; 38 | } 39 | 40 | InputMethodEventCatch::InputMethodEventCatch(QObject *parent) 41 | : QObject{parent} 42 | { 43 | 44 | } 45 | 46 | InputMethodEventCatch::~InputMethodEventCatch() 47 | { 48 | if (m_target) m_target->removeEventFilter(this); 49 | } 50 | 51 | QObject *InputMethodEventCatch::target() 52 | { 53 | return m_target; 54 | } 55 | 56 | void InputMethodEventCatch::setTarget(QObject *target) 57 | { 58 | if (!target) return; 59 | 60 | if (m_target != target) { 61 | if (m_target) m_target->removeEventFilter(this); 62 | target->installEventFilter(this); 63 | m_target = target; 64 | emit targetChanged(); 65 | } 66 | } 67 | 68 | bool InputMethodEventCatch::eventFilter(QObject *obj, QEvent *event) 69 | { 70 | if (event->type() == QEvent::InputMethod) { 71 | QInputMethodEvent *input = static_cast(event); 72 | if (input->preeditString().isEmpty()) { 73 | emit inputMethodEventCommitted(input->commitString()); 74 | } else { 75 | QString key; 76 | for (const auto &attr: input->attributes()) { 77 | if (attr.type == QInputMethodEvent::AttributeType::Cursor && attr.start > 0) { 78 | key = input->preeditString().mid(attr.start - 1, attr.length); 79 | break; 80 | } 81 | } 82 | if (key.size() == 1) 83 | emit inputMethodEventPressed(key2code(*key.begin()), key); 84 | } 85 | } 86 | return QObject::eventFilter(obj, event); 87 | } 88 | -------------------------------------------------------------------------------- /InputMethodEventCatch/inputmethodeventcatch.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTMETHODEVENTCATCH_H 2 | #define INPUTMETHODEVENTCATCH_H 3 | 4 | #include 5 | 6 | class InputMethodEventCatch : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged) 11 | 12 | public: 13 | explicit InputMethodEventCatch(QObject *parent = nullptr); 14 | ~InputMethodEventCatch(); 15 | 16 | QObject *target(); 17 | void setTarget(QObject *target); 18 | 19 | bool eventFilter(QObject *obj, QEvent *event); 20 | 21 | signals: 22 | void targetChanged(); 23 | void inputMethodEventPressed(int code, const QString &key); 24 | void inputMethodEventCommitted(const QString &commitString); 25 | 26 | private: 27 | QObject *m_target = nullptr; 28 | }; 29 | 30 | #endif // INPUTMETHODEVENTCATCH_H 31 | -------------------------------------------------------------------------------- /InputMethodEventCatch/main.cpp: -------------------------------------------------------------------------------- 1 | #include "inputmethodeventcatch.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | QApplication app(argc, argv); 10 | 11 | QTextEdit edit; 12 | InputMethodEventCatch editCatch; 13 | QObject::connect(&editCatch, &InputMethodEventCatch::inputMethodEventPressed, &editCatch, [](int code, const QString &key){ 14 | qDebug() << "inputMethodEventPressed" << Qt::Key(code) << key; 15 | }); 16 | QObject::connect(&editCatch, &InputMethodEventCatch::inputMethodEventCommitted, &editCatch, [](const QString &commitString){ 17 | qDebug() << "inputMethodEventCommitted" << commitString; 18 | }); 19 | editCatch.setTarget(&edit); 20 | edit.show(); 21 | 22 | return app.exec(); 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 mengps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /N-order-BezierCurve/N-order-BezierCurve.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2021-03-29T23:23:56 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = N-order-BezierCurve 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++11 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | beziercurve.cpp 30 | 31 | HEADERS += \ 32 | beziercurve.h 33 | 34 | # Default rules for deployment. 35 | qnx: target.path = /tmp/$${TARGET}/bin 36 | else: unix:!android: target.path = /opt/$${TARGET}/bin 37 | !isEmpty(target.path): INSTALLS += target 38 | -------------------------------------------------------------------------------- /N-order-BezierCurve/beziercurve.cpp: -------------------------------------------------------------------------------- 1 | #include "beziercurve.h" 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /** 13 | * @brief createNBezierCurve 生成N阶贝塞尔曲线点 14 | * @param src 源贝塞尔控制点 15 | * @param dest 目的贝塞尔曲线点 16 | * @param precision 生成精度 17 | */ 18 | static void createNBezierCurve(const QList &src, QList &dest, qreal precision) 19 | { 20 | if (src.size() <= 0) return; 21 | 22 | //清空 23 | QList().swap(dest); 24 | 25 | for (qreal t = 0; t < 1.0000; t += precision) { 26 | int size = src.size(); 27 | QVector coefficient(size, 0); 28 | coefficient[0] = 1.000; 29 | qreal u1 = 1.0 - t; 30 | 31 | for (int j = 1; j <= size - 1; j++) { 32 | qreal saved = 0.0; 33 | for (int k = 0; k < j; k++){ 34 | qreal temp = coefficient[k]; 35 | coefficient[k] = saved + u1 * temp; 36 | saved = t * temp; 37 | } 38 | coefficient[j] = saved; 39 | } 40 | 41 | QPointF resultPoint; 42 | for (int i = 0; i < size; i++) { 43 | QPointF point = src.at(i); 44 | resultPoint = resultPoint + point * coefficient[i]; 45 | } 46 | 47 | dest.append(resultPoint); 48 | } 49 | } 50 | 51 | class BezierCurvePrivate 52 | { 53 | public: 54 | BezierCurvePrivate() = default; 55 | 56 | //完成控制点构成 57 | bool m_completed = false; 58 | bool m_mousePressed = false; 59 | int m_currentControlPointIndex = -1; 60 | qreal m_precision = 0.1; 61 | QList m_controlPoints; 62 | QList m_bezierCurve; 63 | }; 64 | 65 | BezierCurve::BezierCurve(QWidget *parent) 66 | : QWidget(parent) 67 | { 68 | d = new BezierCurvePrivate; 69 | 70 | QComboBox *comboBox = new QComboBox(this); 71 | connect(comboBox, QOverload::of(&QComboBox::activated), this, [=](int index) { 72 | d->m_precision = comboBox->itemText(index).toDouble(); 73 | createNBezierCurve(d->m_controlPoints, d->m_bezierCurve, d->m_precision); 74 | update(); 75 | }); 76 | comboBox->addItem(QString::number(0.1)); 77 | comboBox->addItem(QString::number(0.01)); 78 | comboBox->addItem(QString::number(0.001)); 79 | QLabel *label = new QLabel("精度:", this); 80 | QHBoxLayout *layout = new QHBoxLayout; 81 | layout->addWidget(label); 82 | layout->addWidget(comboBox); 83 | 84 | QWidget *widget = new QWidget(this); 85 | widget->resize(150, 50); 86 | widget->setLayout(layout); 87 | 88 | resize(800, 600); 89 | } 90 | 91 | BezierCurve::~BezierCurve() 92 | { 93 | if (d) delete d; 94 | } 95 | 96 | void BezierCurve::paintEvent(QPaintEvent *event) 97 | { 98 | Q_UNUSED(event); 99 | 100 | QPainter painter(this); 101 | painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); 102 | painter.save(); 103 | painter.setBrush(QBrush(Qt::red)); 104 | QFontMetrics metrics(painter.font()); 105 | for (auto i = 0; i < d->m_controlPoints.size(); i++) { 106 | painter.setPen(Qt::red); 107 | painter.drawEllipse(d->m_controlPoints.at(i), 10.0, 10.0); 108 | painter.setPen(Qt::white); 109 | QString number = QString::number(i); 110 | auto rect = metrics.boundingRect(number); 111 | painter.drawText(d->m_controlPoints.at(i) + QPointF(-rect.width() / 2, rect.height() / 2 - 1.0), number); 112 | } 113 | painter.restore(); 114 | 115 | if (d->m_controlPoints.size() >= 2) { 116 | QPainterPath curve; 117 | curve.moveTo(d->m_bezierCurve.at(0)); 118 | for (auto i = 1; i < d->m_bezierCurve.size(); i++) {; 119 | curve.lineTo(d->m_bezierCurve.at(i)); 120 | } 121 | auto pen = painter.pen(); 122 | pen.setColor(Qt::blue); 123 | pen.setWidth(2.0); 124 | painter.setPen(pen); 125 | painter.drawPath(curve); 126 | } 127 | } 128 | 129 | void BezierCurve::mousePressEvent(QMouseEvent *event) 130 | { 131 | if (event->buttons() & Qt::LeftButton && event->pos().y() > 50) { 132 | d->m_mousePressed = true; 133 | if (d->m_completed) { 134 | d->m_currentControlPointIndex = -1; 135 | auto pos = event->pos(); 136 | for (auto i = 0; i < d->m_controlPoints.size(); i++) { 137 | auto point = d->m_controlPoints.at(i); 138 | //判断是否在控制点上 139 | if (qAbs(qSqrt(qPow(pos.x() - point.x(), 2) + qPow(pos.y() - point.y(), 2))) < 10.0000) { 140 | d->m_currentControlPointIndex = i; 141 | break; 142 | } 143 | } 144 | } else { 145 | d->m_controlPoints.append(event->pos()); 146 | //控制点增加了,需要更新 147 | createNBezierCurve(d->m_controlPoints, d->m_bezierCurve, d->m_precision); 148 | update(); 149 | } 150 | } else if (event->buttons() & Qt::RightButton) { 151 | d->m_completed = true; 152 | } 153 | } 154 | 155 | void BezierCurve::mouseMoveEvent(QMouseEvent *event) 156 | { 157 | if (event->buttons() & Qt::LeftButton 158 | && d->m_mousePressed 159 | && d->m_currentControlPointIndex != -1 160 | && event->pos().y() > 50) { 161 | if (d->m_currentControlPointIndex < d->m_controlPoints.size()) { 162 | d->m_controlPoints[d->m_currentControlPointIndex] = event->pos(); 163 | createNBezierCurve(d->m_controlPoints, d->m_bezierCurve, d->m_precision); 164 | update(); 165 | } 166 | } 167 | } 168 | 169 | void BezierCurve::mouseReleaseEvent(QMouseEvent *event) 170 | { 171 | d->m_currentControlPointIndex = -1; 172 | if (event->buttons() & Qt::LeftButton) { 173 | d->m_mousePressed = false; 174 | } 175 | } 176 | 177 | void BezierCurve::keyPressEvent(QKeyEvent *event) 178 | { 179 | if (event->key() == Qt::Key_Escape) { 180 | d->m_completed = false; 181 | QList().swap(d->m_controlPoints); 182 | QList().swap(d->m_bezierCurve); 183 | update(); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /N-order-BezierCurve/beziercurve.h: -------------------------------------------------------------------------------- 1 | #ifndef BEZIERCURVE_H 2 | #define BEZIERCURVE_H 3 | 4 | #include 5 | 6 | QT_FORWARD_DECLARE_CLASS(BezierCurvePrivate); 7 | 8 | class BezierCurve : public QWidget 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | BezierCurve(QWidget *parent = nullptr); 14 | ~BezierCurve() override; 15 | 16 | protected: 17 | virtual void paintEvent(QPaintEvent *event) override; 18 | virtual void mousePressEvent(QMouseEvent *event) override; 19 | virtual void mouseMoveEvent(QMouseEvent *event) override; 20 | virtual void mouseReleaseEvent(QMouseEvent *event) override; 21 | virtual void keyPressEvent(QKeyEvent *event) override; 22 | 23 | private: 24 | BezierCurvePrivate *d = nullptr; 25 | }; 26 | 27 | #endif // BEZIERCURVE_H 28 | -------------------------------------------------------------------------------- /N-order-BezierCurve/main.cpp: -------------------------------------------------------------------------------- 1 | #include "beziercurve.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication app(argc, argv); 7 | BezierCurve bezierWidget; 8 | bezierWidget.show(); 9 | 10 | return app.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QtExamples 2 | 3 | 提供一些有用Qt示例 4 | 5 | ------ 6 | 7 | ### 所有示例预览 8 | 9 | [预览图均为GIF,较大](https://github.com/mengps/QtExamples/blob/master/demonstrate/demonstrate.md) 10 | 11 | ------ 12 | 13 | ### 示例列表 14 | 15 | - N-order-BezierCurve Qt 中实现任意N阶贝塞尔曲线绘制 & 动态调节 16 | 17 | - TimerTask 无事件循环或非 GUI / Qt 线程中使用 QTimer 18 | 19 | - CaptureStdPrint Qt 中捕获三方库&自身标准打印方法 20 | 21 | - InputMethodEventCatch Qt / Qml 中捕获(中文)输入法事件(按下 & 提交) 22 | 23 | - SystemThemeDetection (Qt5 / Qt6) 系统主题检测(Dark / Light) & 主题变化感知 24 | 25 | ------ 26 | 27 | ### 许可证 28 | 29 | 使用 `MIT LICENSE` 30 | 31 | ------ 32 | 33 | ### 开发环境 34 | 35 | windows 11,Qt 5.15.2 -------------------------------------------------------------------------------- /SystemThemeDetection/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | CMakeLists.txt.user* 41 | 42 | # xemacs temporary files 43 | *.flc 44 | 45 | # Vim temporary files 46 | .*.swp 47 | 48 | # Visual Studio generated files 49 | *.ib_pdb_index 50 | *.idb 51 | *.ilk 52 | *.pdb 53 | *.sln 54 | *.suo 55 | *.vcproj 56 | *vcproj.*.*.user 57 | *.ncb 58 | *.sdf 59 | *.opensdf 60 | *.vcxproj 61 | *vcxproj.* 62 | 63 | # MinGW generated files 64 | *.Debug 65 | *.Release 66 | 67 | # Python byte code 68 | *.pyc 69 | 70 | # Binaries 71 | # -------- 72 | *.dll 73 | *.exe 74 | 75 | -------------------------------------------------------------------------------- /SystemThemeDetection/SystemThemeDetection.pro: -------------------------------------------------------------------------------- 1 | QT = core gui widgets 2 | 3 | CONFIG += c++11 cmdline 4 | 5 | # You can make your code fail to compile if it uses deprecated APIs. 6 | # In order to do so, uncomment the following line. 7 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 8 | 9 | SOURCES += \ 10 | main.cpp 11 | 12 | # Default rules for deployment. 13 | qnx: target.path = /tmp/$${TARGET}/bin 14 | else: unix:!android: target.path = /opt/$${TARGET}/bin 15 | !isEmpty(target.path): INSTALLS += target 16 | 17 | HEADERS += 18 | -------------------------------------------------------------------------------- /SystemThemeDetection/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef Q_OS_WIN 6 | #include 7 | #include 8 | #include 9 | #pragma comment(lib, "Dwmapi.lib") 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | class ThemeHelper : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | Q_PROPERTY(QColor themeColor READ themeColor NOTIFY themeColorChanged) 21 | Q_PROPERTY(ThemeHelper::ColorScheme colorScheme READ colorScheme NOTIFY colorSchemeChanged) 22 | 23 | public: 24 | enum class ColorScheme { 25 | None = 0, 26 | Dark = 1, 27 | Light = 2 28 | }; 29 | Q_ENUM(ColorScheme); 30 | 31 | ThemeHelper(QObject *parent = nullptr) : QObject { parent } 32 | { 33 | m_themeColor = getThemeColor(); 34 | m_colorScheme = getColorScheme(); 35 | 36 | #ifdef Q_OS_WIN 37 | m_timer.start(200, this); 38 | #endif 39 | } 40 | 41 | Q_INVOKABLE ThemeHelper::ColorScheme getColorScheme() const 42 | { 43 | #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) 44 | const auto scheme = QGuiApplication::styleHints()->colorScheme(); 45 | return scheme == Qt::ColorScheme::Dark ? ColorScheme::Dark : ColorScheme::Light; 46 | #else 47 | #ifdef Q_OS_WIN 48 | //0:深色 - 1:浅色 49 | return !m_colorSchemeSettings.value("AppsUseLightTheme").toBool() ? ColorScheme::Dark : ColorScheme::Light; 50 | #else //linux 51 | const QPalette defaultPalette; 52 | const auto text = defaultPalette.color(QPalette::WindowText); 53 | const auto window = defaultPalette.color(QPalette::Window); 54 | return text.lightness() > window.lightness() ? ColorScheme::Dark : ColorScheme::Light; 55 | #endif // Q_OS_WIN 56 | #endif // QT_VERSION 57 | } 58 | 59 | Q_INVOKABLE QColor getThemeColor() const 60 | { 61 | #ifdef Q_OS_WIN 62 | return QColor::fromRgb(m_themeColorSettings.value("ColorizationColor").toUInt()); 63 | #endif 64 | } 65 | 66 | QColor themeColor() const 67 | { 68 | return m_themeColor; 69 | } 70 | 71 | ThemeHelper::ColorScheme colorScheme() 72 | { 73 | return m_colorScheme; 74 | } 75 | 76 | signals: 77 | void themeColorChanged(); 78 | void colorSchemeChanged(); 79 | 80 | #ifdef Q_OS_WIN 81 | protected: 82 | virtual void timerEvent(QTimerEvent *) 83 | { 84 | auto nowThemeColor = getThemeColor(); 85 | if (nowThemeColor != m_themeColor) { 86 | m_themeColor = nowThemeColor; 87 | emit themeColorChanged(); 88 | } 89 | 90 | auto nowColorScheme = getColorScheme() ; 91 | if (nowColorScheme != m_colorScheme) { 92 | m_colorScheme = nowColorScheme; 93 | emit colorSchemeChanged(); 94 | } 95 | } 96 | #endif 97 | 98 | private: 99 | QColor m_themeColor; 100 | ColorScheme m_colorScheme = ColorScheme::None; 101 | 102 | #ifdef Q_OS_WIN 103 | QBasicTimer m_timer; 104 | QSettings m_themeColorSettings { QSettings::UserScope, "Microsoft", "Windows\\DWM" }; 105 | QSettings m_colorSchemeSettings { QSettings::UserScope, "Microsoft", "Windows\\CurrentVersion\\Themes\\Personalize" }; 106 | #endif 107 | }; 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | QApplication app(argc, argv); 112 | 113 | QLabel *window = new QLabel; 114 | window->setFixedSize(640, 480); 115 | window->setText("主题颜色"); 116 | window->setFont(QFont("微软雅黑", 32)); 117 | window->setAlignment(Qt::AlignCenter); 118 | window->show(); 119 | 120 | auto setColorScheme = [window](bool isDark){ 121 | #ifdef Q_OS_WIN 122 | //win11支持 123 | DwmSetWindowAttribute(reinterpret_cast(window->winId()), 20, &isDark, sizeof(isDark)); 124 | #endif 125 | auto color = isDark ? "black" : "white"; 126 | auto palette = window->palette(); 127 | palette.setColor(QPalette::Window, color); 128 | window->setPalette(palette); 129 | }; 130 | 131 | auto setThemeColor = [window](const QString &color){ 132 | auto palette = window->palette(); 133 | palette.setColor(QPalette::WindowText, color); 134 | window->setPalette(palette); 135 | }; 136 | 137 | ThemeHelper *helper = new ThemeHelper; 138 | QObject::connect(helper, &ThemeHelper::colorSchemeChanged, [helper, setColorScheme]{ 139 | qDebug() << "colorSchemeChanged:" << helper->colorScheme(); 140 | setColorScheme(helper->colorScheme() == ThemeHelper::ColorScheme::Dark); 141 | }); 142 | QObject::connect(helper, &ThemeHelper::themeColorChanged, [helper, setThemeColor]{ 143 | qDebug() << "themeColorChanged:" << helper->themeColor(); 144 | setThemeColor(helper->themeColor().name()); 145 | }); 146 | 147 | setColorScheme(helper->colorScheme() == ThemeHelper::ColorScheme::Dark); 148 | setThemeColor(helper->themeColor().name()); 149 | 150 | return app.exec(); 151 | } 152 | 153 | #include "main.moc" 154 | -------------------------------------------------------------------------------- /TimerTask/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /TimerTask/TimerTask.pro: -------------------------------------------------------------------------------- 1 | QT -= gui 2 | 3 | CONFIG += c++11 console 4 | CONFIG -= app_bundle 5 | 6 | # The following define makes your compiler emit warnings if you use 7 | # any Qt feature that has been marked deprecated (the exact warnings 8 | # depend on your compiler). Please consult the documentation of the 9 | # deprecated API in order to know how to port your code away from it. 10 | DEFINES += QT_DEPRECATED_WARNINGS 11 | 12 | # You can also make your code fail to compile if it uses deprecated APIs. 13 | # In order to do so, uncomment the following line. 14 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 15 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 16 | 17 | SOURCES += \ 18 | main.cpp 19 | 20 | # Default rules for deployment. 21 | qnx: target.path = /tmp/$${TARGET}/bin 22 | else: unix:!android: target.path = /opt/$${TARGET}/bin 23 | !isEmpty(target.path): INSTALLS += target 24 | -------------------------------------------------------------------------------- /TimerTask/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | class TimerTask 9 | { 10 | public: 11 | TimerTask() 12 | { 13 | m_thread.start(); 14 | } 15 | 16 | ~TimerTask() 17 | { 18 | for (auto &timer: m_timers) { 19 | if (timer->isActive()) timer->stop(); 20 | timer->deleteLater(); 21 | } 22 | 23 | m_thread.quit(); 24 | m_thread.wait(); 25 | } 26 | 27 | template 28 | void addTask(Task task, int interval, bool repeat = true) 29 | { 30 | QTimer *timer = new QTimer; 31 | timer->moveToThread(&m_thread); 32 | timer->setInterval(interval); 33 | timer->setSingleShot(!repeat); 34 | QObject::connect(timer, &QTimer::timeout, task); 35 | 36 | if (!repeat) 37 | QObject::connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater); 38 | else 39 | m_timers.append(timer); 40 | 41 | QMetaObject::invokeMethod(timer, "start"); 42 | } 43 | 44 | private: 45 | QThread m_thread; 46 | QList m_timers; 47 | }; 48 | 49 | void printCurrentThreadId() { 50 | qDebug() << "TimerTask thread id =" << QThread::currentThreadId(); 51 | } 52 | 53 | int main(int argc, char *argv[]) 54 | { 55 | QCoreApplication app(argc, argv); 56 | 57 | std::thread thread([]{ 58 | qDebug() << "std::thread id =" << QThread::currentThreadId(); 59 | QTimer timer; 60 | timer.setInterval(1000); 61 | QObject::connect(&timer, &QTimer::timeout, []{ 62 | qDebug() << "std::thread 1000 ms time out"; 63 | }); 64 | QEventLoop eventLoop; 65 | timer.start(); 66 | eventLoop.exec(); 67 | }); 68 | 69 | TimerTask tasks; 70 | tasks.addTask([]{ qDebug() << "1000 ms time out"; }, 1000, true); 71 | tasks.addTask([]{ qDebug() << "2000 ms time out"; }, 2000, true); 72 | tasks.addTask(&printCurrentThreadId, 0, false); 73 | 74 | qDebug() << "main app thread id =" << QThread::currentThreadId(); 75 | 76 | while (true) { 77 | QThread::msleep(1000); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /demonstrate/BezierCurve.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengps/QtExamples/e26e0a0505bb297f4fcffda33163b9a62b1d28b7/demonstrate/BezierCurve.gif -------------------------------------------------------------------------------- /demonstrate/CaptureStdPrint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengps/QtExamples/e26e0a0505bb297f4fcffda33163b9a62b1d28b7/demonstrate/CaptureStdPrint.gif -------------------------------------------------------------------------------- /demonstrate/InputMethodEventCatch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengps/QtExamples/e26e0a0505bb297f4fcffda33163b9a62b1d28b7/demonstrate/InputMethodEventCatch.gif -------------------------------------------------------------------------------- /demonstrate/SystemThemeDetection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengps/QtExamples/e26e0a0505bb297f4fcffda33163b9a62b1d28b7/demonstrate/SystemThemeDetection.gif -------------------------------------------------------------------------------- /demonstrate/demonstrate.md: -------------------------------------------------------------------------------- 1 | ## 示例预览 2 | 3 | - N-order-BezierCurve Qt 中实现任意N阶贝塞尔曲线绘制 & 动态调节 4 | 5 |
. 6 | 7 | - CaptureStdPrint Qt 中捕获三方库&自身标准打印方法 8 | 9 |
10 | 11 | - InputMethodEventCatch Qt / Qml 中捕获(中文)输入法事件(按下 & 提交) 12 | 13 |
14 | 15 | - SystemThemeDetection (Qt5 / Qt6) 系统主题检测(Dark / Light) & 主题变化感知 16 | 17 |
--------------------------------------------------------------------------------