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. Thread-GUI communication
Forum Update on Monday, May 27th 2025

Thread-GUI communication

Scheduled Pinned Locked Moved General and Desktop
26 Posts 4 Posters 18.8k 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.
  • N Offline
    N Offline
    NullCoding
    wrote on 23 Oct 2012, 17:05 last edited by
    #17

    Ignore the VerboseInfo class. It contains only a pointer to the GUI which you have said is not necessary.

    Class declaration:

    @class VerboseInfo;

    class VerboseWindow : public QObject
    {
    Q_OBJECT
    public:

    VerboseWindow(VerboseInfo * info = 0, int threadNum = 0);
    ~VerboseWindow();

    int threadNum;

    IIPStructV1 * piipstructv1;
    IIPStructV2 * piipstructv2;
    IIPStructV3 * piipstructv3;

    VerboseInfo * info;

    public slots:

    void BeginNormalVerboseTest();
    void UpdateProgressBar(int threadNum);
    void StopIIPVerboseNormal();
    void FactorFound(int threadNum, unsigned long int factor);
    int CheckFactors();
    void sayPrime(int threadNum);
    void sayComposite(int threadNum, int numFacs);

    signals:

    void testBegun();
    void progressBarUpdated();
    void testsStopped();
    void ReportFactor(int threadNum, unsigned long int factor);
    void itIsPrime(int threadNum);
    void itIsComposite(int threadNum);

    private:

    DWORD IIP_Test_Verbose_1(void * pv);
    DWORD IIP_Test_Verbose_2(void * pv);
    DWORD IIP_Test_Verbose_3(void * pv);

    };
    @

    Example of a function I call when a factor is found:

    @ void VerboseWindow::FactorFound(int threadNum, unsigned long int factor)
    {
    QString nt = QString("Found the factor %1\r\n").arg(factor);
    info->ui.factors->append(nt);
    QString nt2 = QString("%1\r\n").arg(factor);
    if (threadNum == 1)
    {
    info->ui.ThreadStatus1->appendPlainText(nt2);
    }
    if (threadNum == 2)
    {
    info->ui.ThreadStatus2->appendPlainText(nt2);
    }
    if (threadNum == 3)
    {
    info->ui.ThreadStatus3->appendPlainText(nt2);
    }
    info->ui.factorCount->display(info->ui.factorCount->value() + 1);

    int quolen = mpz_sizeinbase(piipstructv1->quotient, piipstructv1->base);
    CHAR* TheQuotient = new CHAR [quolen+5];
    WCHAR* TheQuotientW = new WCHAR [quolen+5];
    gmp_sprintf(TheQuotient, "%Zd\r\n\r\n", piipstructv1->quotient);
    mbstowcs(TheQuotientW, TheQuotient, quolen+5);
    WCHAR ShowFac[1024];
    swprintf(ShowFac, 1024, L"%lu's quotient is %ls", factor, TheQuotientW);
    QString quoq = QString::fromWCharArray(ShowFac, -1);
    info->ui.quotients->append(quoq);
    QString thequo = QString::fromWCharArray(TheQuotientW, -1);
    info->ui.messages->append(thequo);
    ZeroMemory (TheQuotientW, CountOf(TheQuotientW));

    emit VerboseWindow::ReportFactor(threadNum, factor);
    } @

    Still nothing is happening.

    1 Reply Last reply
    0
    • J Offline
      J Offline
      JKSH
      Moderators
      wrote on 23 Oct 2012, 23:31 last edited by
      #18

      Debugging questions:

      Does FactorFound() actually get called? (print a debug message from inside that function, to check)

      What is the ReportFactor() signal connected to?

      Does your GUI show up?

      Does your program have an event loop? (Does your main() function contain "a.exec()"?)

      Also, it looks like VerboseWindow is the Worker, not the GUI. Is that correct? If so, then VerboseWindow shouldn't be updating the progress bar (or writing plain text, or displaying the factor count) -- that's the GUI's job. When you want to update your progress bar, emit a signal with the info, and connect that to a GUI slot:
      @
      // Inside the VerboseWorker: (I renamed it for clarity, since the worker is not a window)
      void VerboseWorker::someFunction()
      {
      ...
      emit progressed(threadNum, percentageProgress);
      }

      // Externally:
      void ProgramEngine::someFunction()
      {
      ...
      connect(verboseWorker, SIGNAL(progressed(int, int)), gui, SLOT(updateProgressBar(int, int)));
      }

      // Inside the GUI:
      void Gui::updateProgressBar(int threadNum, int percentage)
      {
      switch (threadNum)
      {
      case 1:
      this->progressBar1->setValue(percentage);
      break;
      case 2:
      this->progressBar2->setValue(percentage);
      break;
      case 3:
      this->progressBar3->setValue(percentage);
      break;
      }
      }
      @

      Remember: The GUI can only be updated from the main thread. Qt won't let you update the GUI from any other thread.

      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

      1 Reply Last reply
      0
      • N Offline
        N Offline
        NullCoding
        wrote on 24 Oct 2012, 00:03 last edited by
        #19

        According to the task manager, the test doesn't even run because it's not using any CPU. There certainly is an event loop, though.

        @ int main(int argc, char *argv[])
        {
        QApplication a(argc, argv);
        IsItPrimeQT_200 w; // <-- main application class
        w.show();
        return a.exec();
        }
        @

        Hmm I'll re-work the whole class thing.

        It appears I was using signals and slots completely backwards. Great. Well, I'm self-taught, and this is better than the rocky start I got off to with C++ to begin with (read: this program doesn't use 4GiB of RAM)

        1 Reply Last reply
        0
        • J Offline
          J Offline
          JKSH
          Moderators
          wrote on 24 Oct 2012, 11:14 last edited by
          #20

          Yeah, self-teaching does lead to all sorts of adventures :) But it's definitely worth it.

          Keep us posted on your progress!

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          1 Reply Last reply
          0
          • N Offline
            N Offline
            NullCoding
            wrote on 25 Oct 2012, 13:17 last edited by
            #21

            I've gotten the start function to work properly. By that I mean that all the signals and slots are connected properly. I re-wrote the entire testing procedure so that it communicates with the GUI through signals/slots as it's meant to. No more passing GUI as a pointer or silly stuff like that.

            However I am still getting "QThread: Destroyed while thread was still running" and I have NO idea why! I never call QThread::stop() or something like that, nor do I explicitly delete the class instances used in the threads created.

            What is it that causes a thread manager to destroy the threads prematurely?

            1 Reply Last reply
            0
            • N Offline
              N Offline
              NullCoding
              wrote on 25 Oct 2012, 13:20 last edited by
              #22

              For reference, here is how the threads are created:

              @ QThread *vt1 = new QThread(this);
              QThread *vt2 = new QThread(this);
              QThread *vt3 = new QThread(this);

              connect(vt1, SIGNAL(started()), v1, SLOT(BeginNormalVerboseTest()));
              connect(vt2, SIGNAL(started()), v2, SLOT(BeginNormalVerboseTest()));
              connect(vt3, SIGNAL(started()), v3, SLOT(BeginNormalVerboseTest()));

              connect(vt1, SIGNAL(finished()), v1, SLOT(deleteLater()));
              connect(vt2, SIGNAL(finished()), v2, SLOT(deleteLater()));
              connect(vt3, SIGNAL(finished()), v3, SLOT(deleteLater()));
              

              v1->moveToThread(vt1);
              v2->moveToThread(vt2);
              v3->moveToThread(vt3);

              vt1->start();
              vt2->start();
              vt3->start(); @

              Before that, of course, I make a lot of other connections, but figure you'd get the idea.

              The BeginNormalVerboseTest() slot simply fills the testing structures from the GUI and then calls a DWORD function that performs the actual test. Once the test has run to completion, it simply cleans up memory and returns 0, which ought to end the thread from which it is called. It worked in Windows API, but I'm not sure what's different here.

              1 Reply Last reply
              0
              • K Offline
                K Offline
                KA51O
                wrote on 25 Oct 2012, 14:02 last edited by
                #23

                I'm not sure if this has any effect at all, but I ussually first call moveToThread and then do the connect statements.
                @
                QThread* myThread = QThread(this);
                Worker* myWorker = Worker();
                myWorker->moveToThread(myThread);
                connect(myThread, SIGNAL(started()), myWorker, SLOT(doTheJob()));
                connect(myWorker, SIGNAL(jobDone()), myThread, SLOT(quit()));
                connect(myWorker, SIGNAL(jobDone()), myWorker, SLOT(deleteLater()));
                connect(myThread, SIGNAL(finished()), myThread, SLOT(deleteLater()));
                @

                -If you don't expilicitly give the "connection type":http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum as a parameter in the connect statement Qt chooses the appropriate type for you. My fear is that if you first connect and then moveToThread, the connection type DirectConnection is selected since both objects up to this point live in the same thread. After the moveToThread the QueuedConnection type must be set and I'm not sure if this is reset after calling moveToThread.-

                Edit: After having a second look at the Qt::ConnectionType docs I realize that the AutoConnection type seems to select the connection type during runtime (i.e. when the signal is emitted). So the order in which you call connect and moveToThread doesn't matter.

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  JKSH
                  Moderators
                  wrote on 25 Oct 2012, 14:17 last edited by
                  #24

                  [quote author="NullCoding" date="1351171052"]I've gotten the start function to work properly. By that I mean that all the signals and slots are connected properly. I re-wrote the entire testing procedure so that it communicates with the GUI through signals/slots as it's meant to. No more passing GUI as a pointer or silly stuff like that.[/quote]Great! That really helps with modularization in Qt-based programs.

                  [quote]However I am still getting "QThread: Destroyed while thread was still running" and I have NO idea why! I never call QThread::stop() or something like that, nor do I explicitly delete the class instances used in the threads created.

                  What is it that causes a thread manager to destroy the threads prematurely?[/quote]The warning is shown if the QThread object is destroyed prematurely, before the thread stops/finishes/quits. You'll need to find out why they're being deleted, and stop it from happening.

                  [quote]
                  @QThread *vt1 = new QThread(this);@
                  [/quote]Regarding your premature deletions, my guess is that the parent object that owns the vt1, vt2 and vt3 is getting deleted prematurely. (By passing "this" into the constructor, "this" becomes the parent. Qt uses a parent-child relationship for memory management -- deleting a parent will delete all its children)

                  [quote]Once the test has run to completion, it simply cleans up memory and returns 0, which ought to end the thread from which it is called. It worked in Windows API, but I’m not sure what’s different here.[/quote]The difference is, QThread-created threads each have an event loop -- without one, signals/slots don't work.

                  That means the thread doesn't stop when your function (slot) returns; it just idles, until the next signal comes along and invokes the next slot. To stop a QThread-created thread, you'd have to call (externally):
                  @
                  vt1->exit();
                  // or
                  vt1->quit();
                  @

                  Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                  1 Reply Last reply
                  0
                  • N Offline
                    N Offline
                    NullCoding
                    wrote on 26 Oct 2012, 13:43 last edited by
                    #25

                    I have gotten it to work! I also added a stopping function since there is a "stop" button in the GUI. It exits the threads safely and there are no more premature destructions.

                    Odd thing is, each thread seems to do everything three times. It's odd. Also, the GUI locks up. I thought by using separate threads, I would be avoiding exactly that.

                    All I'm trying to do is update the GUI as the tests are in progress in another thread. Is that too much to ask? Something tells me Qt doesn't really want to do that. It leaves the GUI accessible, but very very laggy.

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      JKSH
                      Moderators
                      wrote on 26 Oct 2012, 16:23 last edited by
                      #26

                      [quote author="NullCoding" date="1351259018"]Odd thing is, each thread seems to do everything three times.[/quote]Let's have a look at your code

                      [quote]Also, the GUI locks up. I thought by using separate threads, I would be avoiding exactly that.[/quote]Is it just the GUI, or your whole machine? If it's the latter, it just means your laptop doesn't have enough grunt, and no amount of multithreading will help.

                      [quote]All I'm trying to do is update the GUI as the tests are in progress in another thread. Is that too much to ask? Something tells me Qt doesn't really want to do that. It leaves the GUI accessible, but very very laggy.[/quote]How regularly is the GUI getting updated?

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      1 Reply Last reply
                      0

                      26/26

                      26 Oct 2012, 16:23

                      • Login

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