Hello everyone, I will be very grateful to someone who will help deal with this problem. The other day I started learning threads (QThread). Due to the problem of freezing the interface with large calculations. The main stream of Qthread Gui hangs, and as I understand, you can work with Gui only in it, using signals and slots. My task is this: 1) It is necessary to put the runCalculation () function into a separate thread, but so that the interface is rendered normally, without hanging. The interface itself is in the calcprogressdialog, there is only a progressBar for counting the elements in the sheet, according to the formula from runCalculation (), here is the formula itself int regionCalcGranularity = 100 / listKA-> count (); and then all calculationControl-> ui-> progressBar-> setValue (calculationControl-> ui-> progressBar-> value () + regionCalcGranularity) is output to runCalculation (); Also in runCalculation, functions from ballistic.h are called, but as you understand, you don’t need to touch it, only runCalculation ()
Here is the mainwindow.h code
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPushButton> #include "calcprogressdialog.h" #include "ballistic.h" // Менеджеры соединения с БД #include "lbd_manager.h" // Глобальные настройки и параметры #include "global.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: // Загрузка перечня ИДПл void loadAllIDPl(); void runCalculation(); private: manager_lbd::ManagerLbd * dbManager; CalcProgressDialog * calculationControl; Ballistic * ballistic; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H Code mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "ui_calcprogressdialog.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); dbManager = new manager_lbd::ManagerLbd(this); calculationControl = new CalcProgressDialog(this); ballistic = new Ballistic(this); this->loadAllIDPl(); connect(this->planEditWidget->ui->pushButton_toCalculation, SIGNAL(pressed()), this, SLOT(runCalculation())); } MainWindow::~MainWindow() { delete ui; } // Запуск расчёта void MainWindow::runCalculation() { mAssert(calculationControl); mAssert(ballistic); mAssert(dbManager); int idplNum = 5; // возьмем число 5 как тестовое if (idplNum==0) return; calculationControl->show(); manager_lbd::list * tmp; // Сохранение нужных списков, чтобы те не перезатирались tmp = dbManager->selectAllIdplKa(idplNum); mAssert(tmp); manager_lbd::list * listKA = new manager_lbd::list; *listKA = *tmp; tmp = dbManager->selectAllIdplTz(idplNum); mAssert(tmp); manager_lbd::list * listTZ = new manager_lbd::list; *listTZ = *tmp; tmp = dbManager->selectAllIdplOkik(idplNum); mAssert(tmp); manager_lbd::list * listOKIK = new manager_lbd::list; *listOKIK = *tmp; manager_lbd::Idpl * IDPl = dbManager->selectOneIdpl(idplNum); mAssert(IDPl); // Получим ожидаемый номер, присваиваемый расчёту int calcNum = dbManager->nextvalCalculation(); // ---------------------------------------------------------------------------- // Собираем список РЦР sGeoZone * Geo = new sGeoZone[listTZ->count()]; // Текущий РЦР uint32_t currentGeo = 0; // Для каждой из записей в составе ИДПл QListIterator<manager_lbd::TableList> it(*listTZ); while(it.hasNext()) { const manager_lbd::TableList * t = &it.next(); // Получаем конкретный номер РЦР manager_lbd::IdplTz * IDPlTZ = dbManager->selectOneIdplTz(t->idNum); mAssert(IDPlTZ); manager_lbd::Zones * TZ = dbManager->selectOneZones(IDPlTZ->idTz); mAssert(TZ); // Запишем полученный номер Geo[currentGeo].num = TZ->idTz; // Получаем точки выбранного РЦР manager_lbd::list * TZPoints = dbManager->selectAllTzPoints(TZ->idTz); mAssert(TZPoints); Geo[currentGeo].count = TZPoints->count(); // Заполняем массив точками int currentPoint=0; QListIterator<manager_lbd::TableList> pit(*TZPoints); while(pit.hasNext()) { const manager_lbd::TableList * t = &pit.next(); manager_lbd::TzPoints * point = dbManager->selectOneTzPoints(t->idNum); mAssert(point); Geo[currentGeo].point[currentPoint].x = point->x; Geo[currentGeo].point[currentPoint].y = point->y; Geo[currentGeo].point[currentPoint].z = point->z; dOut << "TZ: " << TZ->idTz << ", point: " << currentPoint << ", --- " << Geo[currentGeo].point[currentPoint].x << ", " << Geo[currentGeo].point[currentPoint].y << ", " << Geo[currentGeo].point[currentPoint].z; currentPoint++; } currentGeo++; } // ---------------------------------------------------------------------------- // На сколько перемещается progressbar за одну операцию расчёта? int regionCalcGranularity = 100 / listKA->count(); // Получаем КА и по одному отдаём их в метод расчёта calculationControl->ui->label->setText("Расчёт интервалов прохождения РЦР..."); calculationControl->ui->progressBar->setValue(0); QCoreApplication::processEvents(); // Список, куда сохраняются результаты, чтобы быть потом скопом записанными // в ЛБД в рамках одной транзакции QList<manager_lbd::ResDTtZ> resDTtZList; QListIterator<manager_lbd::TableList> kit(*listKA); while(kit.hasNext()) { const manager_lbd::TableList * t = &kit.next(); manager_lbd::IdplKa * IDPlKA = dbManager->selectOneIdplKa(t->idNum); mAssert(IDPlKA); //manager_lbd::KAList * KA = dbManager->selectOneKAList(IDPlKA->idSputnik); //mAssert(listKATmp); manager_lbd::list * ICList = dbManager->selectAllEntryCond(IDPlKA->idSputnik); mAssert(ICList); // TODO: добавить получение ПОСЛЕДНИХ НУ для выбранного КА, // а не ПЕРВЫХ ПОПАВШИХСЯ, как сейчас manager_lbd::EntryCond * IC = dbManager->selectOneEntryCond(ICList->at(0).idNum); QDateTime tn = IDPl->idplStartTime; QDateTime tk = IDPl->idplEndTime; //QDateTime tn(QDate(2015, 7,1), QTime(0, 20, 24, 32)); //QDateTime tk(QDate(2015, 7,2), QTime(18, 51, 44, 32)); QList<CR> * result = NULL; QCoreApplication::processEvents(); result = ballistic->calculateRegions(IC, 125, tn, tk, Geo, currentGeo); QCoreApplication::processEvents(); calculationControl->ui->progressBar->setValue( calculationControl->ui->progressBar->value()+regionCalcGranularity); QCoreApplication::processEvents(); for(int i=0; i<result->count(); i++) { // TODO: Оптимизировать под пакетное сохранение manager_lbd::ResDTtZ resDTtZ; resDTtZ.idResDtTz= -1; //qrand(); resDTtZ.idCalculation = calcNum; // этот номер получит расчёт resDTtZ.idSputnik = result->at(i).Nka; resDTtZ.idTz = result->at(i).Ncr; resDTtZ.idPair=result->at(i).Nka; // хм, разве это здесь нужно? //resDTtZ.idUser = 1; // костыль! resDTtZ.numRev = result->at(i).Nv; resDTtZ.tgBegin = ballistic->convertMsecToDateTime (result->at(i).dtvx); resDTtZ.tgMid = ballistic->convertMsecToDateTime (result->at(i).dtmid); resDTtZ.tgEnd = ballistic->convertMsecToDateTime (result->at(i).dtvux); // Добавляем результат в промежуточный список resDTtZList.push_back(resDTtZ); //dbManager->insertResDTtZ(&resDTtZ, 1); } sDelete(result); } // ---------------------------------------------------------------------------- // Собираем список ОКИК sOKIK * OKIK = new sOKIK[listOKIK->count()]; // Текущий РЦР uint32_t currentOKIK = 0; // Для каждой из записей в составе ИДПл QListIterator<manager_lbd::TableList> it2(*listOKIK); while(it2.hasNext()) { const manager_lbd::TableList * t = &it2.next(); // Получаем конкретный номер ОКИК manager_lbd::IdplOkik * IDPlOkik = dbManager->selectOneIdplOkik(t->idNum); mAssert(IDPlOkik); // Получаем конкретный ОКИК manager_lbd::OKIK * cOKIK = dbManager->selectOneOkik(IDPlOkik->idOkik); mAssert(cOKIK); // Запишем полученные данные OKIK[currentOKIK].Nip = cOKIK->idOkik; OKIK[currentOKIK].rop.x = cOKIK->latitude; OKIK[currentOKIK].rop.y = cOKIK->longitude; OKIK[currentOKIK].rop.z = cOKIK->altitude; currentOKIK++; } // ---------------------------------------------------------------------------- int zrvCalcGranularity = 100 / listKA->count(); // Получаем КА и по одному отдаём их в метод расчёта calculationControl->ui->label->setText("Расчёт ЗРВ..."); calculationControl->ui->progressBar->setValue(0); QCoreApplication::processEvents(); QList<manager_lbd::ResRVokik> resRvOkikList; QListIterator<manager_lbd::TableList> kit2(*listKA); while(kit2.hasNext()) { const manager_lbd::TableList * t = &kit2.next(); manager_lbd::IdplKa * IDPlKA = dbManager->selectOneIdplKa(t->idNum); mAssert(IDPlKA); manager_lbd::list * ICList = dbManager->selectAllEntryCond(IDPlKA->idSputnik); mAssert(ICList); // TODO: добавить получение ПОСЛЕДНИХ НУ для выбранного КА, // а не ПЕРВЫХ ПОПАВШИХСЯ, как сейчас manager_lbd::EntryCond * IC = dbManager->selectOneEntryCond(ICList->at(0).idNum); QDateTime tn = IDPl->idplStartTime; QDateTime tk = IDPl->idplEndTime; //QDateTime tn(QDate(2015, 7,1), QTime(0, 20, 24, 32)); //QDateTime tk(QDate(2015, 7,1), QTime(21, 36, 04, 32)); QList<ZRV> * result = NULL; QCoreApplication::processEvents(); result = ballistic->calculateSights(IC, 125, tn, tk, OKIK, currentOKIK); QCoreApplication::processEvents(); calculationControl->ui->progressBar->setValue( calculationControl->ui->progressBar->value()+zrvCalcGranularity); QCoreApplication::processEvents(); for(int i=0; i<result->count(); i++) { // TODO: Оптимизировать под пакетное сохранение manager_lbd::ResRVokik resRvOkik; resRvOkik.idKey = -1; // qrand(); resRvOkik.idCalculation = calcNum; // этот номер получит расчёт resRvOkik.idSputnik = result->at(i).Nka; resRvOkik.idOkik = result->at(i).Nokik; resRvOkik.numRev = result->at(i).Nv; //resRvOkik.idUser = 1; // костыль! resRvOkik.rvz0begin = ballistic->convertMsecToDateTime (result->at(i).dtvx0); resRvOkik.rvz7begin = ballistic->convertMsecToDateTime (result->at(i).dtvx7); resRvOkik.rvz0end = ballistic->convertMsecToDateTime (result->at(i).dtvux0); resRvOkik.rvz7end = ballistic->convertMsecToDateTime (result->at(i).dtvux7); resRvOkikList.push_back(resRvOkik); //dbManager->insertResRVokik(&resRvOkik, 1); } sDelete(result); } // ---------------------------------------------------------------------------- // Записываем результаты в ЛБД // Преобразуем каждый из списков в массив: manager_lbd::ResDTtZ * resDTtZ = new manager_lbd::ResDTtZ[resDTtZList.count()]; manager_lbd::ResRVokik * resRvOkik = new manager_lbd::ResRVokik[resRvOkikList.count()]; dOut << "----------------------------------------------------------"; // Создадим в ЛБД расчёт: manager_lbd::Calculation newCalculation; newCalculation.idplNum = idplNum; newCalculation.dtCalc = QDateTime::currentDateTime(); // в последней // версии вроде бы перекрывается при записи в БД newCalculation.idCalculation = -1; // автогенерируемое, совпадёт с calcNum newCalculation.idUser = 1; // а вот это - костыль! // Запишем в ЛБД расчёт int calcId = dbManager->insertCalculation(&newCalculation, 1); // TODO: Проверить на наличие ошибки сохранения! // Собираем массивы for(int i=0; i<int(resDTtZList.count()); i++) { resDTtZ[i] = resDTtZList[i]; resDTtZ[i].idCalculation = calcId; } for(int i=0; i<int(resRvOkikList.count()); i++) { resRvOkik[i] = resRvOkikList[i]; resRvOkik[i].idCalculation = calcId; } // И запишем массивы одной большой транзакцией dbManager->insertResDTtZ(resDTtZ, resDTtZList.count()); dbManager->insertResRVokik(resRvOkik, resRvOkikList.count()); dOut << "----------------------------------------------------------"; calculationControl->close(); delete listKA; delete listTZ; delete listOKIK; // TODO: запамятовал синтаксис - проверить, правильно ли удаляются массивы? delete [] resDTtZ; delete [] resRvOkik; loadAllIDPl(); }