Проблема рисования в QWidget вне потока GUI - PullRequest
3 голосов
/ 02 октября 2009

Я разрабатываю приложение, в котором хочу непрерывно получать изображения с удаленного хоста и отображать их на моем экране. для этого я следую данной стратегии 1) У меня есть основной объект QWidget, который содержит QImage (работает нормально) 2) Изображения, полученные с удаленного хоста, нарисованы на объекте QImage, эта работа выполняется в рабочем потоке с использованием QPainter. (работает отлично) 3) но проблема в том, что изображение не обновляется в QWidget, если я не изменяю размер виджета, потому что событие перерисовки вызывается для QWidget ... Теперь, если я перерисовываю QWidget из рабочего потока, он выдает ошибку "QPixmap: Это небезопасно использовать растровые изображения вне потока GUI ".. и приложение вылетает.

Любая помощь по этому поводу?

Ответы [ 3 ]

9 голосов
/ 02 октября 2009

испускает сигнал из рабочего потока с QueuedConnection
или опубликуйте событие обновления (QPaintEvent) в виджете из рабочего потока.

//--------------Send Queued signal---------------------
class WorkerThread : public QThread
{
    //...
signals:
    void updateImage();

protected:
    void run()
    {
        // construct QImage
        //...
        emit updateImage();
    }
    //...
};

//...
widgetThatPaintsImage->connect(
    workerThread, 
    SIGNAL(updateImage()), 
    SLOT(update()),
    Qt::QueuedConnection);
//...

//--------------postEvent Example-----------------------
class WorkerThread : public QThread
{
    //...
protected:
    void run()
    {
        //construct image
        if(widgetThatPaintsImage)
        {
            QCoreApplication::postEvent(
                widgetThatPaintsImage, 
                new QPaintEvent(widgetThatPaintsImage->rect()));
        }
        //... 
    }

private:
    QPointer<QWidget> widgetThatPaintsImage;
};

Не забудьте синхронизировать доступ к изображению.
В качестве альтернативы синхронизации вы также можете отправить изображение в поток графического интерфейса, как в примере Мандельброта .

1 голос
/ 15 июля 2011

Существует большая проблема с qt, если вы хотите разрабатывать плагины. Если хост-приложение не является приложением qt (много программ ...), и вы хотите добавить плагин 2 или 3 GUI, у вас большие проблемы (как и у меня).

Проблема в том, что в одном процессе должно быть только 1 приложение QApplication. (Обычно проходит в основном) Если вы пишете плагин, вы не можете позволить себе заблокировать хост-приложение с помощью QApplication.exec ().

В этом случае вы можете создать QThread с QApplication и выполнить exec в функции run (). Это будет работать правильно. Но этот не может решить исходную проблему. Ваш второй плагин не может иметь приложение QApplication ... потому что оно есть у хост-процесса. (указатель Qapplication в разделяемую память не подходит ... потому что QWidget должен создавать в потоке GUI ... всегда есть один ...)

А на ваш вопрос вот ответ. Если вы хотите создать только один плагин, вы можете использовать QMetaObject :: invokeMethod этот код устанавливает растровое изображение для метки и обновляет графический интерфейс.

QImage img;... bool succ = QMetaObject::invokeMethod(mainWin, "DisplaySlot", Qt::QueuedConnection, Q_ARG(QImage, img));

и добавьте публичный слот: в окно вашего дисплея

void mainWinClass::DisplaySlot(QImage qim) { (*(ui.label)).setPixmap(QPixmap::fromImage(qim)); (*(ui.label)).update(); }

Надеюсь, это поможет.

Если кто-нибудь знает решение моей проблемы ... описанной выше (плагин с несколькими GUI с qt в хост-приложении), пожалуйста, напишите мне.

1 голос
/ 02 октября 2009

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

...