QProgressBar in new window don't work - c++

I'm creating the new window with QProgressBar when i click on button of MainWindow but when new window is creating, QProgressBar don't appear while filling cycle is working. After then QProgressBar appear and it is filled.
Constructor:
ProgressWin::ProgressWin():QWidget()
{
this->resize(273,98);
this->move(670, 430);
bar1 = new QProgressBar(this);
bar1->setGeometry(20, 31, 251, 31);
bar1->setMinimum(0);
bar1->setMaximum(10000);
this->show();
unsigned long long secr, PQ;
unsigned long long rv;
unsigned long long decr;
for(int v = 0; v <= 100000; v++) {
bar1->setValue(v);
}
}
Code of button that call new window:
void RsaMainWindow::ButtClickCrypt()
{
FileName1 = ui->LineCrypt->text();
if(FileName1.isEmpty()) {
QMessageBox::information(0, "Information", "File for Crypt wasn't chosen");
return;
}
NewWin = new ProgressWin;
}
Class for new window:
class ProgressWin : public QWidget
{
QProgressBar *bar1;
public:
ProgressWin();
};
Class for MainWindow:
[namespace Ui {
class RsaMainWindow;
}
class RsaMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit RsaMainWindow(QWidget *parent = 0);
~RsaMainWindow();
private slots:
void ButtClickViewCryp();
void ButtClickViewDecr();
void ButtClickViewKeys();
void ButtClickCrypt();
void ButtClickDecr();
private:
Ui::RsaMainWindow *ui;
QString FileName1;
QString FileName2;
QString FileName3;
ProgressWin *NewWin;
};][1]

User interface usually work on the event-loop principle:
While (not closing the app)
Wait for some event
update app according event
endWhile
If you implement your heavy task in the GUI thread, when the user click on "Perform a heavy task", the code managing this click is called, and after it finish, a following event will trigger the drawing of the window. That mean your heavy task will freeze the user interface during the task.
To perform a heavy task correctly, you need to:
Create a background thread that perform the task. Each iteration, it update some shared-memory (or equivalent) status of the task. Some UI libraries, like QT allows to send queued messages, which help for those cases.
On the Main thread, on update of the status, set the progress bar to the new value and return.

Related

Qt splashscreen won't close

I have a QSplashScreen made that runs through a bunch of images to resemble a gif and closes when the main window opens. This works fine on windows, but when I run it on mac it gets funky. Instead of closing when it's gone through all the pictures like it should it starts going through the images in revers order when clicked.
Here is header (splashscreen.h):
class SplashScreen : public QObject
{
Q_OBJECT
public:
explicit SplashScreen(QObject *parent = 0);
private:
QString filename0;
QString filename1;
QString filename;
int frameNum;
Qt::WindowFlags flags;
private slots:
void showFrame(void);
};
and here is implementation (splashscreen.cpp):
SplashScreen::SplashScreen(QObject *parent) :
QObject(parent)
{
QTimer *timer = new QTimer;
timer->singleShot(0, this, SLOT(showFrame()));
frameNum = 0;
}
void SplashScreen::showFrame(void)
{
QSplashScreen *splash = new QSplashScreen;
QTimer *timer = new QTimer;
frameNum++;
QString filename0 = ""; //first and second half of file path
QString filename1 = "";
splash->showMessage("message here", Qt::AlignBottom, Qt::black);
filename = filename0 + QString::number(frameNum) +filename1; // the number for the file is added here
splash->setPixmap(QPixmap(filename)); // then shown in the splashscreen
splash->show();
if (frameNum < 90)
{
timer->singleShot(75, this, SLOT(showFrame()));
}
else if (frameNum == 90)
{
splash->close();
flags |= Qt::WindowStaysOnBottomHint;
return;
}
}
and here is main file (main.cpp):
int main(int argc, char *argv[])
{
Application app(argc, argv);
SplashScreen *splash = new SplashScreen;
QSplashScreen *splashy = new QSplashScreen;
View view; //main window
QTimer::singleShot(10000, splashy, SLOT(close()));
splashy->hide();
QTimer::singleShot(10000, &view, SLOT(show()));
return app.exec();
}
I've got several different ways to close the splash screen but none of them seem to be working. Is this a bug in macs or is there something I can fix in my code?
There are created 90 different QSplashScreen objects. Only the 90th object is closed.
So, it is the main reason for observed behavior.
If you create a new splash screen QSplashScreen *splash = new QSplashScreen; for each frame then the previous screen should be closed and deleted. It is possible to store QSplashScreen *splash as a class member. Otherwise there is a memory leak.
You may consider to use only one instance of QSplashScreen splash as a private SplashScreen class member. The rest of the code may be unchanged (after replacement splash-> by splash.). It will be automatically deleted with deletion of SplashScreen.
Other issues
QTimer should not be instantiated each time to use its static member function. Each call of showFrame() and SplashScreen() creates a new QTimer object that is never deleted and never used.
The splashy also does not make any sense in main(). All three lines related to splashy may be deleted. Actual splash screens are triggered by new SplashScreen. By the way, it is also a leak. In that case it makes sense to instantiate it directly on the main() function stack: SplashScreen splash;
It looks that the private member SplashScreen::flags is not used.

Qt crashes/doesn't appear when i use Qthread::sleep to update progress bar

I am kinda new to QT so i am wondering why is this invalid:
I have a progress bar and i want to update it by using a class that inherits QThread.
void mt::run(QProgressBar * asd){
for(int i = 0;i<100;i++){
asd->setValue(i);
QThread::sleep(100);
}
}
mt is a class that inherits QThread. run is overloaded with a QProgressBar argument. My main UI thread will send it's progressbar like this m.run(ui->progressBar);. If i will remove the QThread::sleep(100); then it will work fine but i won't be able to see the increment because the thread will be done so fast. But if i will put a little delay, my screen won't appear at all.
You can access and update GUI elements from the main thread only.
If you want to prepare some data inside a custom thread, you should use the signals/slots mechanism to send that data to your widgets.
Here's a basic example:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QObject *parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
}
void MyThread::run()
{
for (int i = 0; i < 100; i++)
{
emit valueChanged(i);
QThread::sleep(100);
}
}
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
QHbovLayout *layout = new QHbovLayout(this);
QProgressBar *pb = new QProgressBar;
layout->addWidget(pb);
MyThread *t = new MyThread(this);
connect(t, SIGNAL(valueChanged(int)), pb, SLOT(setValue(int)));
t->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// we are in the main thread here, so we can create a widget
MyWidget w;
w.show();
return a.exec();
}
QThread::sleep(100);
You are telling it to sleep for a 100 seconds - that's quite a long time. Perhaps you meant QThread::msleep(100)?

Qt method call from another class?

I got two windows(two classes), one window that opens another when i click a button.
then the user inputs something into the newly opened window and then transfer that information to the first window when a button is clicked
The problem is I can't seem to send something to the second window so i can send the user input back to the main window. I read a few places that I should use Q_object but not really sure how that works
I should mention that I am new to Qt and didn't know about the designer there is in qt creator before i was way to ahead with the program.
Hope you have some ideas to how I can do this
edit1:
I should show the relevant code i have
Mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
//alot of stuff not relevant right now creating different stuff
changeProfile= new QPushButton("ændre valgte profil",this);
profileList = new QComboBox(this);
cProfile = new CreateProfile;
connect(changeProfile,SIGNAL(clicked()),this,SLOT(ProfileChange()));
}
void MainWindow::ProfileChange()
{
file pfile(profileList->currentText().toStdString());
string tempName = pfile.read(light);
cProfile->setValue(light,tempName);
cPr
ofile->show();
}
void MainWindow::setProfileList(QString Pname_)
{
bool found = 0;
for (int i = 0;i<5;i++)
{
if (Pname_ ==profileList->itemText(i))
found = 1;
}
if (found !=1)
profileList->addItem(Pname_);
}
createProfile.cpp
CreateProfile::CreateProfile(QWidget *parent)
:QMainWindow(parent)
{
//alot of other irrelevant stuff here
saveP = new QPushButton("Save",this);
connect(saveP,SIGNAL(clicked()),this,SLOT(saveProfile()));
}
void CreateProfile::saveProfile()
{
temp = pName->text();
file pFile(temp.toStdString());
bool lights[2] = {light1->checkState(),light2->checkState()};
if (temp.length() == 0)
{
MessageBox(NULL,"Du har ikke skrevet noget navn ind\n Prov igen","Error",MB_ICONWARNING+MB_SETFOREGROUND);
}
else
{
pFile.save(lights);
//call function setProfileList
this->hide();
}
}
If that makes sence, If you need the .h file too i can show them also
I need to call setProfileList from the mainwindow in the function saveprofile(there is in createprofile window) or if there is a way i can change the combobox in the wainwindow from the createprofile window?
edit 2:
mainwindow.h
#include "createprofile.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void ProfileChange();
//some other button clicks
public:
CreateProfile *cProfile;
void setProfileList(QString Pname_);
//other irelevant stuff
private:
// and some private members
};
createProfile.h
class CreateProfile : public QMainWindow
{
Q_OBJECT
public slots:
void saveProfile();
public:
explicit CreateProfile(QWidget *parent = 0);
~CreateProfile();
//and other stuff there isnt relevant
};
You are looking for the Qt signal-slot mechanism, namely:
class SecondWindow : public QMainWindow
{
Q_OBJECT
public:
SecondWindow(QWidget *parent = Q_NULLPTR) : QObject(Q_NULLPTR)
{
// ...
connect(secondWindowButton, SIGNAL(clicked(bool)), SLOT(handleClicked()));
// ...
}
public slots:
void SecondWindow::handleClicked()
{
// Gather information from the UI as you wish
firstWindow->foo();
}
// ...
}
or, if you have a container class for the windows, you could handle it in there, too, as follows:
connect(secondWindow->myButton, SIGNAL(clicked(bool)), SLOT(handleClicked()));
I found a very different way to do this, so I have made a QComboBox in the constructor of createProfile.cpp and then I have access to the profileList this way.

QMessageBox with a countdown timer

I wanted to know what would be the best approach of adding a countdown timer to a QMessageBox ? For instance when a message box is displayed the countdown timer starts for say 5 seconds. If the user doesn't respond to the Message box the message box picks up a default choice.
How about something like this:
#include <QMessageBox>
#include <QPushButton>
#include <QTimer>
class TimedMessageBox : public QMessageBox
{
Q_OBJECT
public:
TimedMessageBox(int timeoutSeconds, const QString & title, const QString & text, Icon icon, int button0, int button1, int button2, QWidget * parent, WindowFlags flags = (WindowFlags)Dialog|MSWindowsFixedSizeDialogHint)
: QMessageBox(title, text, icon, button0, button1, button2, parent, flags)
, _timeoutSeconds(timeoutSeconds+1)
, _text(text)
{
connect(&_timer, SIGNAL(timeout()), this, SLOT(Tick()));
_timer.setInterval(1000);
}
virtual void showEvent(QShowEvent * e)
{
QMessageBox::showEvent(e);
Tick();
_timer.start();
}
private slots:
void Tick()
{
if (--_timeoutSeconds >= 0) setText(_text.arg(_timeoutSeconds));
else
{
_timer.stop();
defaultButton()->animateClick();
}
}
private:
QString _text;
int _timeoutSeconds;
QTimer _timer;
};
[...]
TimedMessageBox * tmb = new TimedMessageBox(10, tr("Timed Message Box"), tr("%1 seconds to go..."), QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Default, QMessageBox::Cancel, QMessageBox::NoButton, this);
int ret = tmb->exec();
delete tmb;
printf("ret=%i\n", ret);
Use QTimer::singleShot with either close(), accept() or reject() slots if you don't need to display the timeout. If you need, then subclass QMessageBox or QDialog and reimplement methods as you want them to be, e.g. reimplement QObject::timerEvent to make text update.
If you want the message box to display the timer value I think you're better off making your own QDialog subclass. Otherwise it sounds simple - display your message with show, start the timer, connect to the timeout slot and manipulate your dialog.

Qt progressBar getting Unhandled exception how detect when parent widget is done loading

im using Qt QProgressBar and place it in the statusBar on my main window
Like this in the constructor :
pb = new QProgressBar(statusBar());
pb->setTextVisible(false);
pb->hide();
statusBar()->addPermanentWidget(pb);
then im running procsses (web page loadding in this case )
and trying to show the progress with :
connect(ui.webView, SIGNAL(loadProgress(int)), SLOT(setProgress (int)));
void myMainWindow:: setProgress(int progress)
{
pb->show();
pb->setRange(0,100);
pb->setValue(progress);
}
But im getting Unhandled exception when it comes to pb->show()
I guess it has to do something with loading the parent main windows and then the progress bar
I was reading about the QAbstractEventDispatcher and processEvents but not understood how to implement it .
i did small test and put the pb->show() function call in button click signal/slut
that means im triggering the pb->show() after the web page and the mainwindows fully loaded and its working fine without the exception. that make me belive there is problem
with the event processing.
here is the class :
class MainWindowMainWindowContainer : public QMainWindow
{
Q_OBJECT
public:
MainWindowContainer(QWidget *parent = 0);
public slots:
void adjustLocation();
void changeLocation();
void adjustTitle();
void setProgress(int p);
void finishLoading(bool);
void finishedSlot(QNetworkReply* reply);
private:
Ui::OnLineBack_mainWindow ui;
int progress;
void createWebViewActions();
QProgressBar *pb;
void setprogressBar(int progress,bool show);
};
MainWindowContainer::MainWindowContainer(QWidget* parent) :
QMainWindow(parent),
{
ui.setupUi(this);
progress = 0;
createWebViewActions();
ui.webView->load(QUrl("www.cnnnn.com"));
ui.webView->show();
pb = new QProgressBar(statusBar());
pb->setTextVisible(false);
pb->hide();
statusBar()->addPermanentWidget(pb);
}
void MainWindowContainer::createWebViewActions()
{
connect(ui.webView, SIGNAL(loadFinished(bool)), SLOT(adjustLocation()));
connect(ui.webView, SIGNAL(titleChanged(QString)), SLOT(adjustTitle()));
connect(ui.webView, SIGNAL(loadProgress(int)), SLOT(setProgress(int)));
connect(ui.webView, SIGNAL(loadFinished(bool)), SLOT(finishLoading(bool)));
connect(ui.webView, SIGNAL(linkClicked(const QUrl&)),this, SLOT(linkClicked(const QUrl&)));
}
void MainWindowContainer::setProgress(int p)
{
progress = p;
adjustTitle();
}
void MainWindowContainer::adjustTitle()
{
qApp->processEvents();
pb->show();
if (progress <= 0 || progress >= 100)
{
QString titl = ui.webView->title();
statusBar()->showMessage(titl);
setprogressBar(-1,false);
}
else
{
statusBar()->showMessage(QString("%1 (%2%)").arg(ui.webView->title()).arg(progress));
setprogressBar(progress,true);
}
}
void MainWindowContainer::finishLoading(bool)
{
progress = 100;
adjustTitle();
}
void MainWindowContainer::setprogressBar(int progress,bool show)
{
if(show)
{
pb->show();
pb->setRange(0,100);
pb->setValue(progress);
}
else
{
pb->hide();
}
}
In your createWebViewActions() function you connect the signals to their respective slots. (One small remark, the connect for the titleChanged(QString) signal and adjustTitle() slot fails because they have different signatures)
Among others you are connecting the signal loadProgress(int) to slot setProgress(int). In this slot you call adjustTitle() where the instruction pb->show() is being executed.
Notice that you are calling the createWebViewActions() function before the call to QProgressBar constructor
(...)
createWebViewActions(); <------ here you establish the signal->slot connections
ui.webView->load(QUrl("www.cnnnn.com"));
ui.webView->show();
pb = new QProgressBar(statusBar()); <------ here you call the QProgressBar constructor
pb->setTextVisible(false);
pb->hide();
statusBar()->addPermanentWidget(pb);
(...)
I think that maybe this slot (setProgress()) is being called before the QProgressBar is constructed which triggers the Unhandled exception you are getting.
You could try and move the call to the QProgressBar constructor so that it is created before the slots connection.