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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QThread && QApplication::postEvent()  (Прочитано 15700 раз)
ZeBriD
Гость
« : Март 13, 2009, 14:31 »

День добрый.
Столкнулся со следующей проблемой, и никак не могу сообразить, как её решить.
Суть проблемы такова: надо обработать большое кол-во файлов (я обрабатываю для теста чуть более 32тыс. таковых).
Дабы отменить этот процесс, а также быть в курсе прогресса, решил во время обработки файлов выводить прогрессбар с кнопкой отмены.
Первый вариант, который я попробовал - это добавить в функцию обработки файлов QApplication::postEvent();
И оно в принципе работало. Прогресс отображался, при нажатии на кнопку - останавливался.
Но! обработка пошла в десятки раз медленнее, что мне совсем не понравилось.
Тогда я решил использовать отдельный поток для отображение прогресса.
Создал поток, наследник QThread, в котором был один сигнал, на прекращение процесса, и один слот, для увелинчения прогресса на 1.
Но и тут всё пошло не чисто.
При обработке файлов стабильно сыпятся сообщения "QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread".
Да и ко всему прочему, нажать на отмену я так и не могу, пока не вставлю в код потока обработчик событий, который, опять же, замедляет в десятки раз процесс обработки файлов.

Собственно, не подскажете, как заставить этот поток работать отдельно от основного, дабы таки была возможность отменить процесс, без добавления QApplication::postEvent() ?
Записан
BRE
Гость
« Ответ #1 : Март 13, 2009, 14:36 »

Попробуй сделать наоборот, т.е. файлы обрабатывай в отдельном потоке, а прогресс-бар рисуй и кнопку обрабатывай в основной потоке.
Записан
ZeBriD
Гость
« Ответ #2 : Март 13, 2009, 17:55 »

Часть обработки файлов заключается в формировании QTreeWidget, который лежит на главной форме.
Поэтому, перенести обработку файлов в отдельный поток не получится, ибо QTreeWidget будет лежать не в нём, а значит и обрабатываться нормально не сможет...
Какие есть ещё варианты ?
Записан
BRE
Гость
« Ответ #3 : Март 13, 2009, 18:02 »

Часть обработки файлов заключается в формировании QTreeWidget, который лежит на главной форме.
Поэтому, перенести обработку файлов в отдельный поток не получится, ибо QTreeWidget будет лежать не в нём, а значит и обрабатываться нормально не сможет...
Какие есть ещё варианты ?
Вариант тот-же.
Посылай из потока обработки сигнал addFileName( const QString &filename ), а в главном потоке добавляй в дерево.
Имя сигнала и параметры можно менять.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Март 13, 2009, 18:33 »

Столкнулся тут на днях с такой же проблемой. Есть модель со списком файлов, нужно поизвлекать их иконки, что есть очень долго. Сделал так: формирую модель,запускаю поток, передав ему имена файлов, в потоке выбирается иконка и делается emit(int,QIcon), что ловится в моделе на слот и устанавливается в модель. Все под масдаем шло отлично, но под Линем сказало, что с пиксмапом не будет работать не в гуи треде. Что делать ХЗ...
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
spirit
Гость
« Ответ #5 : Март 13, 2009, 18:39 »

юзай QImage. QPixmap нельзя юзать вне главного потока.
из ассистанта, см.Thread Support in Qt
Цитировать
Painting in Threads
...Painting onto QPixmaps and QWidgets is not supported....
Записан
ZeBriD
Гость
« Ответ #6 : Март 13, 2009, 18:46 »

Вариант тот-же.
Посылай из потока обработки сигнал addFileName( const QString &filename ), а в главном потоке добавляй в дерево.
Имя сигнала и параметры можно менять.
Уже думал об этом... Но, после прикидки, понял, что либо получится через чур перенавороченые сигналы с кучей параметров, либо ничего не получится...
Чтобы было понятнее, у меня обработка файлов тесно связана с QTreeWidget:
Код:
  QTreeWidgetItem *locwi;
  bool same[] = {false, true, true, true, true, true, true, true};
  for (int i = 0; i < filModel->rowCount(*mi); i++)
  {
    if ((filModel->fileInfo(mi->child(i,0)).isDir()) && (filModel->rowCount(mi->child(i,0)) > 0))
    {
      locwi = new QTreeWidgetItem(wi);
      locwi->setText( 0, filModel->fileName(mi->child( i, 0 )));
      locwi->setIcon( 0, filModel->fileIcon(mi->child( i, 0 )));
      locwi->setText( 8, filModel->filePath(mi->child( i, 0 )));
      locwi->setText( 9, "Folder");
      LookUp(&mi->child(i, 0), locwi);
     
    }
   
    if (filModel->fileInfo( mi->child( i, 0 )).isFile())
    {
      TagLib::FileRef fl(filModel->filePath( mi->child( i, 0) ).toAscii().data());

      locwi = new QTreeWidgetItem(wi);
      locwi->setText( 0, filModel->fileName( mi->child( i, 0) ));
      locwi->setIcon( 0, filModel->fileIcon( mi->child( i, 0) ));
      locwi->setText( 8, filModel->filePath( mi->child( i, 0) ));
      locwi->setText( 9, "File");
      locwi->setText( 1, QString::fromStdWString(fl.tag()->artist().toWString()));
      locwi->setText( 2, QString::fromStdWString(fl.tag()->title().toWString()));
      locwi->setText( 3, QString::fromStdWString(fl.tag()->album().toWString()));
      locwi->setText( 4, QString::number(fl.tag()->year()));
      locwi->setText( 5, QString::number(fl.tag()->track()));
      locwi->setText( 6, QString::fromStdWString(fl.tag()->genre().toWString()));
      locwi->setText( 7, QString::fromStdWString(fl.tag()->comment().toWString()));
     
      emit incProgVal();
     
    }
   
    for (int j = 1; j <= 8; j++)
      if ( (same[j]) && (i > 0) )
        if (wi->child(i - 1) != NULL)
          if (locwi->text(j) != wi->child(i - 1)->text(j))
            same[j] = false;
   
    if (cancel)
    {
      return;
    }
    //QApplication::processEvents();
  }
 
  for (int j = 1; j <= 8 ; j++)
    if (same[j])
      if (wi->child(0) != NULL)
        wi->setText(j, wi->child(0)->text(j));

Возможно глупый вопрос... Но может есть какой-то "локальный" postEvent(), только для одного потока/формы ?
Записан
spirit
Гость
« Ответ #7 : Март 13, 2009, 18:47 »

используй катом ивенты, в них можно запишнуть то, что тебе нужно.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Март 13, 2009, 18:49 »

юзай QImage. QPixmap нельзя юзать вне главного потока.
из ассистанта, см.Thread Support in Qt
Цитировать
Painting in Threads
...Painting onto QPixmaps and QWidgets is not supported....
Да хотелось через QFileIconProvider, чтобы свои костыли не лепить, а там через пиксмап. Грустный
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
spirit
Гость
« Ответ #9 : Март 13, 2009, 18:51 »

так конвертануть потом QImage в пикспам, что нельзя?  Улыбающийся
Цитировать
QPixmap QPixmap::fromImage ( const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor )   [static]
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #10 : Март 13, 2009, 18:53 »

Да не в том дело. Загляни в исходники QFileIconProvider, там работа через QPixmap, а на выходе QIcon. Т.е. получается, что в потоке оперирую с QPixmap, что не позволено.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
BRE
Гость
« Ответ #11 : Март 13, 2009, 18:54 »

Чтобы было понятнее, у меня обработка файлов тесно связана с QTreeWidget:
[offtop]
Вот это очень плохая традиция переплетать функционал и GUI (уж прости  Подмигивающий ). Представь, что завтра тебе нужно будет сделать тоже, только с использованием не Qt (в консоли!). Будешь заново программу писать? Вместо того, чтобы "морду" новую сделать, а функционал старый оставить.
[/offtop]
А в сигналах можно любые объекты передовать. Сделай класс FileMegaInfo, создавай объект этого класса, заполни данными и передавай в главный поток, а он на основании этих данных будет дерево заполнять.
Записан
spirit
Гость
« Ответ #12 : Март 13, 2009, 18:56 »

Да не в том дело. Загляни в исходники QFileIconProvider, там работа через QPixmap, а на выходе QIcon. Т.е. получается, что в потоке оперирую с QPixmap, что не позволено.
[offtop]
типа QFileIconProvider юзается в потоке? че-то не пойму Улыбающийся
[/offtop]
Записан
ZeBriD
Гость
« Ответ #13 : Март 13, 2009, 18:58 »

используй катом ивенты, в них можно запишнуть то, что тебе нужно.
Простите, что ?  Строит глазки


Да, и может кто объяснит, почему таки изначальный вариант, с отображением прогресс-бара в отдельном потоке не работает?


[offtop]
Вот это очень плохая традиция переплетать функционал и GUI (уж прости  Подмигивающий ). Представь, что завтра тебе нужно будет сделать тоже, только с использованием не Qt (в консоли!). Будешь заново программу писать? Вместо того, чтобы "морду" новую сделать, а функционал старый оставить.
[/offtop]
Тоже верно. Не подумал об этом, ибо это мой первый проект... Спасибо за совет.

А в сигналах можно любые объекты передовать. Сделай класс FileMegaInfo, создавай объект этого класса, заполни данными и передавай в главный поток, а он на основании этих данных будет дерево заполнять.
Похоже, выбор у меня не велик... Попробую так реализовать...
Записан
spirit
Гость
« Ответ #14 : Март 13, 2009, 18:59 »

Да, и может кто объяснит, почему таки изначальный вариант, с отображением прогресс-бара в отдельном потоке не работает?
нельзя юзать гуевые классы в негуевом(рабочем) потоке.
опять-таки ассистант, см.Thread Support in Qt
Код:
QObject Reentrancy
...Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant.
They can only be used from the main thread. As noted earlier,
QCoreApplication::exec() must also be called from that thread...
« Последнее редактирование: Март 13, 2009, 19:02 от spirit » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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