Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: polina89 от Декабрь 11, 2013, 14:43



Название: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 11, 2013, 14:43
Здравствуйте!
У меня имеется QProgressDialog, который описывает состояние процесса, идущего в отдельном потоке.При нажатии Cancel пользователю выдается сообщение, действительно ли он хочет остановить процесс. ProgressDialog является немодальным. Все работает как нужно, но после появления QMessageBox по каким-то причинам QProgressDialog вылезает вперед QMessageBox(загораживает его, другими словами).Как это убрать? Это код запуска отдельного потока

Код:
QProgressDialog *ProgressDialog=new QProgressDialog(QObject::trUtf8("Идет экспорт справочников"),QObject::trUtf8("Отмена"),0,100, this);
  ProgressDialog->setWindowFlags(ProgressDialog->windowFlags()&~Qt::WindowContextHelpButtonHint);
  QThread *thread=new QThread();
  workerExp=new LoadingWorkerExp();
  workerExp->moveToThread(thread);
  workerExp->setDefaults(ExportDialog.getFileName(),ExportDialog.getDateTime1(),ExportDialog.getDateTime2());
  connect(thread, SIGNAL(started()), workerExp, SLOT(ExportFunc()));
  /* … и при запуске потока будет вызван метод LoadingProcess(), который обновит БД и  будет работать в новом потоке*/
  connect(workerExp, SIGNAL(finished()), thread, SLOT(quit()));
  /* … и при завершении работы по обновлению БД, обертка  передаст потоку сигнал finished() , вызвав срабатывание слота quit()*/
  connect(workerExp, SIGNAL(finished()), workerExp, SLOT(deleteLater()));
  /* … и обертка пометит себя для удаления при окончании построения отчета*/
  connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
  /* … и поток пометит себя для удаления, по окончании обновления БД. Удаление будет произведено только после полной остановки потока. */
  connect(workerExp,SIGNAL(ValueChanged(int)),ProgressDialog, SLOT(setValue(int)));
  connect(workerExp,SIGNAL(MessageShow()),SLOT(MessageExportSlot()));
 
  connect(workerExp,SIGNAL(StopExporting()),workerExp,SLOT(StopExportProcess()));//вызываем сигнал отмены экспорта
  connect(ProgressDialog,SIGNAL(canceled()),this, SLOT(AskUserExporting()));//спрашиваем, действительно ли пользователь хочет отменить экспорт
  connect(workerExp, SIGNAL(finished()), ProgressDialog, SLOT(cancel()));
  ProgressDialog->show();
  thread->start();
Это схематичный вариант того, что происходит в слоте ExportFunc, т.е. в отдельном потоке

Код:
while ((query.next())&&(stopped))
  {
   value++;
   percentage=(value*100)/count;
   QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
   QEventLoop loop; QTimer::singleShot(3000, &loop, SLOT(quit())); loop.exec();
   if (stopped)
   {
    emit ValueChanged(percentage);
   }
  }
  QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
  while ((query2.next())&&(stopped))
  {
   value++;
   percentage=(value*100)/count;
   QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
   QEventLoop loop; QTimer::singleShot(3000, &loop, SLOT(quit())); loop.exec();
   if (stopped)
   {
    emit ValueChanged(percentage);
   }
  }
  QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
         while ((query3.next()&&stopped))
  {
                        value++;
   percentage=(value*100)/count;
   QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
   if (stopped)
   {
    emit ValueChanged(percentage);
   }
  }
  QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
  file.close();
 }
 if (stopped)
 {
  emit finished();
  emit MessageShow();
 }
 else
 {
 
  emit finished();
 }
Скорее всего дело в ProcessEvents, но точно не могу разобраться.Спасибо большое! ;)


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Hrundel от Декабрь 11, 2013, 15:37
Наверное QMessageBox нужно в каком-нибудь модусе запускать. Типа information(), warning(), или critical().
Тогда он будет на себе фокус удерживать. А так фокус сразу перехватывает QProgressDialog.


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Bepec от Декабрь 11, 2013, 16:10
Модальность задавайте. Проще говоря в конструкторе укажите ProgressDialog в качестве родителя. А вылезает по той причине, что вы его наверняка с потока обновляете, вот он и лезет.


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 11, 2013, 16:41
Не очень поняла про модальность.Ведь все окна класса QMessageBox уже по умолчанию модальны. Разве нет? :)


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Bepec от Декабрь 11, 2013, 19:48
Если им родителя не указать, они не модальны вроде.


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 12, 2013, 08:20
Родителем в моем случае является MainWindow. И QMessageBox является модальным сообщением, так как не дает мне работать, пока я его не закрою.Но это не спасло от того, что ProgressDialog вылезает вперед.Вот код для сообщения :)
Код:
        QMessageBox* msgBox = new QMessageBox( this );
msgBox->setStandardButtons(QMessageBox::Ok|QMessageBox::Cancel);
msgBox->setWindowTitle(QObject::trUtf8("Экспорт обновлений справочников" ));
msgBox->setText(QObject::trUtf8("Вы действительно хотите остановить экспорт?"));
msgBox->setIcon(QMessageBox::Warning);
int res=msgBox->exec();
if (res==QMessageBox::Ok)
{
               ...
        }


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Hrundel от Декабрь 12, 2013, 10:25
Попробуй так:

Код
C++ (Qt)
QMessageBox::StandardButton reply;
   reply = QMessageBox::question(this, trUtf8("Экспорт обновлений справочников" ), trUtf8("Вы действительно хотите остановить экспорт?"), QMessageBox::Yes|QMessageBox::No);
 
   if (reply == QMessageBox::Yes)
   {
        // ...  TODO
   }
 


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Igors от Декабрь 12, 2013, 11:04
А по-народному сделать ProgressDialog->hide() перед показом QMessageBox? Это и по прынцыпам UI правильно


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 12, 2013, 11:26
К сожалению, ни то, ни другое не помогло.Возможно, это из-за того, что из другого потока посылается сигнал о ходе процесса, который привязан к слоту setValue у ProgressDialog. Но разве при каждом setValue ProgressDialog заново отрисовывается?? и причем еще так, что каким-то образом перекрывает модальное окно ??? ??? ???


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Hrundel от Декабрь 12, 2013, 11:35
А может у тебя сам ProgressDialog модальный? Попробуй ему явно указать чтобы не был.

Код
C++ (Qt)
progress.setWindowModality(Qt::WindowModal);

Код
C++ (Qt)
// Operation constructor
Operation::Operation(QObject *parent)
    : QObject(parent), steps(0)
{
    pd = new QProgressDialog("Operation in progress.", "Cancel", 0, 100);
    connect(pd, SIGNAL(canceled()), this, SLOT(cancel()));
    t = new QTimer(this);
    connect(t, SIGNAL(timeout()), this, SLOT(perform()));
    t->start(0);
}
 
void Operation::perform()
{
    pd->setValue(steps);
    //... perform one percent of the operation
    steps++;
    if (steps > pd->maximum())
        t->stop();
}
 
void Operation::cancel()
{
    t->stop();
    //... cleanup
}


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 12, 2013, 12:17
Не помогло. :-\ Причем когда ProgressDialog вылезает вперед мне недоступна кнопка "Отмена", так как она блокируется модальным QMessageBox. Но почему тогда этот Dialog лезет вперед, я ума не приложу.


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Dima от Декабрь 12, 2013, 12:34
сделайте ProgressDialog  родителем для месседжа


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: Hrundel от Декабрь 12, 2013, 14:41
Да делала она уже.

Просто процесс всегда фокус перехватывает. Не понятно как-то. Наверное, тебе придется больше кода показать, а то теперь совсем трудно понять в чем проблемма.


Название: Re: QProgressDialog , processEvents и QThread
Отправлено: polina89 от Декабрь 12, 2013, 14:57
Спасибо всем большое за помощь!=)Получилось сделать с родителем)Изначально не вышло, потому что там был еще мой собственный косяк, точнее недочет)Так что теперь все гуд.Спасибо!!! :D :D :D :D :D