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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Не создаётся виджет в потоке.  (Прочитано 4131 раз)
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();
}
Если закоментирую создание класса внутри потока всё работает. Причём если создаю этот класс в главном потоке, то всё работает! Как мне решить мою проблему? Мне всё-таки нужно работать с этим классом в фоновом потоке.
« Последнее редактирование: Июль 11, 2012, 10:49 от virtual_root » Записан
Странник
Гость
« Ответ #1 : Июль 11, 2012, 10:48 »

сообщение "Widgets must be created in the GUI thread" должно было навести вас на мысль, что виджеты должны создаваться только в GUI-потоке (том самом, в котором ваш QApplication вертится). это одно из базовых ограничений Qt4, в Qt5 грозились его убрать. а пока в других потоках вы можете создавать только нативные окна.
Записан
virtual_root
Гость
« Ответ #2 : Июль 11, 2012, 10:50 »

А что это за нативные окна? У них есть событие winEvent() ?
Записан
Странник
Гость
« Ответ #3 : Июль 11, 2012, 11:20 »

А что это за нативные окна? У них есть событие winEvent() ?
в вашем случае для создания окна необходимо использовать WinAPI, и эвенты обрабатывать с его же помощью.
Записан
virtual_root
Гость
« Ответ #4 : Июль 11, 2012, 11:47 »

спасибо
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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