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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Кнопка прерывания выполнения куска кода под Linux  (Прочитано 4772 раз)
slvno
Гость
« : Январь 15, 2009, 18:00 »

Привет!

Имеется прога портированная из Windows в которой в главном потоке создается
форма (FORM) с кнопкой.

При нажатии на кнопку (b_start) запускается длительная операция (on_b_start_clicked()).

В этом обработчике on_b_start_clicked показывается форма с отменой операции в виде QDialog с кнопкой QPushButton - b_cancel, которая создается в томже главном потоке при создании FORM.

При нажатии на кнопку b_cancel->b_stop устанавливается флаг отмены flag_stop и
завершается выполнеие on_b_start_clicked().

Если убрать QCoreApplication::processEvents(QEventLoop::AllEvents ), то b_cancel
пререстает реагировать. До этого под Windows b_cance создавалась в отдельном потоке
on_b_start_clicked_theread и все работало без вызовов
QCoreApplication::processEvents(QEventLoop::AllEvents ).

Можно ли обойтись без QCoreApplication::processEvents(QEventLoop::AllEvents ) ?

Код:
class FORM: public QWidget
{
  Q_OBJECT
public:
  QPushButton *b_start;
  CANCEL_BTN *b_cancel;
  volatile int *flag_stop;
   ~FORM();
  FORM(QWidget *parent);
public slots:
  void on_b_start_clicked();
};

...

void FORM::on_b_start_clicked()
{
  int sch = 0;

  *flag_stop = false;

  b_start->setEnabled(false);

  b_cancel->show();

  QCoreApplication::processEvents(QEventLoop::AllEvents );

  //pthread_create(&ar_theread_handle,0, on_b_start_clicked_theread, this);
  QCoreApplication::processEvents(QEventLoop::AllEvents );

  while (!(*flag_stop))
    {
      Sleep(1000); //Тут длительная операция
      sch++;
      QCoreApplication::processEvents(QEventLoop::AllEvents );
      if (sch >10)
        break;
    }

  *flag_stop = true;

  //while (!pthread_join(ar_theread_handle,0));
  ar_theread_handle = 0;

  b_start->setEnabled(true);
}

class CANCEL_BTN: public QDialog
{
  Q_OBJECT
public:
  volatile int *flag_stop;
  QPushButton *b_stop;
  ~CANCEL_BTN();
  CANCEL_BTN(volatile int *flag_);
public slots:
  void on_b_stop_clicked();
};



Записан
Winstrol
Гость
« Ответ #1 : Январь 15, 2009, 18:31 »

Можно ли обойтись без QCoreApplication::processEvents(QEventLoop::AllEvents ) ?
Да. В последних версиях появился интересный модуль QtConcurrent. В папке examples\qtconcurrent\imagescaling есть пример, где имеет место похожая ситуация. Длительное параллельное вычисление с выводом на экран промежуточных результатов и кнопка отмены. Без явных потоков, мьютексов, длинных пауз в гуевом потоке и прочей ереси.

Огорчает только, что реализация MapReduce там позорная до безобразия. Но к данной проблеме это не имеет прямого отношения.
« Последнее редактирование: Январь 15, 2009, 18:34 от Winstrol » Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #2 : Январь 15, 2009, 19:29 »

До этого под Windows b_cance создавалась в отдельном потоке
on_b_start_clicked_theread и все работало без вызовов
QCoreApplication::processEvents(QEventLoop::AllEvents ).

Это категорически неправильно! Все гуевые элементы должны быть в главном (гуевом) потоке.

Цитировать
В этом обработчике on_b_start_clicked показывается форма с отменой операции в виде QDialog с кнопкой QPushButton - b_cancel

Взгляните на QProgressDialog
« Последнее редактирование: Январь 15, 2009, 19:34 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
slvno
Гость
« Ответ #3 : Январь 16, 2009, 16:55 »

Взгляните на QProgressDialog

QProgressDialog виснет без вызова processEvents

Код:
void FORM::on_exit()
{
  *flag_stop = true;
}

void FORM::on_b_start_clicked()
{
  QProgressDialog progress("Executing...", "Abort", 0, 0, 0);
  progress.setSizeGripEnabled ( 0 );
  progress.setWindowModality(Qt::WindowModal);
   
  QObject::connect(&progress, SIGNAL( canceled() ), this, SLOT(on_exit()));
  progress.show();
   
  int sch = 0;

  *flag_stop = false;

  //Длительная операция которую нужно отменить
  while (!(*flag_stop))
    {
      Sleep(1000);
      sch++;
      //QCoreApplication::processEvents(QEventLoop::AllEvents );
      if (sch >10)
        break;
    }

  *flag_stop = true;
}

Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #4 : Январь 16, 2009, 17:44 »

Документацию читать нехотим:

Цитировать
void setValue ( int progress )
Warning: If the progress dialog is modal (see QProgressDialog::QProgressDialog()), this function calls QApplication::processEvents(), so take care that this does not cause undesirable re-entrancy in your code.

Ненужно использовать никаких влагов выхода, это все уже есть в QProgressDialog. Смотрите пример в ассистанте:

 
Код
C++ (Qt)
   QProgressDialog progress("Copying files...", "Abort Copy", 0, numFiles, this);
    progress.setWindowModality(Qt::WindowModal);
 
    for (int i = 0; i < numFiles; i++) {
        progress.setValue(i);
 
        if (progress.wasCanceled())
            break;
        //... copy one file
    }
    progress.setValue(numFiles);
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
slvno
Гость
« Ответ #5 : Январь 19, 2009, 13:23 »

А что делать для случая:

setValue(i); wasCanceled() 

Тут большой промежуток по времени что-то ожидается и GUI виснет

setValue(i); wasCanceled()
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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