What is good way to update the Progressbar value?



  • Hi,
    Here I wrote some code for the updating the Progress bar value. I don't know about the what is right way to update the Progress bar. Here I mention some code.

    /*************** RecoveryLoader. h *******************/
    #pragma once
    #include <global_typedefs.h>
    #include <QThread>
    #include <qtimer.h>
    #include <qeventloop.h>

    #define EXIT_CORRECTLY 0
    #define EXIT_INCORRECTLY 1

    class RecoveryProcessLoader : public QObject
    {
    Q_OBJECT
    public:
    static RecoveryProcessLoader* Instance();
    public:
    void RecordReceiveByte(const uint NumberOfReceiveByte);
    void calculateTotalBytes(const HardwareModel_t HWversion, const uint32_t numPagesUsed);

    signals :
    void ProgressChanged(int);
    void Finished(bool);
    void Started();

    public slots:
    void dataReceiveingSwitch(bool);
    void dataReceivePing();

    void setProgressbarValue();
    

    private:
    RecoveryProcessLoader();
    ~RecoveryProcessLoader();
    uint getPageSize(const HardwareModel_t);
    volatile uint numberOfReceiveByte;
    volatile uint totalNumberOfbyte;
    QThread progressBarThread;
    static uint previousProgressBarValue;

    };

    /**************************RecoveryLoader.cpp ***********/
    #include "RecoveryLoader.h"

    RecoveryProcessLoader* RecoveryProcessLoader::Instance() {
    static RecoveryProcessLoader * ret = 0;
    if (0 == ret) {
    ret = new RecoveryProcessLoader;
    }
    return ret;
    }

    RecoveryProcessLoader::RecoveryProcessLoader(){
    QObject::connect(&progressBarThread, &QThread::started, this, &RecoveryProcessLoader::setProgressbarValue);
    }

    RecoveryProcessLoader::~RecoveryProcessLoader() {
    QObject::disconnect(&progressBarThread, &QThread::started, this, &RecoveryProcessLoader::setProgressbarValue);
    }

    uint RecoveryProcessLoader:: getPageSize(const HardwareModel_t HWversion) {
    return pageSizeOfFlash;
    }

    void RecoveryProcessLoader::calculateTotalBytes(const HardwareModel_t HWversion,const uint32_t numPagesUsed) {
    numberOfReceiveByte = 0;
    auto pageSize = getPageSize(HWversion);
    totalNumberOfbyte = pageSize * numPagesUsed;
    }

    void RecoveryProcessLoader::RecordReceiveByte(const uint numberOfByte) {
    numberOfReceiveByte += numberOfByte;
    }

    void RecoveryProcessLoader::dataReceiveingSwitch(bool dataRxSwitch) {
    if (dataRxSwitch) {
    emit Started();
    emit ProgressChanged(0);
    progressBarThread.start();
    this->moveToThread(&progressBarThread);
    }
    else {
    progressBarThread.exit(EXIT_CORRECTLY);
    emit Finished(true);
    }
    }

    // tricky way use for come out from the "Do while" loop. (Data start and Stop bit is use for exit do while loop)
    // Progress bar does not give the Exact value for number of Receiving Data bytes.
    // Error is not checking while recovering the Data.

    //void RecoveryProcessLoader::run() {
    // emit Started();
    // bool noError = true;
    //
    // emit ProgressChanged(0);
    // do {
    // emit ProgressChanged((numberOfReceiveByte *100) / totalNumberOfbyte);
    // } while (dataRx);
    //
    // emit Finished(noError);
    //}

    void RecoveryProcessLoader::setProgressbarValue() {
    QEventLoop loop;
    QTimer timer;
    timer.setInterval(1000);

    QEventLoop *loopPtr = &loop;
    

    #define EXIT_BY_TIMER 1
    #define EXIT_BY_PING 0

    QList<QMetaObject::Connection> connections;
    
    connections << connect(this, &RecoveryProcessLoader::dataReceivePing, [=]() {
    	emit ProgressChanged((numberOfReceiveByte * 100) / totalNumberOfbyte);
    	loopPtr->exit(EXIT_BY_PING);
    });
    
    connections << connect(&timer, &QTimer::timeout, [=]() {
    	loopPtr->exit(EXIT_BY_TIMER);
    });
    
    timer.start();
    int ret = loop.exec();
    timer.stop();
    
    foreach(auto conn, connections) {
    	disconnect(conn);
    }
    
    if (ret != EXIT_BY_PING) {
    	progressBarThread.exit(EXIT_INCORRECTLY);
    	emit Finished(false);
    	return;
    }
    

    }

    I am getting the Error for siganl dataRecivePing Signal. what is wrong with that signal. ??

    Here the Error
    0_1529618538455_c1d48e58-0487-47e0-863b-331a2157f041-image.png

    if any other good way is to updating the progress bar then please let me know.


  • Moderators

    @Yash001 You put void dataReceivePing() under slots.
    Also, I don't know exactly all your code, but I'm wondering why you need an event loop to update the progress bar. Usually you have a signal which provides a new progress value which you then set in the slot.



  • thank you @jsulm. I transfer into the signal area., and it is work. I need to Qevent loop because of the dataReceivePing() signal is generated whenever the data is received from hardware. if it is not received then i wanted to exit from the thread loop.



  • void RecoveryProcessLoader::dataReceiveingSwitch(bool dataRxSwitch) {

    if (dataRxSwitch) {
    	emit Started();
    	emit ProgressChanged(0);
    	this->moveToThread(&progressBarThread);
    	progressBarThread.start();
    	
    }
    else {
    	progressBarThread.exit(); // need to work here, immidiatly stop the Thread after creating. yash 
    	//progressBarThread.exit(EXIT_CORRECTLY);
    	emit Finished(true);
    }
    

    }

    void RecoveryProcessLoader::setProgressbarValue() {
    QEventLoop loop;
    QTimer timer;
    timer.setInterval(1000);

    QEventLoop *loopPtr = &loop;
    

    #define EXIT_BY_TIMER 1
    #define EXIT_BY_PING 0

    QList<QMetaObject::Connection> connections;
    
    connections << connect(this, &RecoveryProcessLoader::dataReceivePing, [=]() {
    	emit ProgressChanged((numberOfReceiveByte * 100) / totalNumberOfbyte);
    	loopPtr->exit(EXIT_BY_PING);
    });
    
    connections << connect(&timer, &QTimer::timeout, [=]() {
    	loopPtr->exit(EXIT_BY_TIMER);
    });
    
    timer.start();
    int ret = loop.exec();
    timer.stop();
    
    foreach(auto conn, connections) {
    	disconnect(conn);
    }
    
    if (ret != EXIT_BY_PING) {
    	progressBarThread.quit();
    	emit Finished(false);
    	return;
    }
    

    }
    Here One More Issue is created. if the dataReceiveingSwitch signal received 2 times. true and false. Then thread should immediately exit. but it won't.
    if first time : datarxswitch value is true; thread start to run .
    second time it is false; thread exit .

    whenever I received false at that time i wanted to immediately exit from the thread. first two time pointer git in to dataReceiveingSwitch. it is right but after that it is also hit into setProgressbarValue(). i don't want that things.

    how can i stop immediately stop thread execution. after receiving false into dataReceiveingSwitch signal.


  • Moderators

    @Yash001 I don't understand the need for a thread at all. Why do you think you need one? If you already get a signal to update the progress bar then there is really no need for a thread.



  • @jsulm.
    I want two functionality should work parallel.

    1. Thread One (Main thread);
      - Write the Data into File
      - Remove the Widgets if the Data Reeving completed ( few button and Progress bar dialog)

    2. another thread need to update progress bar.

    before you advise about Qthread I wrote this code. funcanality is work perfect.

    .h file

    #pragma once
    
    #include <global_typedefs.h>
    #include <QThread>
    #include <qtimer.h>
    #include <qeventloop.h>
    
    #define EXIT_CORRECTLY 0
    #define EXIT_INCORRECTLY 1
    
    class RecoveryProcessLoader : public QThread
    {
    	Q_OBJECT
    public:
    	static RecoveryProcessLoader* Instance();
    
    public:
    	 void RecordReceiveByte(const uint NumberOfReceiveByte);
    	 void calculateTotalBytes(const HardwareModel_t HWversion, const uint32_t numPagesUsed);
    	 
    signals :
    	void ProgressChanged(int);
    	void Finished(bool);
    	void Started();
    	void dataReceivePing();
    	
    public slots:
    	void dataReceiveingSwitch(bool);
    
    private:
    	RecoveryProcessLoader();
    	uint getPageSize(const HardwareModel_t);
    	volatile uint numberOfReceiveByte;
    	volatile uint totalNumberOfbyte;
    	bool previousSignalVal = false;
    	void run();
    };
    

    .cpp file

    #include "RecoveryLoader.h"
    
    
    RecoveryProcessLoader* RecoveryProcessLoader::Instance() {
    	static RecoveryProcessLoader * ret = 0 ;
    	if (0 == ret) {
    		ret = new RecoveryProcessLoader;
    	}
    	return ret;
    }
    
    RecoveryProcessLoader::RecoveryProcessLoader(){
    	//this->moveToThread(this);
    }
    
    uint RecoveryProcessLoader::getPageSize(const HardwareModel_t HWversion) {
    
    
    	return pageSizeOfFlash;
    }
    
    
    void RecoveryProcessLoader::calculateTotalBytes(const HardwareModel_t HWversion,const uint32_t numPagesUsed) {
    	numberOfReceiveByte = 0;
    	auto pageSize = getPageSize(HWversion);
    	totalNumberOfbyte = pageSize * 1;
    	return;
    	totalNumberOfbyte = pageSize * numPagesUsed;
    }
    
    void RecoveryProcessLoader::RecordReceiveByte(const uint numberOfByte) {
    	numberOfReceiveByte += numberOfByte;
    }
    
    void RecoveryProcessLoader::dataReceiveingSwitch(bool dataRxSwitch) {
    	
    	if (dataRxSwitch && (!previousSignalVal)) {
    		
    		previousSignalVal = true;
    
    		emit ProgressChanged(0);
    		emit Started();
    		this->start();
    	}
    	else if ((!dataRxSwitch) &&(previousSignalVal)){
    		previousSignalVal = false;
    		
    		this->exit(EXIT_CORRECTLY);
    		if (!this->isFinished()) {
    			this->wait();
    		}
    
    		emit ProgressChanged(100);
    		emit Finished(true);
    		
    	}
    	else {
    		NULL;
    	}
    }
    
    // This Thread may through wrong value for Finished signal if the dataReceiveingSwitch signal does not received in correct order.
    #define EXIT_BY_TIMER	1
    #define EXIT_BY_PING	0
    
    void RecoveryProcessLoader::run() {
    	QTimer timer;
    	QEventLoop loop;
    	QEventLoop *loopPtr = &loop;
    	QList<QMetaObject::Connection> connections;
    
    	connections << connect(this, &RecoveryProcessLoader::dataReceivePing, [=](){
    		emit ProgressChanged((numberOfReceiveByte * 100) / totalNumberOfbyte);
    		loopPtr->exit(EXIT_BY_PING);
    		});
    
    	connections << connect(&timer, &QTimer::timeout, [=]() {
    		loopPtr->exit(EXIT_BY_TIMER);
    	});
    
    	timer.start(10);
    	int ret = loopPtr->exec();
    	timer.stop();
    
    	foreach(auto conn, connections) {
    		disconnect(conn);
    	}
    
    	if (ret != EXIT_BY_PING) {
    		this->exit(EXIT_INCORRECTLY);
    
    		if (!this->isFinished()) {
    			this->wait();
    		}
    		emit Finished(false);
    		return;
    	}
    }
    

    I am using thread with signal because of on arrival of the datareceivSwitch signal, I wanted to start the loop on value of true. loop should be continue work until certain conditions.

    the loop should exit many condition like below.

    1. if the data is not receive.
    2. if datarecevSwitch signal does not send in proper order.
      Order: true false true false.
    3. datarecevSwitch get send false value.

    after getting guidance from you I try to remove the Qthread and Make this change.

    .h file

    class RecoveryProcessLoader : public QObject
    {
    	Q_OBJECT
    public:
    	static RecoveryProcessLoader* Instance();
    
    public:
    	 void RecordReceiveByte(const uint NumberOfReceiveByte);
    	 void calculateTotalBytes(const HardwareModel_t HWversion, const uint32_t numPagesUsed);
    	 
    signals :
    	void ProgressChanged(int);
    	void Finished(bool);
    	void Started();
    	void dataReceivePing();
    	
    public slots:
    	void dataReceiveingSwitch(bool);
    
    private:
    	RecoveryProcessLoader();
    	uint getPageSize(const HardwareModel_t);
    	volatile uint numberOfReceiveByte;
    	volatile uint totalNumberOfbyte;
    	bool previousSignalVal = false;
    	bool updateProgressBar();
    	bool dataNotReceive = false;
    };
    

    .cpp file funcations

    void RecoveryProcessLoader::dataReceiveingSwitch(bool dataRxSwitch) {
    	
    	while ((dataRxSwitch) && (!previousSignalVal))
    	{
    		previousSignalVal = true;
    
    		auto updateSuccessFull = updateProgressBar();
    
    		if (!updateSuccessFull) {
    			dataNotReceive = true;
    			emit Finished(false);
    			break;
    		}
    	}
    
    	if ((!dataRxSwitch) && (previousSignalVal) && (!dataNotReceive)) {
    		previousSignalVal = false;
    		emit ProgressChanged(100);
    		emit Finished(true);
    	}
    }
    
    
    #define EXIT_BY_TIMER	1
    #define EXIT_BY_PING	0
    
    bool RecoveryProcessLoader::updateProgressBar() {
    	QTimer timer;
    	QEventLoop loop;
    	QEventLoop *loopPtr = &loop;
    	QList<QMetaObject::Connection> connections;
    
    	connections << connect(this, &RecoveryProcessLoader::dataReceivePing, [=](){
    		emit ProgressChanged((numberOfReceiveByte * 100) / totalNumberOfbyte);
    		loopPtr->exit(EXIT_BY_PING);
    		});
    
    	connections << connect(&timer, &QTimer::timeout, [=]() {
    		loopPtr->exit(EXIT_BY_TIMER);
    	});
    
    	timer.start(10);
    	int ret = loopPtr->exec();
    	timer.stop();
    
    	foreach(auto conn, connections) {
    		disconnect(conn);
    	}
    
    	if (ret != EXIT_BY_PING) {
    		
    		emit Finished(false);
    		return false;
    	}
    	return true;
    }
    

    it make software crash. if i will comment loopPtr->exit(EXIT_BY_PING); and loopPtr->exit(EXIT_BY_TIMER); line then it is work.


  • Moderators

    @Yash001 said in What is good way to update the Progressbar value?:

    connections << connect(this, &RecoveryProcessLoader::dataReceivePing, ={
    emit ProgressChanged((numberOfReceiveByte * 100) / totalNumberOfbyte);
    loopPtr->exit(EXIT_BY_PING);
    });

    connections << connect(&timer, &QTimer::timeout, = {
    loopPtr->exit(EXIT_BY_TIMER);

    No wonder this crashes!
    You pass pointer to a local variable to a lambda. If then the signal is emitted after updateProgressBar() finished then the lambda will try to dereference a dangling pointer. Move the loop variable to the class (make it class member). But I still not see a need for a thread to update the progress bar - updating a progress bar is not an expensive operation and really does not need a thread.



  • @jsulm to handle this condition, I use the

    QList<QMetaObject::Connection> connections;
    

    and

    foreach(auto conn, connections) {
    		disconnect(conn);
    	}
    

    I am disconnecting all local signal in side the updateProgressBar().

    am I doing any wrong for disconnecting signals?

    another things is timer is local object. if I will comment only

    loopPtr->exit(EXIT_BY_PING);
    

    then also i am getting same issue.


  • Moderators

    @Yash001 Then you should check the stack trace when your app crashes...



  • @jsulm Thank you for giving me direction.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.