LINUX.ORG.RU

QProgressBar exception

 


0

1

Добрый день!

Пытаюсь сделать модальное окно с бесконечным QProgressBar. Но при вызове bar->setValue() получаю exceprion. Может кто подсказать, что я делаю не так?

Header

#pragma once
#ifndef NONCLOSEWINDOW_H
#define NONCLOSEWINDOW_H
class UpdateThread: public QThread
{
	Q_OBJECT
public: 
	UpdateThread(){
		terminated = false;
	}
	void run(){
		while(!terminated){			
			emit updateSignal();
			Sleep(10);
		}
	}
	void setTerminated(bool terminated){
		this->terminated = terminated;
	}
private:
	bool terminated;
signals:
	void updateSignal();
};

class NonCloseWindow : public QDialog
{
	Q_OBJECT

public:
	NonCloseWindow(QString text = "", bool closeAlowed = true);
	~NonCloseWindow();
	void setText(QString s){lbl->setText(s);}	
protected:
	virtual void reject();
	virtual void closeEvent(QCloseEvent* e);
	virtual void showEvent(QShowEvent* event);
private:
	QLabel* lbl;
	QProgressBar* bar;
	bool closeAlowed;	
	int value;
	UpdateThread* thread;
	QMutex* mutex;
private slots:
	void setValue();
};


#endif // NONCLOSEWINDOW_H

Source

#include "nonclosewindow.h"

NonCloseWindow::NonCloseWindow(QString text, bool pcloseAlowed)
: QDialog(),closeAlowed(pcloseAlowed)
{
	value = 0;
	mutex = new QMutex();
	QVBoxLayout* vb = new QVBoxLayout();
	lbl = new QLabel(text);
	vb->addWidget(lbl);

	bar = new QProgressBar(this);
	bar->setMinimum(0);
	bar->setMaximum(100);

	lbl->setAlignment (Qt::AlignCenter);
	vb->addWidget(bar);
	setWindowFlags(Qt::FramelessWindowHint);
	setWindowModality(Qt::ApplicationModal);
	setFixedSize(400,100);
	this->setLayout(vb);
}

void NonCloseWindow::setValue(){
  if(bar->value() >= bar->maximum() ) bar->reset();
    bar->setValue(bar->value()+1);
}

void NonCloseWindow::showEvent(QShowEvent* event){
	value = 0;
	connect(thread,SIGNAL(updateSignal()),this,SLOT(setValue()),Qt::DirectConnection);
	thread->setTerminated(false);
	thread->start();
}

NonCloseWindow::~NonCloseWindow()
{
	delete lbl;
}

void NonCloseWindow::reject()
{

}
void NonCloseWindow::closeEvent(QCloseEvent* e)
{
	disconnect(thread,SIGNAL(updateSignal()),this,SLOT(setValue()));
	thread->setTerminated(true);
	thread->quit();		
}

Методы QObject/QWidget не thread-safe. А ты вызываешь их из другого потока, т.к. сигнал коннектишь напрямую

connect(thread,SIGNAL(updateSignal()),this,SLOT(setValue()),Qt::DirectConnection);

а надо Qt::QueuedConnection (или AutoConnection или BlockingQueuedConnection)

В общем почитай enum Qt::ConnectionType


Кстати, если

при вызове .... получаю exceprion

то было бы правильным говорить какой exception потряс тебя.

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Проблема в том, что при связке с использованием Qt::QueuedConnection слот отработает после закрытия модального окна.

Sakura
() автор топика
Ответ на: комментарий от Sakura

Проблема в том, что при связке с использованием Qt::QueuedConnection слот отработает после закрытия модального окна.

потому что надо QThread::startTimer() и QThread::exec() делать в run()

поток тебе вообще обязателен?

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Не помогло.

Нет, не обязателен. Если в двух словах, то хочу вот что: окно с прогрес баром, которое можно юзать следующим образом - показали (висит окно с надписью и полоской), в это время выполняется другой код, закрыли.

Sakura
() автор топика
Ответ на: комментарий от dib2

qApp->processEvents() так же не дал никаких результатов, как и выполнение по таймеру. Я сюда потому и написал, что свои идеи закончились.

Sakura
() автор топика
Ответ на: комментарий от dib2

Пока добился следующего поведения: диалог показывается, лейбла на нем обновляется, когда нужно, но прогресс бар на месте.

Sakura
() автор топика
Ответ на: комментарий от dib2

Header

#pragma once
#ifndef NONCLOSEWINDOW_H
#define NONCLOSEWINDOW_H
class UpdateThread: public QThread
{
	Q_OBJECT
public: 
	UpdateThread(){
		terminated = false;
	}
	void run(){
		//this->startTimer(10);
		//this->exec();
		int i = 0;
		while(!terminated){			
			emit updateSignal();
			Sleep(10);
		}
	}
	void setTerminated(bool terminated){
		this->terminated = terminated;
	}
private:
	bool terminated;
signals:
	void updateSignal();
};

class NonCloseWindow : public QDialog
{
	Q_OBJECT

public:
	NonCloseWindow(QString text = "", bool closeAlowed = true);
	~NonCloseWindow();
	void setText(QString s){lbl->setText(s);}	
	void startProcess();
protected:
	virtual void reject();
	virtual void closeEvent(QCloseEvent* e);
	virtual void showEvent(QShowEvent* event);
private:
	QLabel* lbl;
	QProgressBar* bar;
	bool closeAlowed;	
	int value;
	UpdateThread* thread;
	QMutex* mutex;
private slots:
	void setValue();
};


#endif // NONCLOSEWINDOW_H

Source

#include "nonclosewindow.h"

NonCloseWindow::NonCloseWindow(QString text, bool pcloseAlowed)
: QDialog(),closeAlowed(pcloseAlowed)
{
	value = 0;
	mutex = new QMutex();
	QVBoxLayout* vb = new QVBoxLayout();
	lbl = new QLabel(text);
	vb->addWidget(lbl);

	bar = new QProgressBar(this);
	bar->setMinimum(0);
	bar->setMaximum(0);

	lbl->setAlignment (Qt::AlignCenter);
	vb->addWidget(bar);
	setWindowFlags(Qt::FramelessWindowHint);
	setWindowModality(Qt::ApplicationModal);
	setFixedSize(400,100);

	thread = new UpdateThread();

	this->setLayout(vb);
}

void NonCloseWindow::setValue(){
	if(bar->value() >= bar->maximum() )
		bar->reset();
	bar->setValue(bar->value()+1);
	bar->update();
}

void NonCloseWindow::startProcess(){

}

void NonCloseWindow::showEvent(QShowEvent* event){
	value = 0;
	connect(thread,SIGNAL(updateSignal()),this,SLOT(setValue()),Qt::QueuedConnection);
	thread->setTerminated(false);
	thread->start();
	QApplication::processEvents();
}

NonCloseWindow::~NonCloseWindow()
{
	delete lbl;
}

void NonCloseWindow::reject()
{

}
void NonCloseWindow::closeEvent(QCloseEvent* e)
{
	disconnect(thread,SIGNAL(updateSignal()),this,SLOT(setValue()));
	thread->setTerminated(true);
	thread->quit();	
	if(!closeAlowed)
		e->ignore();
	else
		exit(0);
	
}
Sakura
() автор топика
Ответ на: комментарий от Sakura

нет. UpdateThread вообще убирай, в
void NonCloseWindow::startProcess(){

}

пиши свою задачу, в которой периодически вызывай qApp->processEvents();

если все же хочешь с потоком - то внутри потока (run()) периодически отправляй QEvent на диалог, в диалоге лови его и обновляй данные. QEvent отправляй через QApplication::postEvent()

dib2 ★★★★★
()
Ответ на: комментарий от dib2
void NonCloseWindow::startProcess(){
	while(true){
		setValue();
		QApplication::processEvents();
	}
}

Если так, то не выполняется остальной код.

Sakura
() автор топика
Ответ на: комментарий от dib2
...

NonCloseWindow* ncw = new NonCloseWindow();
ncw->show();

for (int i = 0; i < 100; i++){
  qDedug(i);
}

ncw->close();

...

Это должно работать так: показали окно с прогресс-баром, вывели 1-100, закрыли окно. Или я многого хочу и так вообще не получится?

Sakura
() автор топика
Ответ на: комментарий от Sakura

В потоке надо выполнять рабочий код, а не управление представлением.

for (int i = 0; i < 100; i++){
  qDedug(i);
  qApp->processEvents();
}

либо
for (int i = 0; i < 100; i++){
  qDedug(i);
}

выноси в поток, и отправляй из него сообщения.

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

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Спасибо за пояснения. Для такого подхода придётся много переделывать, проект древний. Я надеялся что можно легче.

Sakura
() автор топика
Ответ на: комментарий от Sakura

с этим:

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

не придется. более того, можно запихнуть все это в диалог, и просто передавать ему функцию (лямбду), и пускай себе выполняет работу (лямбду) в другом потоке, даже блокируя основной поток через exec().

Будет что-то типа

NonCloseWindow ncw;
ncw.myjob([] () {
    for (int i = 0; i < 100; i++) {
         doYourStuffThere();
    }
});
ncw.exec();

dib2 ★★★★★
()
Последнее исправление: dib2 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.