Использование QThreads для выполнения QWidget::grab() во время QDialog::exec()

Я написал программу Qt, в которой генерируются серии графиков, когда пользователь загружает определенный файл данных и нажимает кнопку. Когда кнопка нажата, программа произведет серию расчетов, построит несколько графиков и отобразит их на экране при вызове функции QDialog::exec(). Чего я пытаюсь добиться, так это grab скриншотов сгенерированных графиков, используя QWidget::grab(). По сути, QWidget::grab() вызывается сразу после QDialog::exec(). Но поскольку QDialog::exec() продолжает работать до тех пор, пока пользователь не закроет конкретное окно, вызов QWidget::grab() после закрытия окна не дает желаемых результатов.

Это часть моего кода;

In mainwindow.cpp

    graphWindow.setWindowState(Qt::WindowMaximized);
    graphWindow.exec(); 
    graphWindow.savePlots();

In graphWindow.savePlots()

void GraphWindow::savePlots()
{ 

  QStringList plotNames;
  plotNames << "Income Statement (Plot A)" << "Income Statement (Plot B)" << "Balance Sheet (Plot A)"
            << "Balance Sheet (Plot B)" << "Cash Flow Plot" << "Holistic Stock Performance";

  for(int item = 0; item < ui->graphTab->count(); item++)
  {
      ui->graphTab->setCurrentIndex(item);
      QWidget * currentWidget = ui->graphTab->widget(item);

      int height = currentWidget->height();
      int width = currentWidget->width();
      int x = currentWidget->x();
      int y = currentWidget->y();

      QRect grabRect(x,y,width,height);

      //destImagePath is a global variable
      QString imageFilePath = destImagePath;
      imageFilePath.append(plotNames.at(item));
      imageFilePath.append(".png");

      currentWidget->grab(grabRect).save(imageFilePath);
  }

     //Reset to first tab after grab
     ui->graphTab->setCurrentIndex(0);
 }

Я думал обойти QDialog::exec(), запустив еще один QThread, который выполняет GraphWindow::savePlots(), пока окно все еще работает, чтобы снимки экрана давали желаемые результаты.

Есть ли лучший способ сделать это? Я думаю, что создание нового QThread только для вызова одной функции очень неэффективно. Даже если это не так, не могли бы вы объяснить, как это можно реализовать в параллельном QThreads.


person Vino    schedule 02.03.2017    source источник
comment
Неправильно вызывать методы виджета из рабочего потока: они могут работать или не работать до тех пор, пока графический интерфейс предназначен для работы в потоке пользовательского интерфейса. Вы должны просто вызвать savePlots() из диалогового окна. Просто сделайте это до закрытия диалога.   -  person Alexander V    schedule 02.03.2017
comment
это значит вызвать его в конструкторе? (Я знаю, что это не сработает, поскольку при первом создании объекта нечего захватывать) Как мне вызвать saveplots() из диалогового окна? Я знаю, что вы имеете в виду, но не уверен в том, как это реализовать. Было бы очень полезно, если бы вы могли уточнить, пожалуйста?   -  person Vino    schedule 02.03.2017
comment
Почему из конструктора? Когда картина должна быть готова? Ты должен знать. Мы не можем этого видеть.   -  person Alexander V    schedule 02.03.2017
comment
О, я думал, что изображение уже должно отображаться в окне, чтобы grab() работало. Вот почему я позвонил exec() перед saveplots(). Я попробую то, что вы сказали. Спасибо.   -  person Vino    schedule 02.03.2017


Ответы (1)


В вашем случае использование QThread или использование QtConcurrent::run на самом деле не требуется, вместо этого вы можете поставить в очередь вызов слота в основном потоке, используя

QTimer::singleShot(0, &graphWindow, &GraphWindow::savePlots);
graphWindow.exec();

Преимущество в вашем случае в том, что он будет работать в основном потоке, поэтому вам не нужно беспокоиться о потоках, синхронизации и т. Д. Для захвата (хотя Qt упрощает это).

Единственным ограничением этого подхода является то, что он фактически «замораживает» ваше приложение на время захвата. Обычно это должно быть вполне приемлемо, учитывая, что это будет значительно меньше секунды.

person Adrien Leravat    schedule 02.03.2017
comment
Работает как шарм. Большое спасибо. Я внес небольшую корректировку в ваш код (добавлено в EDIT). - person Vino; 02.03.2017