Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Ilya_181 от Август 11, 2017, 10:50



Название: Как прекратить цикл for после закрытия приложения
Отправлено: Ilya_181 от Август 11, 2017, 10:50
Как прекратить выполнение цикла for, foreach после закрытия приложения.
Код
C++ (Qt)
void MainWindow::func(QDir dir)
{
   foreach (QFileInfo fileInfo, dir.entryInfoList())
   {
       QApplication::processEvents();
 
           QTextCursor cursor = ui->textEdit->textCursor();
           cursor.insertText(fileInfo.absoluteFilePath());
 
           if(fileInfo.isDir() && fileInfo.baseName() != "" && fileInfo.baseName() != "." && fileInfo.baseName() != "..")
           func(QDir(fileInfo.absoluteFilePath()));
 
    }
}
 
void MainWindow::on_pushButton_clicked()
{
   func(some_dir);
   QMessageBox::information(this, "Title","Конец!");
}

Если несколько раз вызвать слот (on_pushButton_clicked()), функция вызовется несколько раз, а там еще рекурсия. Если преждевременно закрыть приложение, мало того что будет продолжаться выполнение кода, так еще QMessageBox будет периодически мигать.
Что сделать, чтобы по желанию пользователя можно было прекратить любое выполнение участка кода?


Название: Re: цикл for после закрытия приложения
Отправлено: gil9red от Август 11, 2017, 11:23
Закрывайте приложение через
Код
C++ (Qt)
QApplication::quit()


Название: Re: цикл for после закрытия приложения
Отправлено: Ilya_181 от Август 11, 2017, 11:52
Закрывайте приложение через QApplication::quit()

Если я правильно понял, это не работает.
Код
C++ (Qt)
MainWindow::~MainWindow()
{
   QApplication::quit();
   delete ui;
}
 
--------------------------------------------------------------------------------
void MainWindow::closeEvent(QCloseEvent *event)
{
   Q_UNUSED(event);
   QApplication::quit();
   QMainWindow::closeEvent(event); // если закомментировать тут, все-равно  результат отрицательный
}


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: qate от Август 11, 2017, 12:42
завести переменную stop_now = false
по команде пользователя или в деструкторе MainWindow присвоить её true
в func проверять её, и сразу выход из func


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: lit-uriy от Август 11, 2017, 12:47
>" Если преждевременно закрыть приложение, мало того что будет продолжаться выполнение кода, так еще QMessageBox будет периодически мигать."
Если приложение закрыть, то ни какой код уже не будет выполнятся.

У тебя проблема где-то в другом месте.


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: Ilya_181 от Август 12, 2017, 11:40
У тебя проблема где-то в другом месте.
Проблема здесь QApplication::processEvents();. Но processEvents() нужен для того чтобы приложение реагировало на действия пользователя во время выполнения цикла. Если его закомментировать программа зависает пока не выполнится код. А такое поведение программы не нужно.

Более того, если вызвать слот дважды, нажать на кнопку два раза, код программы выполниться дважды. Видимо за время между первым нажатием кнопки и вторым успевает выполниться строка QApplication::processEvents(); в цикле. То есть я нажимаю первый раз кнопку, мы попадаем в цикл, и когда я нажму еще раз кнопку, QApplication::processEvents(); запомнит событие и выполнит нажатие кнопки после окончания цикла, что в свою очередь, повлечет выполнение кода еще раз.

И если закрыть окно, QApplication::processEvents(); продолжает выполнять код.


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: Igors от Август 12, 2017, 13:01
Собсно "закоытие приложения" здесь ни при чем, с тем же успехом в processEvents может вызваться другой код который не позволит func (весьма невнятное имя) выполняться корректно. Это общая, фундаментальная (не побоюсь этого слова) проблема которая не имеет какого-то четкого, однозначного решения. Рецепты что я знаю

- сделать func "модальным", самое простое вызвать ее из модального окна

- навесить фильтр на QApplication который будет взводить флажок (напр при событии закрытия), а в func проверять его напр
Код
C++ (Qt)
QApplication::processEvents();
if (funcAbortFlag) return;

Для полноты картины заметим что популярная рекомендация "выноси в поток" здесь по существу ничего не меняет - все равно обеспечивать флажок.


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: lit-uriy от Август 14, 2017, 08:49
Ilya_181, Не менял ли ты настройку quitOnLastWindowClosed у QApplication?

И ещё:
приведи код функции main()


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: Ilya_181 от Август 14, 2017, 18:49
Ilya_181, Не менял ли ты настройку quitOnLastWindowClosed у QApplication?

И ещё:
приведи код функции main()

Ничего нигде не менял.
Код
C++ (Qt)
       #include "mainwindow.h"
       #include <QApplication>
 
       int main(int argc, char *argv[])
       {
           QApplication a(argc, argv);
           MainWindow w;
           w.show();
 
           w.move(444,55);
           return a.exec();
       }
-----------------------------------------------------------------------------------------------------------
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
 
#include <QtWidgets>
#include <QWidget>
#include <QMessageBox>
#include <QTextEdit>
#include <QPushButton>
#include <QDir>
#include <QTextCursor>
#include <QVBoxLayout>
#include <QApplication>
 
class MainWindow : public QWidget
{
   Q_OBJECT
 
 
public:
   explicit MainWindow(QWidget *parent = 0) : QWidget(parent)
   {
       lay->addWidget(pushButton);
       lay->addWidget(textEdit);
       setLayout(lay);
       connect(pushButton, &QPushButton::clicked,this, &MainWindow::on_pushButton_clicked);
   }
   ~MainWindow(){}
 
QPushButton *pushButton = new QPushButton;
QTextEdit *textEdit = new QTextEdit;
QVBoxLayout *lay = new QVBoxLayout;
 
 
   void func(QDir dir)
   {
       foreach (QFileInfo fileInfo, dir.entryInfoList())
       {
           QApplication::processEvents();
 
               QTextCursor cursor = textEdit->textCursor();
               cursor.insertText(fileInfo.absoluteFilePath());
 
               if(fileInfo.isDir() && fileInfo.baseName() != "" && fileInfo.baseName() != "."
                                                               && fileInfo.baseName() != "..")
               func(QDir(fileInfo.absoluteFilePath()));
 
        }
   }
 
public slots:
   void on_pushButton_clicked()
   {
       func(QDir("D:/Programing/4.8/chapter41"));
       QMessageBox::information(this, "Title","Конец!");
   }
 
};
 
#endif // MAINWINDOW_H
 
 

добавил еще .h фаил. Запускаю и все выше описанное происходит. Можно скопировать код и запустить и проверить. Только каталог помять.


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: ssoft от Август 15, 2017, 07:48
Так как выбран подход явного управления обработкой событий, то вполне уместным будет и использование флага - признака завершения программы.
Он может быть как глобальным (паттерн синглтон в помощь), так и членом класса MainWindow, в зависимости от пространства имен в котором его нужно использовать.
Если пользователь желает прервать выполнение цикла то достаточно выставить флаг в значение true, а в цикле (и в любом другом месте) установить его проверку.
С точки зрения работоспособности программы - все будет работать, с точки зрения "правильной" архитектуры - все нужно делать по-другому  ;).


Название: Re: Как прекратить цикл for после закрытия приложения
Отправлено: Igors от Август 15, 2017, 09:57
Самое простое - заменить processEvents на модальный QProgressDialog (см примерчик в доке)
 
..и использование флага - признака завершения программы.
Мол, "и так можно" :) Ну хорошо, а как иначе-то?

..с точки зрения "правильной" архитектуры - все нужно делать по-другому  ;).
Расскажите, др способы (кроме озвученных выше) мне неизвестны