Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Рисование из потока в Gui. Пример Mandelbrot. Как правильно рисовать из потока 
:(
    Опции темы
SirFreeFrag
Дата 14.3.2011, 00:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 9.3.2011

Репутация: нет
Всего: нет



День добрый.

Подскажите как правильно передать подготовленное изображение в Gui поток для отрисовки. Делаю, как в примере Mandelbrot. Там сделано таким образом:

Код

//Класс потока
class RenderThread : public QThread 
{
    Q_OBJECT
    ...
signals:
    void renderedImage(const QImage &image, double scaleFactor);

protected:
    void run();
    ...
};

void RenderThread::run()
{
    QImage image(resultSize, QImage::Format_RGB32);
    //Дальше что-то рисуется на QImage
    ...
    emit renderedImage(image, scaleFactor);
};


//И в потоке Gui  слот виджета  updatePixmap принимает
//сигнал renderedImage из дочернего потока и отрисовывает изображение

class MandelbrotWidget : public QWidget
{
    Q_OBJECT
    ...
private slots:
    void updatePixmap(const QImage &image, double scaleFactor);
    ...
};

void MandelbrotWidget::updatePixmap(const QImage &image, double scaleFactor)
{
    ...
    pixmap = QPixmap::fromImage(image);
    ...
    update();
 };



Вроде работает, но смущает следующая вещь. В Gui поток изображение передается с помощью сигнала renderedImage через объект image. Объект image объявлен и создается в методе класса потока run(), то бишь по сути являетстя локальным. Т.к сигнал из метода посылается другому (основному) потоку, то тип сигнала будет с постановкой в очередь. Мне казалось что слот updatePixmap (который обрабатывает сигнал renderedImage) может и выполнится поздней, чем закончится выполнение run(). Соответственно и объект image (т.к. это локальный объект метода run) будет уничтожен раньше, чем его обработает слот updatePixmap. Но как ни странно, вроде работает.

Собственно вопрос, почему этого не происходит, или где я ошибаюсь? И как правильно и потоко-безопасно передавать постоянно обновляющееся изображение в главный поток для отрисовки. Если можно, поделитесь примерами.

PS: Сори, забыл добавить в заголовок темы, что речь идет о Qt (4.7.1)

Это сообщение отредактировал(а) SirFreeFrag - 14.3.2011, 00:24
PM MAIL   Вверх
borisbn
Дата 14.3.2011, 00:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



SirFreeFrag, обрати внимание, как они связывают сигнал потока со своим слотом
Код

    connect(&thread, SIGNAL(renderedImage(QImage,double)), this, SLOT(updatePixmap(QImage,double)));

видишь, знака ссылки ( & ) уже нет. поэтоу, наверное, и работает. Если же убрать и в сигнале, и в слоте ссылку, а передавать объект QImage по значению, то вообще никаких проблем не будет, т.к. при emit'е сигнала создастся копия этого имаджа. Судя по всему из-за этого коннекта так и получается, но я бы не советовал так делать...

и ещё... обрати внимание, что run начинается с
Код

    forever {
...

а выход из него будет только при разрушении объекта thread в главном окне.

в общем, правильно делаешь, что обращаешь внимание на такие вещи.

Это сообщение отредактировал(а) borisbn - 14.3.2011, 00:37


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SirFreeFrag
Дата 14.3.2011, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 9.3.2011

Репутация: нет
Всего: нет



borisbn, если я правильно понял, ты имеешь виду, что image передается в данном случае не по ссылке, а по значению?
Если так, то не хотелось бы, что бы лишний раз производилось копирование image при передаче его в updatePixmap.

Т.к в Qt Examples это единственный пример в разделе Threading, был бы благодарен за линки на альтернативные реализации. Может есть какая-нитбудь общепринятая реализация решения данной задачи?

Добавлено через 12 минут и 10 секунд
Цитата(borisbn @ 14.3.2011,  00:32)
и ещё... обрати внимание, что run начинается с
Код

    forever {
...

а выход из него будет только при разрушении объекта thread в главном окне.

Ммм...вот этот момент я пропустил, просто в моей реализации не требовался бесконечный цикл в run().
PM MAIL   Вверх
borisbn
Дата 14.3.2011, 01:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Цитата(SirFreeFrag @  14.3.2011,  00:50 Найти цитируемый пост)
если я правильно понял, ты имеешь виду, что image передается в данном случае не по ссылке, а по значению?

не уверен. возможно, всё-таки, всё работает из-за того, что они уверены, что run не закончится раньше, чем полностью отработает слот. Если передавать не по ссылке, а по значению, то об этом и дкмать не нужно.

Цитата(SirFreeFrag @  14.3.2011,  00:50 Найти цитируемый пост)
то не хотелось бы, что бы лишний раз производилось копирование image при передаче его в updatePixmap


из документации по QImage
Цитата

QImage objects can be passed around by value since the QImage class uses implicit data sharing. QImage objects can also be streamed and compared.

почитай про Implicit Data Sharing

Есть ещё вариант... Не очень кошерный, но работает. Можно передавать объект по ссылке, но коннектить сигнал со слотом с явным указанием типа коннекта: Qt::BlockingQueuedConnection
В этом случае слот вызовется в своём (GUI-шном) потоке, но управление потоку, вызвавшему emit, будет возвращено только после того, как все слоты, связанные с сигналом, завершат свою работу.



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SirFreeFrag
Дата 14.3.2011, 01:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 9.3.2011

Репутация: нет
Всего: нет



Цитата

почитай про Implicit Data Sharing

Познавательно. Спасибо.
PM MAIL   Вверх
SirFreeFrag
Дата 14.3.2011, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 9.3.2011

Репутация: нет
Всего: нет



Блин, вроде гуглил до создания темы, а сейчас нашел точно такой же тред  smile 
http://www.linux.org.ru/forum/development/5192523

Насколько я понял из него, в данном случае при передаче image слоту все таки создается копия объекта, но за счет как раз выше упомянутого "Implict Data Sharing", накладные расходы при этом малы и копия будет уничтожена после того, как будет уничтожена последняя ссылка на нее (в данном примере, после того, как отработает слот updatePixmap). Если это так, то вопрос:

Код

signals:
void renderedImage(const QImage &image);

и
Код

signals:
void renderedImage(QImage image);

Эти варианты будут работать одинаково? В обоих случаях будет происходить "копирование" объекта?
PM MAIL   Вверх
borisbn
Дата 14.3.2011, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Цитата(SirFreeFrag @  14.3.2011,  15:44 Найти цитируемый пост)
Эти варианты будут работать одинаково? В обоих случаях будет происходить "копирование" объекта?

проверь smile
создай вместо QImage свой объект с выводом в конструкторе и деструкторе в qDebug() соответствующей информации. Только не забудь зарегистрировать его через qRegisterMetaType


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0488 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.