Russian Qt Forum
Ноябрь 23, 2024, 04:10 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [решено]QCoreApplication::postEvent из QThread::run()  (Прочитано 8240 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« : Апрель 26, 2011, 11:01 »

Доброго времени суток.

У меня возникла идея реализовать (пока только под Win) свой класс (диспетчер) для отлова событий от последовательного порта и передачи их в цикл обработки приложения.
Т.е. сам класс - диспетчер WinSerialEventDispatcher наследуется от QThread и в своем методе run() обрабатывает дескрипторы портов и при возникновении каких-то событий,
формирует свой евент SerialEvent , наследуемый от QEvent и методом QCoreApplication::postEvent() шлет этот евент приемнику.
Приемником в данном случае выступает QApplication.

В приложении QApplication имею виджет в котором переопределяю метод QWidget::event() в котором перехватываю и, если надо,
обрабатываю нужное пришедшее событие.

Т.е. имеется две сущности:
1. Генератор событий: диспетчер, WinSerialEventDispatcher который формирует и рассылает евенты от последовательных портов
2. Приемник событий: само приложение QApplication, которое их обрабатывает.

Так вот, проблема в том, что мои евенты не доходят куда надо.
Естественно, код в WinSerialEventDispatcher::run() работает верно.

1. Вот класс моего события (от последовательного порта)
Код
C++ (Qt)
class SerialEvent : public QEvent
{
public:
   enum NotifyTypeFlag {
       None    = 0x00,
       Read    = 0x01,
       Write   = 0x02,
       Except  = 0x04,
       Break   = 0x08,
       Cts     = 0x10,
       Dsr     = 0x20,
       Ring    = 0x40
   };
   Q_DECLARE_FLAGS(NotifyType, NotifyTypeFlag)
 
   SerialEvent(NotifyType type, ::HANDLE descriptor)
       : QEvent((QEvent::Type)(QEvent::User + 1))
       , d(new PrivateData)
   {
       d->type = type;
       d->descriptor = descriptor;
       d->cts = false;
       d->dsr = false;
       d->ring = false;
   }
   virtual ~SerialEvent()
   {
       delete d;
   }
   NotifyType notifyType() const { return d->type; }
   ::HANDLE descriptor() const { return d->descriptor; }
private:
   class PrivateData
   {
   public:
       NotifyType type;
       ::HANDLE descriptor;
       bool cts;
       bool dsr;
       bool ring;
   };
 
   PrivateData *d;
};
 


2. Вот код метода run()
Код
C++ (Qt)
void WinSerialEventDispatcher::run()
{
   ...
 
   while (!stopped) {
 
       //бесконечно ожидаем сигнального состояния какого нить дескриптора порта
       WaitForSingleObjectEx()
       ...
 
       //проверяем что за евент и что да дескриптор и т.п. и формируем
       //набор битовых масок для последующей идентификации типа события и т.п.
       ...
 
       //тут создаем наш класс - событие SerialEvent с необходимыми параметрами и отправляем в приложение
       SerialEvent *e = new SerialEvent(...);
       QCoreApplication::postEvent(qApp, e);
       ...
   }
}
 

3. Далее, в приложении есть виджет в котором переопределен метод event()
Код
C++ (Qt)
bool TestWidget::event(QEvent *e)
{
   bool ret = true;
   if (e->type() == (QEvent::User + 1)) {
 
       SerialEvent *se = reinterpret_cast<SerialEvent *>(e);
       qDebug() << "TestWidget::event() hook: descriptor: " << se->descriptor()
                << " flags = " << se->notifyType();
   }
   else
       ret = QWidget::event(e);
 
   return ret;
}
 

Так вот, дебаг сообщение не выводится. Что я делаю не так?  В замешательстве
« Последнее редактирование: Апрель 26, 2011, 12:59 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Апрель 26, 2011, 11:37 »

И так не работает:
Код
C++ (Qt)
void TestWidget::customEvent(QEvent *e)
{
   if (e->type() == (QEvent::User + 1)) {
 
       SerialEvent *se = reinterpret_cast<SerialEvent *>(e);
       qDebug() << "TestWidget::event() hook: descriptor: " << se->descriptor()
                << " flags = " << se->notifyType();
   }
}
 

 В замешательстве
Записан

ArchLinux x86_64 / Win10 64 bit
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #2 : Апрель 26, 2011, 12:36 »

Ну дык, ты шлёшь событие в qApp:
Код
C++ (Qt)
QCoreApplication::postEvent(qApp, e);
а слушаешь его в своём виджете:
Код
C++ (Qt)
TestWidget::event(QEvent *e)
QCoreApplication просто так бродкастить такие события всем не будет.
« Последнее редактирование: Апрель 26, 2011, 12:38 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Akon
Гость
« Ответ #3 : Апрель 26, 2011, 12:38 »

А зачем клиентскому коду какие-то события. Удобнее всего работать с сигналами.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #4 : Апрель 26, 2011, 12:41 »

Цитата: Akon
А зачем клиентскому коду какие-то события. Удобнее всего работать с сигналами.
А какая разница? Суть-то одна.
Записан

Qt 5.11/4.8.7 (X11/Win)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #5 : Апрель 26, 2011, 12:53 »

Цитировать
QCoreApplication просто так бродкастить такие события всем не будет.
Так я пробовал переопределять метод eventFilter() и устанавливать его installEventFilter(qApp) но ничего не работает все-равно.

Я так понимаю, что вызвав myWidget->installEventFilter(qApp) я для моего виджета добавляю обработку событий от самого QApplication,
т.е. фильтрую и события от QApplication?! Но не работает.

Просто я задумывал так, что класс - диспетчер ничего не должен знать о том, кому именно он рассылает события!
(Т.е. знает только одного приемника - QApplication) .
А вот QApplication уже может иметь туеву хучу экземпляров классов типа  TestWidget, каждый из которых нуждается в своем типе пользовательского события от последовательного устройства.

Т.е. в идеале нужно сделать так, чтобы можно было в любом подобъекте (классе) приложения переопределив методы: event(), customEvent() и т.п. поимать события от диспетчера.

-----

Тьфу ты, проблема решена: нужно делать не:
Код
C++ (Qt)
myWidget->installEventFilter(qApp)
 
а
Код
C++ (Qt)
qApp->installEventFilter(myWidget)
 

Улыбающийся
« Последнее редактирование: Апрель 26, 2011, 12:58 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Апрель 26, 2011, 13:07 »

Цитировать
Я так понимаю, что вызвав myWidget->installEventFilter(qApp) я для моего виджета добавляю обработку событий от самого QApplication,
т.е. фильтрую и события от QApplication?! Но не работает.
Всё наоборот Подмигивающий
Код
C++ (Qt)
qApp->installEventFilter( myWidget )
Записан

Qt 5.11/4.8.7 (X11/Win)
asvil
Гость
« Ответ #7 : Апрель 26, 2011, 14:50 »

Соотвественно вопрос. Как броадкастить?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #8 : Апрель 26, 2011, 16:15 »

Соотвественно вопрос. Как броадкастить?
В смысле?

Для тех объектов которым нужны евенты делаем:
Код
C++ (Qt)
MyObject_N1::MyObject_N1()
{
   ....
   qApp->installEventFilter(this);
   ....
}
 
bool MyObject_N1::eventFilter(QObject *obj, QEvent *e)
{
   if ((obj == qApp) && (e->type() == (QEvent::User + 1))) {
 
 
       SerialEvent *se = reinterpret_cast<SerialEvent *>(e);
       // Вот тут проверяем, а кому этот евент принадлежит?
       // т.е. MyObject_N1 - это по сути отдельный класс типа SerialDevice
       // у которого имеется приватная переменная типа "дескриптор"
       // поэтому можно легко узнать кому принадлежит событие, сравнив дескрипторы (к примеру)
 
       if (se->descriptor() == m_descriptor) {
           qDebug() << "Наше событие для MyObject_N1 !!!";
           return true;
      }
   }
   return QWidget::eventFilter(obj, e);
}
 

Как то так...
« Последнее редактирование: Апрель 26, 2011, 16:17 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
asvil
Гость
« Ответ #9 : Апрель 26, 2011, 16:33 »

А как QEvent::LanguageChanged всем передается?

А вот как

Код:
qApp.installTranslator() {
  qApp.postEvent(qApp, LaguageChanged);
}
qApp.event() {
  foreach(widget, topLevelWidgets()) {
    qApp.postEvent(widget, LanguageChanged);
  }
}
QWidget.event() {
  foreach(widget, children()) {
    qApp.postEvent(widget, LanguageChanged);
  }
}

Функции вызывается в перечисленном порядке.

Как аналогично забродкастить событие?
« Последнее редактирование: Апрель 26, 2011, 16:47 от Филоненко Михаил » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #10 : Апрель 26, 2011, 17:23 »

С виджетами всё просто - берёшь QApplication::allWidgets() и каждому постишь событие.
А тебе-то надо каждому объекту. Непонятно только зачем каждому.
Записан

Qt 5.11/4.8.7 (X11/Win)
asvil
Гость
« Ответ #11 : Апрель 26, 2011, 17:28 »

Да, каждому-таки не нужно. Событие Database connection changed, его должны отловить только заинтересованные объекты. Не хотелось фильтр инсталлировать. Хотелось сразу только changeEvent переопределять.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #12 : Апрель 26, 2011, 17:32 »

Ну дык и используй сигналы для этого. Имхо, намного проще будет.
Записан

Qt 5.11/4.8.7 (X11/Win)
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.43 секунд. Запросов: 22.