Qregistermetatype как пользоваться qt
Перейти к содержимому

Qregistermetatype как пользоваться qt

  • автор:

В каком месте лучше всего писать qRegisterMetaType?

Допустим у меня есть класс в котором есть приватное перечисление или что-то в этом духе(короче определенный мною тип). И я хочу внутри класса использовать сигнально-слотовое взаимодействие. Соответственно, чтобы обменивать такими сообщениями, я долже зарегистрировать мои новые типы методом(/макросом) qRegisterMetaType(«MyType») . Вопрос куда их можно элегантно запихать? В конструктор как-то некрасиво выходит, а в глобальной области cpp файла этот метод не работает, пишет
main.cpp:9:1: error: specializing member ‘::qRegisterMetaType’ requires ‘template<>‘ syntax
Вот пример кода

1 2 3 4 5 6 7 8 9 10 11 12 13
#include class Dummy { public: enum Numbers {ONE, TWO}; }; qRegisterMetaTypeDummy::Numbers>("Dummy::Numbers"); int main(int argc, char *argv[]) { return 0; }

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

В каком событии лучше всего проверять изменения буфера обмена?
Только начинаю изучать Qt. Делаю блокнот на подобии стандартного в Windows. В меню есть пункт.

В каком формате лучше всего писать документацию к API?
Добрый день! Написали документацию по API, возник вопрос насколько документация понятна. Помогите.

На каком с++ лучше начать писать?
Здравствуйте. Я не особо разбираюсь в с++. Но написав одну из своих первых программ на C++/cli.

На каком языке лучше писать скрипты?
Работа скрипта, в основном, будет заключаться в том, чтобы на определенном сайте нажать кнопку.

Эксперт С++

1936 / 1048 / 109
Регистрация: 29.03.2010
Сообщений: 3,167

я стараюсь писать в main-овской функции, а вот когда работаешь с библиотекой — тут хз, я так и не смог выяснить Qt гарантирует единичное вхождение зарегистрированных типов или каждый раз будет регистрировать новый.

Многопоточность в Qt Widgets

При работе приложения с оконным интерфейсом важно обеспечить отсутствие зависаний. Для этого сложные вычисления стоит запускать в отдельной нити. Концепция многопоточного приложения отлично сочетается с подходом сигналы-слоты Qt, при этом совершенно не нужно переопределять никакой метод run().

Основная идея. В многопоточном приложении вычисления проводятся в отдельной ните, по окончанию излучается сигнал, передающий результат в своих аргументах. Слот, принадлежащий уже MainWindow, будет вызван. Результаты вычислений окажутся в аргументах слота и не составит труда вывести их.

Проводя аналогию с микроконтроллерами, сигнал — это переход по вектору прерывания, а слот — сам обработчик прерывания. Чтобы возникло «прерывание», сигнал необходимо излучить: emit mysignalvoid(); тогда Qt начнёт искать ему «обработчик» (слот). В Qt можно на один сигнал повесить много слотов.

На следующем рисунке представлен алгоритм работы демонстрационного приложения. Нить обработки ежесекундно опрашивает по легенде USB HID устройство. Затем излучается (emit) сигнал, который обрабатывает слот, принадлежащий уже MainWindow и имеющий соответственно возможность рисовать на форме.

Итак, имеем классы, способные использовать подход сигналы-слоты. Для этого в их объявлении используется макрос Q_OBJECT.

class Worker : public QObject < Q_OBJECT //теперь можем использовать сигналы-слоты в классе public: QTimer *timerDeviceRead; //будем каждую секунду вызывать собственный слот GuiUpdateCallback Worker(); public slots: void updateElectropipData(); signals: void GuiUpdatePlease(uint8_t const *arrptr,size_t); >; class MainWindow : public QMainWindow //класс окна с GUI < Q_OBJECT public slots: void GuiUpdateCallback(uint8_t const *arrptr, size_t); private: Ui::MainWindow *ui; //доступ к кнопкам и иже с ними QThread *thread;

Чтобы передавать результат вычислений в аргументах необходимо зарегистрировать типы, используемые для аргументов. Сделать это можно в разных местах, но обычно — в конструкторе класса, который потом будет с этими типами работать:

Worker::Worker()< qRegisterMetaType("size_t"); qRegisterMetaType("uint8_t const *");

Обратите внимание, что в Qt уже существует множество своих типов, их не нужно регистрировать. Например, имеет смысл использовать quint8 вместо uint8_t.

Далее в конструкторе нити обработки создаётся таймер. Каждую секунду будет вызываться слот обработки updateUSBDataCallback. Обратите внимания на синтаксис подключения сигнал-слот в Qt5.

 this->timerDeviceRead = new QTimer(); connect(Worker::timerDeviceRead, &QTimer::timeout, this, &Worker::updateUSBDataCallback); this->timerDeviceRead->start();

Ниже приведено тело слота нити обработки. Здесь должен находится весь долгодумающий код.

void Worker::updateUSBDataCallback()< size_t mysize = 65; uint8_t buf[65] = < "I like USB HID" >; emit GuiUpdatePlease(buf,mysize); //излучение сигнала к слоту MainWindow //Подмена: for(int i =0;i <64;i++)< buf[i]=i+'0'; if (i+'0' >250) i=0; > >

Для демонстрации здесь сразу после излучения сигнала к слоту MainWindow, когда вероятно, что слот уже начал, но ещё не успел считать данные целиком, нагло подменяется содержимое массива. А так как массив передаётся по указателю, получается грязное чтение. Для предотвращения подобной ситуации сигнал из нити обработки должен быть связан со слотом GuiUpdateCallback() определённым образом:

MainWindow::MainWindow< connect(worker, &Worker::GuiUpdatePlease, this, &MainWindow::GuiUpdateCallback, Qt::BlockingQueuedConnection);

В таком случае, излучив сигнал, нить обработки блокируется до окончания работы слота GuiUpdateCallback().

Если в тексте программы вас смущает длинное «uint8_t const *», то можно завести синоним TU8PTR:

typedef uint8_t const * TU8PTR;

typedef и шаблоны

Шаблоны — один из самых пыльных уголков C++. Количество ситуаций, которые могут возникнуть при разных сочетаниях аргументов шаблона, аргументов функций, частичных специализациях и т.д. — чудовищно. Для прикладного разработчика это непочатый край возможностей, взять хотя бы тот же boost. Для разработчика компилятора — это непочатый край геморроя. Признанный лидер в искусстве разгребать эти Авгиевы конюшни это GCC, но и у него случаются заскоки.

Для программиста, пишущего на Qt, это всплывает при попытке использовать систему метаобъектов. Вот реальный пример:

namespace SCGenericSettings
// .
typedef qint64 setting_id_t;
// .
>
Q_DECLARE_METATYPE(SCGenericSettings::setting_id_t)

qint64 и setting_id_t — это разные типы или нет? Одна версия GCC считает, что одинаковые. Попробуешь скомпилировать приведённый выше код — получишь на строке с макросом ошибку переопределения ранее определённой специализации.

Прошёл годик, GCC обновился — и программа перестала компилироваться: Qt ругается на то, что тип setting_id_t не зарегистрирован. То есть теперь qint64 и setting_id_t стали разными типами. Ладно, добавили #ifdef:

#if (SC_GCC_VERSION < SC_GCC_VERSION_CHECK(4, 8, 4))
#define SC_GCC_CANT_DIFFERENTIATE_TYPEDEFED_IN_TEMPLATES
#endif
// .
#ifndef SC_GCC_CANT_DIFFERENTIATE_TYPEDEFED_IN_TEMPLATES
Q_DECLARE_METATYPE(SCGenericSettings::setting_id_t)
#endif

Прошёл ещё годик — и программа вдруг перестала работать: сигналы не доходят до слотов, ругаясь на то, что setting_id_t не зарегистрирован с помощью qRegisterMetaType(). Да как же он не зарегистрирован, если зарегистрирован?! Вот же:

const int metaType_setting_id_t = qRegisterMetaType();

Фишка в том, что теперь GCC не ругается при регистрации типа с помощью Q_DECLARE_METATYPE, но при этом умудряется раскрывать шаблон одинаково для обоих типов (qint64 и setting_id_t). То есть вместо того, чтобы зарегистрировать setting_id_t как метатип, вышеуказанный код просто присвоил переменной metaType_setting_id_t идентификатор метатипа для типа qint64. Метод QObject::connect() попытался найти метатип со строковым идентификатором «SCGenericSettings::setting_id_t» — и не нашёл. Проблема решилась добавлением «SCGenericSettings::setting_id_t» в качестве аргумента для qRegisterMetaType().

ПРАВИЛО: не использовать перегрузку функции qRegisterMetaType(), которая не имеет аргументов; вместо неё всегда нужно использовать ту версию, которая принимает текстовый идентификатор метатипа. (Обратите внимание, что он должен быть идентичен тому, что находится в скобках макроса Q_DECLARE_METATYPE).

По имеющимся исходникам имеет смысл пробежаться регулярным выражением

Qt и Q_REGISTER_METATYPE — что это такое, и как его использовать?

Для класса QAbstractSocket генерируется сигнал error с параметром QAbstractSocket::SocketError socketError. В документации написано: "QAbstractSocket::SocketError is not a registered metatype, so for queued connections, you will have to register it with Q_REGISTER_METATYPE", но про этот Q_REGISTER_METATYPE нет упоминания вообще нигде. Сталкивался-ли кто-нить с этим жЫвотным? (А я пока погуглю, мало-ли).

one_more_hokum ★★★
08.08.08 11:28:17 MSD

Re: Qt и Q_REGISTER_METATYPE — что это такое, и как его использовать?

у тебя объект сокета и слот, принимающий сигнал error(), находятся в одном потоке?

alex_custov ★★★★★
( 08.08.08 11:32:42 MSD )

Re: Qt и Q_REGISTER_METATYPE — что это такое, и как его использовать?

Угу, даже в одном классе.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *