QProgressBar hanging at 98% - c++

I'm a beginner in Qt and I'm trying to show process bar for my application’s gui . i have written following code
void my_app::progress()
{
int val=1;
while(process.state()!=0)
{
ui->progressBar->setValue(val++);
}
ui->progressBar->setValue(100);
}
but progress bar is hanging at 98% . Can any one suggest me some solution .
thank you !

Two possible points: QProcess:::state() does not enter the Qt event loop - so calling it repeatedly will not update your application; all your Qt logic hangs. And verify the progressBar initialization: If the progressBar property "maximum" is not exactly 100 it'll will not reach 100%. Your "val" also ignores the "progressBar" maximum, so it needs a fix:
if( val < ui->progressBar->maximum() )
ui->progressBar->setValue(val++);
Most jobs have a clear concept of progress, which is not obvious here. Your while loop could be too fast to visually recognize the progress steps. Consider substituting the while loop with a signal/slot pair to sync the progressBar. This will also allow Qt to enter the event loop at times to update your app. Consider using the signal QProcess::readyReadStandardOutput() if your called process outputs something reasonable to stdout. Maybe your process does something, ie fills a buffer, whose size you can use to indicate progress - or simply outputs a count to stdout. Let me sketch here:
.. Somewhere in your my_app constructor ...
.. ui->progressBar->setRange(0, 100); ..
.. connect( this, SIGNAL(processProgressSignal(int)), this, SLOT(progressSlot(int) ); ..
.. connect( &process, SIGNAL(readyReadStandardError()), this, SLOT(processProgress()) ); ..
Q_SIGNALS:
void processProgressSignal( int val );
Q_SLOTS:
void my_app::processProgress()
{
int val = 1;
// Insert your process progress calculation here
// Example: Parse the result of QByteArray QProcess::readAllStandardOutput()
// Example: val = ( buffer.currLength / buffer.maxLength ) * 100;
Q_EMIT processProgressSignal( val );
}
void my_app::progressSlot(int val)
{
if( val < ui->progressBar->maximum() )
ui->progressBar->setValue(val++);
}
If that does not help, make sure that process.state() is 100 times "true" - to allow 100 iterations of your loop. qDebug() is your friend !
Good Luck!

Related

Updating QChart from QLineSeries in a running while loop

I want to make my QChart dynamically update whenever a point is added to the QLineSeries object attached to it, but it seems that this update only occurs after the while loop I am running has finished. I am using said while loop in interface.cpp that calls a function updatePlot() which adds the data point to the line series, but this only updates the chart after the while loop has completely finished. Pseudo code of what is happening here:
qtwindow.cpp
// Constructor that initializes the series which will be passed into the interface
AlgoWindow::AlgoWindow( ..., TradingInterface* interface, ... ) {
...
QLineSeries* series = new QLineSeries();
QLineSeries* benchmark = new QLineSeries();
QChart* chart = new QChart();
chart->addSeries(series);
chart->addSeries(benchmark);
// Also creates custom axes which are attached to each series
...
}
// Slot connected to a button signal
void AlgoWindow::buttonClicked() {
// Runs the backtest
interface->runbacktest(..., series, benchmark, ...);
}
interface.cpp
void TradingInterface::runbacktest(..., QtCharts::QLineSeries* algoplot, QtCharts::QLineSeries* benchplot) {
// Runs a huge while loop that continuously checks for events
while (continue_backtest) {
if (!eventsqueue.isEmpty()) {
// Handle each event for the bar
} else {
// All events have been handled for the day, so plot
updatePlot(algoplot, benchplot);
}
}
}
void TradingInterface::updatePlot(QtCharts::QLineSeries *algoseries,
QtCharts::QLineSeries *benchseries) {
// Get the date and the information to put in each point
long date = portfolio.bars->latestDates.back();
double equitycurve = portfolio.all_holdings.rbegin().operator*().second["equitycurve"];
double benchcurve = benchmarkportfolio.all_holdings.rbegin().operator*.second["equitycurve"];
// Append the new points to their respective QLineSeries
algoseries->append(date * 1000, equitycurve*100);
benchseries->append(date * 1000, benchcurve*100);
}
This gives me no errors and the while loop completes, but the lines are only plotted after runbacktest() exits. It then plots all the data correctly, but all at once.
What I need to happen is for the QChart to update every time the lines are added, which my guess was to use some form of custom signal-slot listener but I have no clue how to go about that. If the graph will not update until after the function completes, is it even possible within the QChart framework?
Also, I have already tried QChart::update() and QChartView::repaint(). Both produced the same results as without.
EDIT: I tried setting up a new thread that emits a signal back to the main thread whenever the data is completed but it seems to have changed nothing. The QChart still does not update until after all the data has been inputted. I added a couple lines to help debug and it seems like the function which emits the signal runs consistently just fine, but the slot function which receives the signal only runs after the thread has finished. Not only that, but slowing the signals down with a sleep does not make it plot slowly (like I thought), as the QChart still refuses to update until after the final update to addData().
Either remove your while loop and perform the work one step at a time with a timer.
Or run your runbacktest function in another thread and send a signal to update the QChart in the UI's thread when the data is ready.
Either way you need to give control back to the event loop so that the chart can be repainted.
The Qt idiom for running an operation “continuously” is to use a zero-duration “timer”. It’s not a timer really, but Qt calls it one.
You can do the operation in chunks that take approximately a millisecond. For this, invert the control flow. Qt doesn't provide too much syntactic sugar for it, but it's easy to remedy.
Convert this code, which maintains a loop:
for (int i = 0; i < 1000; ++i) {
doSomething(i);
}
into this lambda, which is invoked by the event loop:
m_tasks.addTask([this](i = 0) mutable {
doSomething(i);
++i;
return i < 1000;
});
assuming:
class Controller : public QObject {
Tasks m_tasks;
...
};
where the Tasks class maintains a list of tasks to be executed by the event loop:
class Tasks : public QObject {
Q_OBJECT
QBasicTimer timer;
std::list<std::function<bool()>> tasks;
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != timer.timerId())
return;
for (auto it = tasks.begin(); it != tasks.end(); ) {
bool keep = (*it)();
if (!keep)
it = tasks.erase(it);
else
++it;
}
if (tasks.empty())
timer.stop();
}
public:
using QObject :: QObject;
template <typename F> void addTask(F &&fun) {
tasks.emplace_back(std::forward(fun));
if (!timer.isActive())
timer.start(0, this);
}
};

How do I make a custom event with VTK?

I'm making a thread software with VTK, where I need to change the model itself in real time, while I need to change his method of rendering. Everything is working fine, but, the problem start with the interactor->start(); , the model data gets updated just fine, but it's only showed on screen when I move The camera. Also I have selected some methods for generating a 3D data from a imagedata file, for that I need to close the vtk window (interactor window) and then the code will reopen it and send the new data generated to it...
I would need something like these:
int force close_window = false; int refresh_interactor = false;
I managed to make the Window close, but only with vtkcommand::Keypressed command, but idk how do I do with a new command :S, I tried the vtkcommand::UserEvent but I didn't found a good information about how to deal with that data (like some way to call it)
the way I'm dealing with VTK is with two threads, the first one, is just about the vtk iren loop, and the second one would manage the models and check if iren requires to be updated.
In my dream code it should be something like this:
=======================================================
bool VTKWindow()
{
...
vtkSmartPointer ator = vtkSmartPointer::New();
iren = vtkSmartPointer::New();
RenWindow = vtkSmartPointer::New();
render->SetBackground(.1, .2, .3);
RenWindow->AddRenderer(renderer);
iren->SetRenderWindow(RenWindow);
if(data_type == voxel_type)
{
Render->AddViewProp(VoxelData);
}
else
{
actor->SetMapper(PolyData);
Render->AddActor(Actor);
}
RenWindow->Render();
iren->Start();
}
void ManageVTK()
{
while true loop...
if(force close_window == true)
do some command to exit the iren loop
if(refresh_interactor == true)
do some command to refresh iren
}
Sorry for the english, it's not my native language, and also sorry about the question format, it's the first time I'm using stackoverflow
It may sounds stupid, but, I found a kind of solution for the problem.
I saw on related links this guy vtkRenderWindowInteractor event loop and threading and, it's almost the same problem...
class VTKNewEvent : public vtkCommand{
public:
vtkTypeMacro(VTKNewEvent , vtkCommand);
static VTKNewEvent * New(){
return new VTKNewEvent ;
}
void Execute(vtkObject * caller, unsigned long vtkNotUsed(eventId), void * vtkNotUsed(callData)){
vtkRenderWindowInteractor *iren = static_cast<vtkRenderWindowInteractor*>(caller);
if (iren_close == true){
iren->GetRenderWindow()->Finalize // Stop the interactor
iren->TerminateApp();
iren_close = false;
}
if (iren_update== true){
renderJanela->Render();
iren_update= false;
}
}
};
bool VTKWindow(){
vtkSmartPointer<VTKNewEvent > IrenRefresh= vtkSmartPointer<VTKNewEvent>::New();
...
iren->CreateRepeatingTimer(1);//this makes that IrenRefresh will be called at every 1ms
iren->AddObserver(vtkCommand::TimerEvent, IrenRefresh);
iren->Start();
...
}
it's simple, but, maybe not the best, but it did Th job, I hope this link will help people that are starting into the VTK world, since threads + rendering loop wasn't a simple job to understand what was going on

Qt c++ Increasing integer with pushButton to label

I'm trying to make a simple "Cookie Clicker" game and I'm having trouble with this. When I press the button I want the label to print out "You have mined (VALUE) FSCoins" but the label won't update for some reason. Console shows no errors :(
Here's my code:
mainwindow.cpp
void MainWindow::on_pushButton_clicked(int num, int numplus)
{
num = numplus + 1;
QString qstr = QString::number(numplus);
ui->label->setText("You have mined " + qstr + " FSCoins");
}
Any help would be appreciated, I've only started working with Qt yesterday and I'm "Sort of" getting the hang of it.
num = numplus + 1;
What is the point of this line? num is a local variable that is never used. Did you mean to pass it by reference?
You need to connect a SIGNAL to a SLOT, but that function you wrote there does not seem like a SLOT. Somewhere in your code there shall be something like this in your header file:
class ...
{
// ...
private slots:
void onPushButtonClicked();
};
and in your source file:
// For example in the constructor.
connect( ui->PushButton, SIGNAL( clicked() ), this, SLOT( onPushButtonClicked() ) );
// The implementation of your SLOT.
Class::onPushButtonClicked()
{
// Your implementation.
updateLabel( /* Your arguments */ );
}
The SLOT function cannot have more arguments than the SIGNAL, so in this case your SLOT cannot have any.
And something else. I prefer this version of creating a QString:
QString( "You have mined %1 coins" ).arg( value );
I think it's more readable.
So the point is that that you need store that integers somewhere. Maybe in your class as a member variable.

Waiting till the QLineEdit text changes

I want to use QLineEdit to get an integer value that I want to work with. My problem is that I want to wait till the text is entered. It would also be nice if I can give a default text at the begining that will automatically be deleted after clicking on the QEditLine, like :
for the first point I tried this and it didn't work:
......
int num =0;
QLineEdit *qtest = new QLineEdit();
........
mailayout->addWiget(qtest);// when I use the while loop the QLineEdit won't be added !!
while(num ==0 ){
num = qtest->text.toInt();
}
.............
the program stays in the while loop, any Idea I'm doing wrong?
Use setPlaceholderTest(const QString&) for text to show when the user has not entered anything.
Don't poll the QLineEdit for changes, this is Qt so use signals.
connect( qtest, SIGNAL( editingFinished() ),
someContainerObj, SLOT( myLineEditSlot() ) );
...
ContainerObj::myLineEditSlot()
{
int num = qtest->text().toInt();
...
}

fill database table in wxListCtrl using wxThread- i can fill but system is going to hang

Firstly i make a program for showing table in wxListCtrl, it worked but for limited amount of data..
it shows a problem like:-
when i execute the program . frame do the visible after some time... but it works
then i turns to use wxThread now everthing is going fine, now when i execute the program frame immediately visible because i write Sleep(1000), so it add a line in wxListCtrl one by one , but it is giving unexpected result depend upon how many rows are in database..
my code is:-
# include "thread.h"
# include "login.h"
# include "sql.h"
# include <mysql.h>
class List_Ctrl_Data;
MyThread :: MyThread(login* login_obj)
{
this->temp = login_obj;
}
void *MyThread :: Entry()
{
int i=1,j,k=0 ;
while(i!=100)
{
long index=this->temp->data_list_control->InsertItem(i,wxT("amit"));
for(j=1;j<3;j++)
{
this->temp->data_list_control->SetItem(index,j,wxT("pathak"));
}
k++;
if(k==1)
{
k=10;
this->Sleep(1000);
}
i++;
}
}
here data_list_control is the object of wxListCtrl , with the help of thread i m filling value inside the wxListCtrl.
some people advised me that here u r knocking frame control( wxListCtrl) again and again from thread entry ,
thats why frame getting hanged you should use wxPost or AddPendingRequest for this, i dont think that it would work,
i tried to explain you my prob, still u feel to ask anything , u r welcome.. if you will help me, it would be a lot for me
The problems you are seeing are likely due to the fact that you are calling methods on a GUI control from a secondary thread rather than the main thread. This should never be done. You need to add the items from the main thread.
I'm guessing one of the reasons you have attempted to do this from a secondary thread is because it takes too long to add large number of items, and it's hanging your user interface. The correct approach is either to use a virtual list control (as noted in the "duplicate" question #Erik mentioned), or to periodically call wxYield (or wxSafeYield) while adding items so that UI events are processed.
********************************SOLUTION IS HERE******************
i used the code in thread like[ it get a row from database and pass to event]
void *MyThread :: Entry()
{
List_Ctrl_Data obj1 ;
MYSQL_RES *database_table_data;
database_table_data=obj1.getdata();
MYSQL_ROW row;
while((row=mysql_fetch_row(database_table_data))!=NULL)
{
wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, 100000 );
void *row_data;
row_data=(void *)row;
event.SetClientData(row_data);
temp->GetEventHandler()->AddPendingEvent( event );
this->Sleep(1000);
}
}
and for handling this we create a event table and a function to handle this value-
void onNumberUpdate(wxCommandEvent& evt);
private:
DECLARE_EVENT_TABLE()
in header file and in cpp file we write
void login::onNumberUpdate(wxCommandEvent& evt)
{
int i=0,j;
void* hold_row;
hold_row=(void *)evt.GetClientData();
MYSQL_ROW row;
row=(MYSQL_ROW)hold_row;
//while(row!=NULL)
//{
//wxPuts(wxT("kjhjkh"));
const char* chars1 = row[0];
wxString mystring1(chars1, wxConvUTF8);
long index=data_list_control->InsertItem(this->counter,mystring1);
this->counter++;
for(j=1;j<3;j++)
{
const char* chars2=row[j];
wxString mystring2(chars2,wxConvUTF8);
data_list_control->SetItem(index,j,mystring2);
}
//}
}
BEGIN_EVENT_TABLE(login, wxFrame)
EVT_COMMAND (100000, wxEVT_COMMAND_TEXT_UPDATED, login::onNumberUpdate)
END_EVENT_TABLE()
and finally i got the solution of my problem//////
www.rohitworld.site90.net OR ROHITAMITPATHAK#GMAIL.COM