Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. (seemingly) simple Qt app: creating a progress bar

(seemingly) simple Qt app: creating a progress bar

Scheduled Pinned Locked Moved General and Desktop
72 Posts 5 Posters 58.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by
    #31

    Thanks for the clarification on #2 above. I was only putting text in the button as a convenience; I'll probably do it as you suggest above.

    I still don't get this:

    bq. But, as Volker said, keep in mind that text may or may not be displayed (depending on the widget style in use.)

    What is this widget style you're talking about? Do I have control over it?

    Thanks.

    1 Reply Last reply
    0
    • mzimmersM Offline
      mzimmersM Offline
      mzimmers
      wrote on last edited by
      #32

      Mlong -

      I've begun re-coding based on your suggestion above. It presents an issue, though. If I create objects (like m_bar) as private members of another object (like mainWindow), then this line of code obviously doesn't work:

      @ QObject::connect(&worker, SIGNAL(percentChanged(int)), bar, SLOT(setValue(int)));
      @

      So, is the solution to define a slot within mainWindow, and somehow re-deliver the signal to m_bar? Or, does Qt offer a somewhat more automated way of accomplishing this?

      Thanks.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        mlong
        wrote on last edited by
        #33

        bq. What is this widget style you’re talking about? Do I have control over it?

        On a Mac, Qt draws widgets in a Mac style. On Windows, it uses Windows' style. And so on. There are a number of ways to override the default style (although not all styles are available on all platforms -- you can't have Mac-styled widgets on Windows, for instance.) See "here":http://developer.qt.nokia.com/doc/qt-4.8/style-reference.html for some more details.

        bq. So, is the solution to define a slot within mainWindow, and somehow re-deliver the signal to m_bar?

        That's probably the most straightforward way I can think of offhand. Just create a public slot in MainWindow that will pass the information on to m_bar. That way you just expose the functionality that the world outside your widget needs to have access to, rather than exposing the entire QProgressBar. It makes the interface to your MainWindow class a little more tidy, in that it can have an interface to the outside world that is directly-related to the business at hand.

        Software Engineer
        My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

        1 Reply Last reply
        0
        • mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #34

          Thanks for the clarification about styles. It makes sense, now...it explains why Qt applications don't look identical on all platforms.

          I took a stab at changing the signal to go to the mainWindow object. It compiles, but doesn't work:

          in main.cpp, the new connect looks like:

          @ QObject::connect(&worker,
          SIGNAL(percentChanged(int)),
          &mainWindow,
          SLOT(setBarValue(int)));
          @

          and in mainwindow.cpp, I believe I need something like:

          @void MainWindow::setBarValue(int i)
          {
          emit barValueChanged(i);
          }
          @

          But I'm not sure where to go from here. Do I need another connect() call, and/or do I implement another slot to handle this signal, or...not?

          1 Reply Last reply
          0
          • G Offline
            G Offline
            goetz
            wrote on last edited by
            #35

            No, in the slot setBarValue(), you call

            @
            void MainWindow::setBarValue(int i)
            {
            m_bar->setValue(i);
            }
            @

            http://www.catb.org/~esr/faqs/smart-questions.html

            1 Reply Last reply
            0
            • mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by
              #36

              Oh, yes...because QProgressBar already has the smarts to know what to do with this, right? Got it. Thanks, Volker.

              OK, I guess the next step is to empower the close button. (Then maybe a start/stop button, and that'll be that for this exercise.) I gather that I'm probably to use this signal:

              @void QAbstractButton::clicked ( bool checked = false ) [signal]@

              Assuming this is right:

              1. would the connect() call most appropriately go within the MainWindow constructor?
              2. I gather the first half of the connect() would look like this:

              @ connect(&m_button, SIGNAL(clicked(bool)), )
              @

              but what would be the object for the third parameter? And, what is the signal to QMainWindow to get it to close? I can't find anything in the doc about closing (except in the saveState() method, which I'm pretty sure isn't relevant to this).

              Thanks for the help.

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #37

                The quick and dirty option would be:

                @
                connect(m_button, SIGNAL(clicked()), qApp, SLOT(quit()));
                @

                This just terminates the QApplication object, which in turn shuts down the rest of your application. Note that the bool parameter is not necessary here. It's sufficient to know that the button was clicked.

                This is quite "rude", though, as it does not ask the user, if it was ok to quit the application and the worker thread doesn't get a chance to finish its work cleanly. So what you could do, is connect the signal to a slot in the main window class, ask the user if he/she really wants to quit the application (using one of the static [[Doc:QMessageBox]] methods). If yes, send the thread a signal to terminate its work, wait until the thread has finished (using wait, probably with a timeout). Some outline would be:

                @
                // move the thread and the worker out of the main method
                // to the MainWindow class

                // so you have
                QThread *m_thread;
                Worker *m_worker;

                // define a signal
                requestWorkerToFinish();

                // in constructor of MainWindow:
                connect(m_button, SIGNAL(clicked()), this, SLOT(onQuitButtonClicked()));
                connect(this, SIGNAL(requestWorkerToFinish()), m_worker, SLOT(requestFinish()));

                // you have to implement requestFinish in the worker!

                void MainWindow::onQuitButtonClicked()
                {
                QMessageBox::StandardButton answer = QMessageBox::question(
                this,
                tr("Quit applicaton?"),
                tr("Do you really want to quit the application?"),
                QMessageBox::Yes | QMessageBox::No,
                QMessageBox::No
                );

                if(answer == QMessageBox::No)
                    // user clicked no, so just continue as if nothing had happened
                    return;
                
                emit requestWorkerToFinish(); // no direct call!
                bool finishOk = m_thread->wait(30000);
                if(!finishOk) {
                    qDebug() << "WARNING: request to finish thread timed out!";
                    m_thread->terminate();
                    m_thread->wait();
                }
                close();
                

                }
                @

                This is brain to terminal and untested. Please expect errors :-)

                Just a hint: if you do like outlined here, don't forget to reimplement closeEvent() in the main window. Otherwise your users are able to just nuke off your application by clicking on the (X) button in the title bar of the window!

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #38

                  Hi, Volker -

                  Since I'm not exactly breezing through this stuff, I'd like to take it step by step, so I'll begin with the quick and dirty option.

                  1. Just to keep my example program consistent with the code snippets in this thread, I tried renaming my QApplication from app to qApp. The build objected, claiming:

                  bq. error: no matching function for call to 'QApplication::QApplication(QApplication*)

                  I searched the docs for "qApp" and found that it's a global pointer, so evidently I shouldn't have tried to use it as a variable name. So, I reverted to the original variable name.

                  1. from what context (function) should the above connect call be made? If I do it in the mainwindow c'tor, it doesn't "see" my QApplication object (which lives in main()).

                  I suspect that the answers to these two issues are related. Can you tell me what's going on here? Should my QApplication object be global or something?

                  I can post code if desired. Thanks.

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    mlong
                    wrote on last edited by
                    #39

                    The purpose of the qApp macro is to provide a global access point to your QApplication. It's equivalent to the static method QCoreApplication::instance().

                    So long as you #include <QApplication> in a piece of code, then qApp will provide you with global access to your application instance.

                    Edit to add:

                    QCoreApplication (and, as such, QApplication) is an example of the "Singleton pattern.":http://en.wikipedia.org/wiki/Singleton_pattern As such, it inherently has global qualities.

                    Software Engineer
                    My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                    1 Reply Last reply
                    0
                    • mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #40

                      Well, then...I'm doing something wrong. Here's a couple of code snippets:

                      main.cpp:
                      @#include <iostream>

                      #include <QObject>
                      #include <QApplication>
                      #include <QString>
                      #include <QThread>

                      #include "workerthread.h"
                      #include "mainwindow.h"

                      using namespace std;

                      int main(int argc, char *argv[])
                      {
                      QApplication app (argc, argv);
                      MainWindow mainWindow;
                      .
                      .
                      .@

                      and mainwindow.cpp:
                      @#include <QApplication>

                      #include "mainwindow.h"

                      MainWindow::MainWindow(QWidget *parent) :
                      QMainWindow(parent)
                      {
                      m_bar = new QProgressBar (this);
                      m_button = new QPushButton (this);

                      setupWidgets();

                      connect(&m_button, SIGNAL(clicked()), app, SLOT(quit()));
                      }
                      .
                      .
                      .
                      @

                      I'm getting a compiler error that app isn't declared in mainwindow.

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        mlong
                        wrote on last edited by
                        #41

                        bq. I’m getting a compiler error that app isn’t declared in mainwindow.

                        It's not. The variable name "app" in main() has no bearing. It's not really a global. That's why you use qApp in other parts of your program. It's a shortcut that always refers back to "The QApplication" (There can only be one QApplication in your program, so it always "knows" what you're talking about.)

                        @
                        connect(&m_button, SIGNAL(clicked()), qApp, SLOT(quit()));
                        @

                        Software Engineer
                        My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                        1 Reply Last reply
                        0
                        • mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by
                          #42

                          Ahh...I suppose I should have figured that out. Thanks, mlong. Just for keeping the thread "good," I should point out another error in my code:
                          @ connect(&m_button, SIGNAL(clicked()), qApp, SLOT(quit()));
                          @
                          should actually be:
                          @ connect(m_button, SIGNAL(clicked()), qApp, SLOT(quit()));
                          @

                          As m_button is a pointer.

                          Anyway...it works! (Yes, I'm excited...I've learn to measure progress in small increments with respect to my education in Qt.) So...now that the "rude" implementation works, I'm ready to start on the more "polite" version that Volker implemented above. I'll be back with more newbie questions.

                          Thanks, mlong.

                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            mlong
                            wrote on last edited by
                            #43

                            Ah, good catch! You're right.

                            Glad to help out!

                            Software Engineer
                            My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                            1 Reply Last reply
                            0
                            • mzimmersM Offline
                              mzimmersM Offline
                              mzimmers
                              wrote on last edited by
                              #44

                              Hi, Volker:

                              Regarding this line:

                              @connect(this, SIGNAL(requestWorkerToFinish()), m_worker, SLOT(requestFinish()));
                              @

                              According to the docs, requestFinish() is a signal, not a slot. Or...am I supposed to define my own slot by this name?

                              1 Reply Last reply
                              0
                              • G Offline
                                G Offline
                                goetz
                                wrote on last edited by
                                #45

                                requestFinish() is only a signal in class [[Doc:QHttp]] - unless exactly that is your worker, you will need to define that slot in your worker class and act accordingly (e.g. setting a bool variable to true and check that regularly in your loop in order to finish it prematurely).

                                http://www.catb.org/~esr/faqs/smart-questions.html

                                1 Reply Last reply
                                0
                                • M Offline
                                  M Offline
                                  mlong
                                  wrote on last edited by
                                  #46

                                  Which docs are you looking at?

                                  You're supposed to define your own slot in your thread to start the "finish everything up and shut down" process there. Thus the comment, "// you have to implement requestFinish in the worker!"

                                  There's nothing special about that particular slot name. Is just an example.

                                  Software Engineer
                                  My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                                  1 Reply Last reply
                                  0
                                  • mzimmersM Offline
                                    mzimmersM Offline
                                    mzimmers
                                    wrote on last edited by
                                    #47

                                    Oops...my bad. I didn't read the documentation carefully. Thanks, guys.

                                    So, I defined the slot requestFinish(), which sets a bool that an "end" request was received. In my loop in run(), I test this bool. If it's true, I terminate the loop, which drops me to a file.close() and the end of the run() routine.

                                    I made my connect calls in my MainWindow c'tor:
                                    @ connect(m_button,
                                    SIGNAL(clicked()),
                                    this,
                                    SLOT(onQuitButtonClicked()));
                                    connect(this,
                                    SIGNAL(requestWorkerToFinish()),
                                    m_worker,
                                    SLOT(requestFinish()));
                                    m_worker->moveToThread(m_thread);
                                    @

                                    Now I get a run-time error:

                                    bq. QObject::connect: Cannot connect MainWindow::requestWorkerToFinish() to (null)::requestFinish()

                                    Is the reason I'm getting the (null) because I haven't yet called m_thread->start()? I guess I'm not too clear on the proper order of things in the c-tor (or if it's even OK to do this stuff in the c'tor).

                                    Thanks.

                                    1 Reply Last reply
                                    0
                                    • M Offline
                                      M Offline
                                      mlong
                                      wrote on last edited by
                                      #48

                                      Have you created m_worker at that point, yet? Let's see the ctor code.

                                      Software Engineer
                                      My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                                      1 Reply Last reply
                                      0
                                      • mzimmersM Offline
                                        mzimmersM Offline
                                        mzimmers
                                        wrote on last edited by
                                        #49

                                        I've created the pointer, but perhaps it doesn't get "populated" until the start() call?:

                                        @MainWindow::MainWindow(QWidget *parent) :
                                        QMainWindow(parent)
                                        {
                                        m_bar = new QProgressBar (this);
                                        m_button = new QPushButton (this);

                                        setupWidgets();

                                        connect(m_button,
                                        SIGNAL(clicked()),
                                        this,
                                        SLOT(onQuitButtonClicked()));
                                        connect(this,
                                        SIGNAL(requestWorkerToFinish()),
                                        m_worker,
                                        SLOT(requestFinish()));
                                        m_worker->moveToThread(m_thread);

                                        // run the run() method of the worker object once the thread has started

                                        QObject::connect(m_thread, SIGNAL(started()), m_worker, SLOT(run()));

                                        // enable the updating of the progress bar

                                        QObject::connect(m_worker,
                                        SIGNAL(percentChanged(int)),
                                        this,
                                        SLOT(setBarValue(int)));
                                        m_thread->start();
                                        }
                                        @

                                        1 Reply Last reply
                                        0
                                        • M Offline
                                          M Offline
                                          mlong
                                          wrote on last edited by
                                          #50

                                          m_worker should have a value as soon as you say m_worker = new WorkerThread(); Where are you doing that? In setupWidgets()? If so, can you show that code, as well?

                                          Software Engineer
                                          My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved