1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/fmldd-Quick-Event

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Быстрый выпуск события (QuickEvent)

Примечание: при использовании Qt::AutoConnection, при публикации сообщения между потоками используется асинхронный запуск.

3.1.4. Приём и обработка сообщений

Для классов, которые вводят функции публикации и подписки, можно реализовать функцию обработки событий event_ + имя сообщения, чтобы принимать и обрабатывать отправленные сообщения publishEvent.

private slots:
    void event_show_time(const QDateTime &time);
...
void Dialog::event_show_time(const QDateTime &time) {
    box->setText(time.toString());
    box->show();
}

Примечание: необходимо, чтобы списки параметров функций совпадали.

3.1.5. Отмена подписки

Класс QuickApplication предоставляет метод UnsubscribeEvent для отмены подписки на сообщения. Макрос QUICK_DESTRUCT позволяет легко отменять подписку.

Определение UnsubscribeEvent:

bool QuickApplication::UnsubscribeEvent(QObject *listener, QByteArray eventName) {
    QWriteLocker loker(&s_lock);
    bool result = false;
    if(s_quick_event_pool.contains(eventName)) {
        QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
        tmplist.remove(tmplist.key(listener));
        s_quick_event_pool.insert(eventName, tmplist);
        result = true;
    }
    if(s_quick_event_pool_high.contains(eventName)) {
        QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
        tmplist.remove(tmplist.key(listener));
        s_quick_event_pool.insert(eventName, tmlist);
        result = true;
    }
    if(s_quick_event_pool_low.contains(eventName)) {
        QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
        tmplist.remove(tmplist.key(listener));
        s_quick_event_pool.insert(eventName, tmlist);
        result = true;
    }
    return result;
}

bool QuickApplication::UnsubscribeEvent(QObject *listener) {
    QWriteLocker loker(&s_lock);
    foreach (auto var, s_quick_event_pool.keys()) {
        s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
    }
    foreach (auto var, s_quick_event_pool_low.keys()) {
        s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
    }
    foreach (auto var, s_quick_event_pool_high.keys()) {
        s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
    }
    return true;
}

Определение QUICK_DESTRUCT:

#define QUICK_DESTRUCT \
    QuickApplication::UnsubscribeEvent(this);\

3.1.6. Приоритет подписки

По умолчанию, как и в случае с сигналами и слотами Qt, сообщения принимаются и обрабатываются в порядке подписки. Класс QuickEvent разделяет подписчиков на три категории: высокий уровень, по умолчанию и низкий уровень. После публикации сообщения все подписчики выполняются последовательно в порядке высокого уровня подписки, подписки по умолчанию и низкого уровня. При этом у подписчиков высокого и низкого уровней есть свой порядок, а у подписчиков по умолчанию порядка нет.

  static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool_high;
  static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool;
  static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool_low;

3.1.7. Типы публикации и подписки

При использовании QuickEvent поддерживается четыре режима публикации и подписки. Обратите внимание, что при использовании QuickEvent, как правило, неизвестно, какой код использует другая сторона. Будьте осторожны при использовании блокирующей публикации, чтобы избежать взаимоблокировки! 3.2. Контроль класса заполнения

Quick Event код модели предоставляет два управляющих класса: QuickWork, QuickScript.

3.2.1. QuickScript и его подклассы:

Наследуется от QThread скриптового базового класса, используется следующим образом:

  • Инициализация:

    • Экземпляр.
    • Указать рендеринг окна пользовательского интерфейса (если есть).
    • Привязать QThread::finished().
  • Выполнение:

    • Запустить рендеринг оконного взаимодействия.
    • Передать данные и параметры для расчёта после взаимодействия с рендерингом.
    • Выполнить расчёт скрипта.
    • Начать рендеринг взаимодействия окон.
    • Завершить рендеринг взаимодействия окон.
  • Завершение:

    • deleteLater();

Следует отметить: весь класс находится в новом потоке, за исключением метода Execute(), который находится в родительском потоке. Предоставляются интерфейсы Wait и Wake, которые можно использовать для вставки взаимодействия в расчёт скрипта, а также интерфейс SignalProgressIn для печати хода выполнения расчёта скрипта.

3.2.2. QuickWork и его подклассы:

Позволяет отражать себя через QUICK_AUT макрос и QuickController, что позволяет автоматически создавать экземпляры управляющих классов.

Класс QuickController используется для отражения и реализует автоматическое создание экземпляров QuickWork и его подклассов. Поток, к которому принадлежит QuickWork, может быть определён с помощью move_type.

QUICK_AUT макрос выполняет следующие функции:

  1. Регистрирует свой тип в системе метаобъектов QT.
  2. Перед основным методом регистрирует своё имя класса в списке необходимых для отражения классов. После создания объекта QuickController будет отражён каждый зарегистрированный класс, и будет выполнена обработка потока принадлежности.

Определение QUICK_AUTO:

#define QUICK_AUTO(ClassName)
Q_DECLARE_METATYPE(ClassName *)
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();
static void *ThisPtr##ClassName = QuickController::NewInstance(#ClassName);

#define QUICK_AUTO_H(ClassName,value)
Q_DECLARE_METATYPE(ClassName *)
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();
static void *ThisPtr##ClassName = QuickController::NewInstance(
                                      #ClassName,QuickController::High,value);

#define QUICK_AUTO_L(ClassName,value)
Q_DECLARE_METATYPE(ClassName *)
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();
static void *ThisPtr##ClassName = QuickController::NewInstance(
                                      #ClassName,QuickController::Low,value);

Порядок отражения QuickWork и его подклассов аналогичен порядку подписки. Он делится на три уровня: высокий приоритет, по умолчанию, низкий приоритет. Сначала отражаются классы с высоким приоритетом, затем классы по умолчанию и, наконец, классы с низким приоритетом. В классе по умолчанию порядок не определён, в то время как в классах с высоким и низким приоритетом порядок определён.

Принцип заключается в том, что C/C++ не может выполнять сложные операции перед main, но можно выполнить часть кода перед main с использованием статических переменных и функций для присвоения значений. Однако эта операция может выполняться несколько раз, поэтому список отражённых классов использует контейнер Set для предотвращения дублирования вставок.

Примечание 1: после наследования от QuickWork можно переопределить метод QuickWork::start, который обязательно будет вызван в потоке назначения.

Примечание 2: если вставить повторяющиеся последовательности с высоким или низким приоритетом, будет выведено повторяющееся сообщение, и только один из них будет отражён.

3.3. Инициализация QuickEvent

Для использования только функции публикации и подписки QuickEvent нет необходимости инициализировать. Для управления классом отражения и жизненного цикла QuickEvent требуется инициализация в основной функции.

Макросы QUICK_INSTALL() и QUICK_INSTALL_DETAILED() могут использоваться для инициализации. QUICK_INSTALL_DETAILED() добавляет печать более подробной информации о QuickEvent, такой как версия, информация о деталях публикации и подписки, что удобно для отладки.

Пример:

#include "dialog.h"
#include <QuickEvent>
#include <QFile>
int main(int argc, char **argv) {
    QApplication a(argc, argv);
    QUICK_INSTALL()// QUICK_INSTALL  QUICK_INSTALL_DETAIL
    QUICK_SETSTYLE("../../Examples/resource/Style/gray_style.qss")
    Dialog dialog;
    dialog.show();
    return a.exec();
}

3.4. Краткое описание всех макросов QuickEvent

Макрос QuickEvent Описание
QUICK_AUTO(ClassName) Регистрация типа в системе метаобъектов Qt и создание экземпляра самого себя (по умолчанию).
QUICK_AUTO_H(ClassName, value) Регистрация типа в системе метаобъектов Qt и создание экземпляра самого себя (высокий приоритет).
QUICK_AUTO_L(ClassName, value) Регистрация типа в системе метаобъектов Qt и создание экземпляра самого себя (низкий приоритет).
QUICK_EVENT(PARENTNAME) Позволяет классу поддерживать функции публикации и подписки.
QUICK_DESTRUCT Отменяет все подписки самого себя.
QUICK_SUBSCRIBE_OBJ(obj, name) Удобная подписка, подписчик и имя подписки (подписчик может быть собственной внутренней переменной).
QUICK_SUBSCRIBE(name) Простая подписка на себя.
QUICK_SUBSCRIBE_H(name, lev) Удобная высокая подписка на самого себя, lev указывает на сортировку высокой подписки, при повторении предыдущая удаляется.
QUICK_SUBSCRIBE_L(name, lev) Удобная низкая подписка на самого себя, lev указывает на сортировку низкой подписки, при повторении предыдущая удаляется.
QUICK_PUBLISH1(name, arg1) Публикация по умолчанию с одним параметром.
QUICK_PUBLISH3(name,arg1,arg2,arg3) режим публикации по умолчанию, 3 параметра
QUICK_PUBLISH4(name,arg1,arg2,arg3,arg4) режим публикации по умолчанию, 4 параметра
QUICK_Direct_PUBLISH1(name,arg1) синхронный режим публикации, 1 параметр
QUICK_Direct_PUBLISH2(name,arg1,arg2) синхронный режим публикации, 2 параметра
QUICK_Direct_PUBLISH3(name,arg1,arg2,arg3) синхронный режим публикации, 3 параметра
QUICK_Queued_PUBLISH1(name,arg1) асинхронный режим публикации, 1 параметр
QUICK_Queued_PUBLISH2(name,arg1,arg2) асинхронный режим публикации, 2 параметра
QUICK_Queued_PUBLISH3(name,arg1,arg2,arg3) асинхронный режим публикации, 3 параметра
QUICK_BlockingQueued_PUBLISH1(name,arg1) асинхронный ожидающий режим публикации, 1 параметр
QUICK_BlockingQueued_PUBLISH2(name,arg1,arg2) асинхронный ожидающий режим публикации, 2 параметра
QUICK_BlockingQueued_PUBLISH3(name,arg1,arg2,arg3) асинхронный ожидающий режим публикации, 3 параметра
- -
QUICK_GETSET(name,type) интерфейс быстрого чтения и записи переменных
QUICK_INITIAL_VAR(name,type) быстрый интерфейс определения, чтения и записи переменных
QUICK_GETSET_Object(name,type) интерфейс быстрой записи и чтения указателей
- -
QUICK_INSTALL() инициализация QuickController
QUICK_INSTALL_DETAILED() подробная инициализация QuickController, вывод подробной информации
QUICK_SETSTYLE(name) инициализация таблицы стилей

Версия 4. Обновление

Обновление версии 2.0.0

  1. Введение шаблона с переменным числом параметров сделало определение функций обработки событий (event_ + название сообщения) более гибким;
  2. Поддерживаются следующие типы публикаций:
    • синхронная публикация [DirectConnection];
    • асинхронная публикация [QueuedConnection];
    • асинхронная ожидающая публикация [BlockingQueuedConnection].

Проблемы:

— 1. После публикации события не всегда удаётся точно определить, какая функция обработки события будет вызвана. Проблема заключается в том, что система метаобъектов QT слишком сильно отличается от метода typeid() в C++. В настоящее время рекомендуется не перегружать функции обработки событий с одинаковым количеством параметров. Например:

void event_show_time(const QDateTime &time, QList<int> list);
void event_show_time(const QDateTime &time, QList<QString> list);

Примечание:

  1. При передаче параметров через потоки необходимо использовать известные типы QT.
  2. Как и в случае с QMetaObject::QMetaCallEvent, при обработке асинхронных вызовов через потоки QuickEvent также создаёт копии переменных в куче.
  3. Подписчик может быть не один, поэтому используется QSharedPointer::QVariant для совместного использования этой области памяти. Поэтому передаваемые параметры преобразуются в тип QVariant.
  4. Неизвестные типы приводят к ошибкам компиляции.
  5. Синхронные вызовы и асинхронные ожидающие вызовы поддерживают параметры любого типа.

Обновление версии 2.0.2

  1. Для организации проекта используется cmake, добавлена компиляция динамической библиотеки, см. CMakeLists.txt;
#true компилирует динамическую библиотеку; false компилирует статическую библиотеку;
set(quickevent_BUILD_SHARED_LIBS false)
#ON компилирует примеры OFF не компилирует примеры
set(quickevent_BUILD_EXAMPLES ON)
  1. Решена проблема сбоя отражения после наследования от класса, экспортируемого из DLL. Ниже приводится выдержка из исходного кода QT:qmetatype.h;
 static int qt_metatype_id()
    {
        static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
        if (const int id = metatype_id.loadAcquire())
            return id;
        //После наследования от экспортируемого класса объектов T шаблонного типа невозможно определить, требуется предварительное объявление Q_DECLARE_METATYPE
        const char * const cName = T::staticMetaObject.className();
        ...
    }

Обновление версии 3.0.0

  1. Переработана структура файлов для облегчения интеграции в существующие проекты;
  2. Добавлены несколько макросов, которые делают код более чистым при вызове QuickEvnet;
  3. Отменён конструктор и деструктор QuickApplication, устранена инвазивность по отношению к существующей структуре QT;
  4. Добавлен файл QuickEventConfig.h.in для управления версиями;
  5. Добавлена функция QuickScript;
  6. Оптимизирована инициализация QuickController;
  7. Внутренние переменные QuickWork добавлены с помощью методов setter/getter;
  8. Переработан пример вызова логики cmkae, чтобы упростить добавление примеров в будущем.

Обновление версии 3.0.1

  1. Добавлено несколько примеров;
  2. Исправлена ошибка разрушения при отражении нового потока;
  3. Улучшен вывод подробных сообщений;
  4. Добавлена функция QuickController для сортировки регистрации.

Версия 3.X.X План

  1. Добавить больше примеров, демонстрирующих все способы использования интерфейса QuickEvnet;
  2. Исправить ошибки, появившиеся после обновления до версии 3.0.0.

Примеры

Пример 1: Полная функциональность

Пример 2: Автоматическая инициализация QuickApplication и QuickWork, демонстрация сортировки и отражения

----------------- Инициализация QuickController:----------------- 
Имя библиотеки: «QuickEvent» 
Версия библиотеки: «3.0.1» 
Контроллер QuickWorks: («High0», «High1», «High2», «Disorder2», «Disorder1», «Disorder0», «Low0», «Low1», «Low2») 
----------------------------------

«High0  Инициализация завершена»
«High1  Инициализация завершена»
«High2  Инициализация завершена»
«Disorder2  Инициализация завершена»
«Disorder1  Инициализация завершена»
«Disorder0  Инициализация завершена»
«Low0  Инициализация завершена»
«Low1  Инициализация завершена»
«Low2  Инициализация завершена»
«High0  Завершение деконструкции»
«High1  Завершение деконструкции»
«High2  Завершение деконструкции»
«Disorder2  Завершение деконструкции»
«Disorder1  Завершение деконструкции»
«Disorder0  Завершение деконструкции»
«Low0  Завершение деконструкции»
«Low1  Завершение деконструкции»
«Low2  Завершение деконструкции»
  • Примечание: 1. Disorder отражает порядок, который необходимо учитывать при наличии последовательности. Перевод текста запроса на русский язык:

QThread(0x1b9428d5fa0, name = "Main Thread") Disorder2 Initialization QThread(0x1b9428d5fa0, name = "Main Thread") Disorder0 Initialization QThread(0x1b9428d5fa0, name = "Main Thread") Disorder1 Initialization QThread(0x1b9428d5fa0, name = "Main Thread")

Disorder0 Run QThread(0x1b9428d5fa0, name = "Main Thread") Disorder2 Run QThread(0x1b9428f94c0) Disorder3 Run msleep Begin QThread(0x1b9428f9400, name = "Work Thread") Disorder3 Run msleep End QThread(0x1b9428f9400, name = "Work Thread")

Disorder1 Run msleep Begin QThread(0x1b9428f9400, name = "Work Thread") Disorder1 Run msleep End QThread(0x1b9428f9400, name = "Work Thread") -------------quit------------- "Disorder2 End of deconstruction" "Disorder3 End of deconstruction" "Disorder1 End of deconstruction" "Disorder0 End of deconstruction"

* Примечание: 1. WorkThread — поток, который похож на MainThread, блокирует выполнение всех операций в WorkThread.

### Example4: публикация и подписка между потоками
Операция запуска потока в WorkThread будет блокировать все операции подписки в потоке WorkThread.
```cpp
----------------- QuickController Initialization:----------------- 
Lib Name: "QuickEvent" 
Lib VER: "3.0.1" 
Controlle QuickWorks: ("MainThreadSubscibe", "MainThreadPublish", "NewThreadPublish", "WorkThreadPublish", "NewThreadSubscibe", "WorkThreadSubscibe") 
----------------------------------

-------------Main Thread Publish-------------

----------------- publishEvent:----------------- 
Event name:  "Example4" 
Event ConnectionType: Qt::AutoConnection 
Event Args: Qt::AutoConnection 
Event Thread: QThread(0x20815dc6640, name = "Main Thread") 
----------------------------------

MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)

-------------Work Thread Publish-------------

----------------- publishEvent:----------------- 
Event name:  "Example4" 
Event ConnectionType: Qt::AutoConnection 
Event Args: Qt::AutoConnection 
Event Thread: QThread(0x20815de8820, name = "Work Thread") 
----------------------------------

WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")
MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)
WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")

-------------New Thread Publish-------------

----------------- publishEvent:----------------- 
Event name:  "Example4" 
Event ConnectionType: Qt::AutoConnection 
Event Args: Qt::AutoConnection 
Event Thread: QThread(0x20815de86c0) 
----------------------------------

MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)
WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")
-------------Quit-------------
  • Примечание: 1. Операция запуска потока WorkThread блокирует все операции подписки в этом потоке.

Example4: демонстрация различных типов публикации (синхронная, асинхронная, асинхронное ожидание, автоматическая)

----------------- QuickController Initialization:----------------- 
Lib Name: "QuickEvent" 
Lib VER: "3.0.1" 
Controlle QuickWorks: ("NewThreadSubscibe1", "NewThreadSubscibe2") 
----------------------------------


----------------- subscibeEvent:----------------- 
listener: NewThreadSubscibe1(0x23c34998610) 
Event name: "Example5" 
subscibe level Disorder 
Event Thread "Main Thread" 
----------------------------------


----------------- subscibeEvent:----------------- 
listener: NewThreadSubscibe2(0x23c34998950) 
Event name: "Example5" 
subscibe level Disorder 
Event Thread "Main Thread" 
----------------------------------


-------------Direct PUBLISH-------------

----------------- publishEvent:----------------- 
Event name:  "Example5" 
Event ConnectionType: Qt::DirectConnection 
Event Args: Qt::DirectConnection 
Event Thread: QThread(0x23c34976690, name = "Main Thread") 
----------------------------------

New1 Subscibe bugin QThread(0x23c34998570)
New2 Subscibe bugin QThread(0x23c349988d0)
New2 Subscibe end QThread(0x23c349988d0)
New1 Subscibe end QThread(0x23c34998570)

-------------Queued PUBLISH-------------

----------------- publishEvent:----------------- 
Event name:  "Example5" 
Event ConnectionType: Qt::QueuedConnection 
Event Args: Qt::QueuedConnection 
Event Thread: QThread(0x23c34976690, name = "Main Thread") **New1 Subscibe bugin QThread(0x23c34998570)**
**New2 Subscibe bugin QThread(0x23c349988d0)**
**New2 Subscibe end QThread(0x23c349988d0)**
**New1 Subscibe end QThread(0x23c34998570)**  

-------------Blocking Queued PUBLISH-------------

----------------- publishEvent:-----------------  
Event name: «Example5»  
Event ConnectionType: Qt::BlockingQueuedConnection  
Event Args: Qt::BlockingQueuedConnection  
Event Thread: QThread(0x23c34976690, name = «Main Thread»)  
----------------------------------

**New1 Subscibe bugin QThread(0x23c34998570)**
**New1 Subscibe end QThread(0x23c34998570)**
**New2 Subscibe bugin QThread(0x23c349988d0)**
**New2 Subscibe end QThread(0x23c349988d0)**  

-------------Auto PUBLISH1-------------  

----------------- publishEvent:-----------------  
Event name: «Example5»  
Event ConnectionType: Qt::AutoConnection  
Event Args: Qt::AutoConnection  
Event Thread: QThread(0x23c34976690, name = «Main Thread»)  
----------------------------------  

**New1 Subscibe bugin QThread(0x23c34998570)**
**New2 Subscibe bugin QThread(0x23c349988d0)**
**New2 Subscibe end QThread(0x23c349988d0)**
**New1 Subscibe end QThread(0x23c34998570)**  

-------------Quit-------------  
«NewThreadSubscibe1 End of deconstruction»  
«NewThreadSubscribe2 End of deconstruction»

*: 1. 小心死锁,尤其跨线程阻塞同步、带QDialog等有返回值的窗口请勿使用阻塞发布*  

### 。。。。持续增加中  

# 6 QuickEvnet代码模型使用心得  
&emsp;  
&emsp;  
&emsp;  
&emsp;

# 7 关于作者  

&emsp;**Bruce**  
Gitee  
https://gitee.com/fmldd  
个人博客  
https://me.csdn.net/dadabruce  

&emsp;**Beyond**  
Gitee  
https://gitee.com/yaoxin001  
个人博客  
http://118.25.63.144

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

На основе модели кода с полным разделением контроля и интерфейса, разработанной с использованием QT, применяется концепция проектирования MVC. Она включает в себя рефлексию классов управления и управление жизненным циклом. Это способствует практике высокой степени сцепления внутри и низкой степени сцепления между модулями. Развернуть Свернуть
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/fmldd-Quick-Event.git
git@api.gitlife.ru:oschina-mirror/fmldd-Quick-Event.git
oschina-mirror
fmldd-Quick-Event
fmldd-Quick-Event
master