Название: Не создаётся виджет в потоке.
Отправлено: virtual_root от Июль 11, 2012, 10:45
Доброе утро ребята. Я написала класс и мне нужно его использовать в потоке. Я создаю указатель на класс в фун-и run() потока и соединяю его сигнал со слотом в классе потока. Но вот проблема, когда запускаю приложение оно падает со следующим сообщением об ошибке: ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", file kernel/qwidget.cpp, line 1299 Я так понимаю он мне говорит что widget я должна создать в потоке, но я же его там создала! Вот код класса(класс у меня синглетон) который мне нужно использовать в потоке: #ifndef WINAPIUSER_H #define WINAPIUSER_H
#include <QWidget> #include <Windows.h> #include <Wtsapi32.h> #include <winbase.h> #include <QLibrary> #include <QDebug>
class winAPIUser : public QWidget { Q_OBJECT public: static winAPIUser* instance();
/// метод блокирующий учетную запись пользователя /// @return возвращает true если действие произошло успешно и в противном случае возвращает false bool screenLock();
/// метод проверяющий заблокирована ли учетная запись пользователя /// @return возвращает true если учетная запись заблокирована и в противном случае возвращает false bool IsScreenLock();
protected:
/// виртуальный метод переопределяющий поведения окна QWidget в ответ на сообщения от ОС bool winEvent(MSG *message, long *result);
/// метод - регистрирует в системе окно приложения, которое будет получать уведомления о действиях пользователя, касающиеся его учетной записи void sendMessageOfActionUser();
private:
explicit winAPIUser(QWidget *parent = 0);
QLibrary m_user32Library; QLibrary m_wtsapi32Library;
/// статический указатель на класс static winAPIUser* s_winApi;
/** прототип для winAPI фун-и WTSRegisterSessionNotification*/ typedef bool (*PrototypeWTSRegisterSessionNotification)(HWND,DWORD); PrototypeWTSRegisterSessionNotification WTSRegisterSessionNotification;
/** прототип для winAPI фун-и WTSUnRegisterSessionNotification*/ typedef bool (*PrototypeWTSUnRegisterSessionNotification)(HWND); PrototypeWTSUnRegisterSessionNotification WTSUnRegisterSessionNotification;
/** прототип для winAPI фун-и LockWorkStation*/ typedef BOOL (*PrototypeLockWorkStation)(); PrototypeLockWorkStation LockWorkStation; signals:
/// сигнал информирующий о блокировке/разблокировки учетной записи bool userScreenLock(bool);
public slots: };
#endif // WINAPIUSER_H
#define _WIN32_WINNT 0x0501 #include "winapiuser.h"
winAPIUser::winAPIUser(QWidget *parent) : QWidget(parent) { /*загружаем dll */ m_wtsapi32Library.setFileName("wtsapi32"); if (!m_wtsapi32Library.load()) qDebug()<<QString::fromLocal8Bit("ошибка загрузки библиотеки wtsapi32, пишем в лог-файл"); else { // импортируем фун-ю из библиотеки WTSRegisterSessionNotification = (PrototypeWTSRegisterSessionNotification) m_wtsapi32Library.resolve("WTSRegisterSessionNotification"); if (!WTSRegisterSessionNotification) qDebug()<<QString::fromLocal8Bit("ошибка импорта фун-и из библиотеки wtsapi32, пишем в лог-файл");
// импортируем ещё одну фун-ю из библиотеки WTSUnRegisterSessionNotification = (PrototypeWTSUnRegisterSessionNotification) m_wtsapi32Library.resolve("WTSUnRegisterSessionNotification"); if (!WTSUnRegisterSessionNotification) qDebug()<<QString::fromLocal8Bit("ошибка импорта фун-и из библиотеки wtsapi32, пишем в лог-файл"); }
/*загружаем dll */ m_user32Library.setFileName("user32"); if (!m_user32Library.load()) qDebug()<<QString::fromLocal8Bit("ошибка загрузки библиотеки user32, пишем в лог-файл"); else { LockWorkStation = (PrototypeLockWorkStation) m_user32Library.resolve("LockWorkStation"); if (!LockWorkStation) qDebug()<<QString::fromLocal8Bit("ошибка импорта фун-и из библиотеки wtsapi32, пишем в лог-файл"); }
this->sendMessageOfActionUser(); }
winAPIUser *winAPIUser::s_winApi = 0;
winAPIUser* winAPIUser::instance(){ if (!s_winApi) s_winApi = new winAPIUser(); return s_winApi; }
bool winAPIUser::IsScreenLock(){ return true; }
bool winAPIUser::winEvent(MSG *message, long *result){
if (message->message == WM_WTSSESSION_CHANGE) { qDebug() << "WM_WTSSESSION_CHANGE received."; switch (message->wParam) { case WTS_SESSION_LOCK : // qDebug() << "Seesion locked."; emit userScreenLock(true); break; case WTS_SESSION_UNLOCK : //qDebug() << "Seesion unlocked."; emit userScreenLock(false); break; default : ; } } return QWidget::winEvent(message, result); }
void winAPIUser::sendMessageOfActionUser(){
WTSRegisterSessionNotification(winAPIUser::winId(),0);
}
Вот функ-я run() потока: void MouseTrackThread::run(){
winAPIUser *blockWindow = winAPIUser::instance();
connect(blockWindow,SIGNAL(userScreenLock(bool)),this,SLOT(screenLock(bool)));
keyboard->setConnected(true); mouse->setHook();
// создаём таймер для сбора инф-я каждую минуту QTimer *timer = new QTimer; connect(timer,SIGNAL(timeout()),this,SLOT(returnStatistics())); timer->setInterval(60000); timer->start(); } Если закоментирую создание класса внутри потока всё работает. Причём если создаю этот класс в главном потоке, то всё работает! Как мне решить мою проблему? Мне всё-таки нужно работать с этим классом в фоновом потоке.
Название: Re: Не создаётся виджет в потоке.
Отправлено: Странник от Июль 11, 2012, 10:48
сообщение "Widgets must be created in the GUI thread" должно было навести вас на мысль, что виджеты должны создаваться только в GUI-потоке (том самом, в котором ваш QApplication вертится). это одно из базовых ограничений Qt4, в Qt5 грозились его убрать. а пока в других потоках вы можете создавать только нативные окна.
Название: Re: Не создаётся виджет в потоке.
Отправлено: virtual_root от Июль 11, 2012, 10:50
А что это за нативные окна? У них есть событие winEvent() ?
Название: Re: Не создаётся виджет в потоке.
Отправлено: Странник от Июль 11, 2012, 11:20
А что это за нативные окна? У них есть событие winEvent() ?
в вашем случае для создания окна необходимо использовать WinAPI, и эвенты обрабатывать с его же помощью.
Название: Re: Не создаётся виджет в потоке.
Отправлено: virtual_root от Июль 11, 2012, 11:47
спасибо
|