Aus thread auf Formular zugreifen



  • Hi,

    Ich versuche einen Thread zu erstellen, der mir eine Zahl im Hauptfenster ausgeben soll. Das ganze habe ich mir so vorgestellt, dass der Thread aus dem Hauptfenster raus erstellt werden soll (nach button-click) und dann im thread the funktion "run" loslaufen soll.

    In der funktion soll die Zahl ermittelt werden und dann per signal zurück in einen Slot vom hauptfenster geschickt werden. Beim kompilieren bekomme ich diese Fehler:

    Undefined reference to 'vtable for hinzufuegen'
    Undefined reference to 'vtable for hinzufuegen'
    collect2: Id returned 1 exit status

    Hier die ist main.cpp:

    #include <hinzufuegen.h>
    ...
    void MainWindow::on_ok_clicked()
    {
    
        hinzufuegen *hin = new hinzufuegen;
        hin->start();
        connect(hin, SIGNAL(hinz_signal(int)), this, SLOT(add(int)));
    }
    
    void MainWindow::add(int i)
    {
        ui->listWidget->addItem(QString::number(i));
    }
    

    die main.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    
    private slots:
        void on_ok_clicked();
        void add(int i);
    };
    
    #endif // MAINWINDOW_H
    

    Hinzufuegen.cpp:

    #include "hinzufuegen.h"
    
    hinzufuegen::hinzufuegen()
    {
    }
    
    void hinzufuegen::run()
    {
        set_value(2);
    }
    
    void hinzufuegen::set_value(int i)
    {
        emit hinz_signal(i);
    }
    

    und die hinzufuegen.cpp:

    #ifndef HINZUFUEGEN_H
    #define HINZUFUEGEN_H
    #include <QThread>
    
    class hinzufuegen
        :public QThread
    {
    
        Q_OBJECT
    
    public:
        hinzufuegen();
    
    void run();
    
    public slots:
    void set_value(int);
    
    signals:
    void hinz_signal(int);
    
    };
    
    #endif // HINZUFUEGEN_H
    

    Hat irgendjemand eine Idee, was da faul sein könnte ?

    Grüße,
    Lusches



  • Hast du das Q_OBJECT-Macro erst später hinzugefügt? -> .pro öffnen, deinen hinzufuegen.h unter "HEADERS" hinzufügen. Danach ein make clean && qmake && make, und alles sollte richtig linken.



  • In der .pro-datei war schon ein eintrag vorhanden. Neu erstellen und bereinigen hat auch nichts gebracht.

    class hinzufuegen
        :public QThread
    {
    
    //Q_OBJECT
    
    public:
    
    void run();
    void set_value(int);
    
    signals:
    //void hinz_signal(int);
    
    hinzufuegen.cpp:
    
    void hinzufuegen::run()
    {
        set_value(2);
    }
    
    void hinzufuegen::set_value(int i)
    {
        //emit hinz_signal(i);
    }
    
    };
    

    So kann ich es erstellen, aber es funktioniert dann nicht mehr. Sobald ich "Q_OBJECT" nicht mehr auskommentiere kommt der fehler. Es hat anscheinend irgendwas mit Q_Objekt und dem Signal zu tun.


  • Mod

    Entfern evtl. die Datei mal aus dem Projekt vom Qt Creator, und füge sie dann wieder hinzu.
    Und dann solltest du das Projekt komplett neuerstellen. Klingt doof, hilft mir aber meistens.



  • Ich habe das Projekt schon mehrfach neu erstellt, aber irgendwie scheint es immernoch nicht zu funktionieren.

    thread.h:
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
        virtual void run()
        {
            for( int count = 0; count < 20; count++ )
                {
                    sleep( 1 );
                    qDebug( "Ping!" );
    
                }
        }
    };
    

    Das lässt sich super kompilieren.

    Aber sobald ich dann in der mainwindow.cpp folgendes einfüge, kommt der fehler:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include "thread.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_pushButton_clicked()
    {
        MyThread a;
    
    }
    

    Er tritt also erst dann auf, wenn ich versuche, eine Instanz der Klasse in der Mainwindow.cpp-datei zu erstellen.

    Undefined reference to 'vtable for MyThread'
    In function ~MyThread
    Undefined reference to 'vtable for MyThread'
    collect2: Id returned 1 exit status



  • Tip 1;
    1)Build-Probleme 2)Suchergebnisse 3)Ausgabe d.A. 4)Kompilierung
    Du guckst in 1) was eine Zusammenfassung von 4) ist. Guckstu in 4) mussdu vielleicht Scrollen aber da gibts viel mehr (auch rote) Meldungen die dir zu denken geben werden.

    Tip 2:

    void MainWindow::on_pushButton_clicked()
    {
        MyThread a;
    }
    

    Was glaubst du wie lange das leben wird? Geeeeeeeeeeeeeenau.

    Tip 3:
    Das Q_OBJECT Macro funzt nicht wenn man es in reine .h dateien packt die nirgendwo eine .cpp dazu liegen haben (dafür gibts zwar ein anderes Makro um es funzen zu lassen aber das kann ich mir irgendwie nicht merken).
    Bau dir also noch ne thread.cpp mach da ein #include "thread.h" rein und adde die .h und .cpp zu dem .pro file. dann nochmal make qmake && make und es sollte gehen - wenn du Glück hast1



  • Ich hatte leider kein glück.

    Aber: http://doc.trolltech.com/latest/qmake-project-files.html

    For example, if your application uses the Qt library and you want to build it as a multi-threaded application in debug mode, your project file will contain the following line:

    CONFIG += qt thread debug

    Damit scheint es jetzt zu funktionieren.

    void MainWindow::on_pushButton_clicked()
    {
        MyThread c;
        c.start();
        c.wait();
    
    }
    

    So kann ich den Thread starten, aber leider ist das GUI blockiert bis der Thread fertig ist. Das dürfte doch normalerweise nicht sein, oder ?

    Grüße,
    Lusches



  • Schau in die Doku was QThread::wait() macht. Dann siehst du dass das Verhalten absolut korrekt ist.



  • Ja, jetzt bin ich schon schlauer.

    Mein jetziges Problem sieht allerdings so aus:

    Ich will mehrere Threads laufen lassen, die auf eine Variable zugreifen und diese z.B. immer um 1 erhöhen. Dass ich dafür soetwas wie eine "critical section" brauche ist mir klar.

    Wie kann ich aber die globale Variable ordentlich deklarieren ?

    Schon in der mainwindow.h includiere ich die thread.h-datei.

    In der thread.h soll dann die globale Variable deklariert werden:

    #ifndef THREAD_H
    #define THREAD_H
    
    #include <QThread>
    
    extern int abba;
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
        virtual void run();
    
        signals:
        void neuezahl(int zahl);
    };
    
    #endif // THREAD_H
    

    ich bekomme immer den Fehler "multiple deklaration of 'abba'".

    Hat jemand einen Lösungsvorschlag ?



  • Das Problem ist gelöst.

    Wie kann ich n threads auf gleichzeitig starten ?

    Wenn ich 200 threads von Hand deklariere ist das irgendwie blöd.

    Das muss doch mit einer for-schleife funktionieren!

    for(int i = 0;i < = 100;i++)
    {
       Was muss hier rein ?  :) 
    }
    


  • Anscheinend funktioniert das mit QThreadpool. Dafür brauche ich aber ein QRunnable-objekt und kein QThread-objekt.

    Muss ich jetzt alles neu schreiben oder funktioniert das auch irgendwie mit QThread ?



  • Beliebig viele Objekte speichern?

    QList<MyThread*> threads;
    

    Und bitte brav aufpassen, dass der Thread auch den Scope überlebt (-> dynamische Speicherverwaltung).



  • Danke für deine Hilfe.

    Ich habe jetzt einfach in der Main-Klasse ein Thread-Array erstellt:

    private:
        Ui::MainWindow *ui;
        MyThread c[100];
    

    So starte ich die Threads:

    for(int i = 0;i < 50;i++)
        {
            connect(&c[i], SIGNAL(neuezahl(int)), this, SLOT(zahl(int)));
            connect(&c[i], SIGNAL(threadcount(int)), this, SLOT(showThreads(int)));
    
            c[i].start();
        }
    

    Jetzt kommt das misteriöse:

    Ich habe eine globale Variable definiert, auf die ich in allen erstellten Threads zugreifen will. Die Variable heißt "id" und wird vor thread-start auf 0 gesetzt. Dann soll sie bei jedem Thread hochzählen und jedem einzelnen Thread eine Id geben. Komischerweise ist "threadId" immer 1, egal wie viele Threads ich starte.

    void MyThread::run()
    {
        QMutex mutex;
    
        mutex.lock();
        id++;
        int threadId = id;
    
            while(current < proxy_count)
            {
                    current++;
            }
        mutex.unlock();
    }
    

    Woran liegt das ?



  • Lusches12345 schrieb:

    Woran liegt das ?

    Du hast Mutex nicht verstanden. Es muss GENAU EINE Mutex existieren, welche bei Zugriffen auf deine Variable gelockt wird.

    Deine connects bringen auch nicht viel. 1) sind das DirectConnections wegen 2) leben deine Threads im Main-Thread 3) seh ich nirgends ein "emit neuezahl(100)" o.Ä.



  • Du hast Mutex nicht verstanden. Es muss GENAU EINE Mutex existieren, welche bei Zugriffen auf deine Variable gelockt wird.

    Also muss ich eine Mutex global deklarieren ?

    #ifdef _extern_
    extern int proxy_count;
    extern int current;
    extern int threadsRunning;
    extern int id;
    extern QStringList proxyliste;
    extern QMutex mutex;
    #else
    int proxy_count = 0;
    int current = 0;
    int threadsRunning = 0;
    int id = 0;
    QStringList proxyliste;
    QMutex mutex;
    #endif
    

    so sehen jetzt meine globalen variablen in der Thread.h aus.

    vieleicht habe ich die funktion zu stark gekürzt:

    void MyThread::run()
    {
    
        QString proxy;
    
        mutex.lock();
        ThreadPlus();
    
        id++;
        int threadId = id;
    
            while(current < proxy_count)
            {
    
                    current++;
                    proxy = proxyliste[current-1];
    
                    emit checking(proxy, threadId);
    
                    //Hier proxy testen
    
                    emit checked(true, proxy);
    
            }
    
        ThreadMinus();
        mutex.unlock();
    
    }
    

    Die emits funkionieren einwandfrei und ich bekomme auch eine Ausgabe im Main-Thread. Allerdings wird immer die gleiche Id bei emit

    checking(proxy, threadId);
    

    zurückgegeben.

    void MainWindow::checking(QString proxy, int id)
    {
        ui->EThreads->addItem("Checking " + proxy + " from ID: " + QString::number(id));
    }
    

    Irgendwas scheint da nicht 100%tig zu funktionieren 😕



  • Da sind so viele unbekannte. Was machen z.B. ThreadPlus() und ThreadMinus()?
    Kannst du dein Programm bitte auf das Problem reduzieren, so dass ein kompilierbares Minimalbeispiel entsteht? das .ui rausschmeißen, GUI händisch erstellen, alle rechnenden Komponenten entfernen, einfach deine Threadklasse, dein MainWindow, deine Anzeigekomponente. Dein geposteter Code sollte direkt kompilierbar sein.



  • Jetzt habe ich mal meinen alten Account wiederbelebt.

    void MyThread::ThreadPlus()
    {
        threadsRunning++;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::ThreadMinus()
    {
        threadsRunning--;
        emit threadcount(threadsRunning);
    }
    

    threadcount wird dann im Main-Thread dazu verwendet, die anzahl der laufenden Threads anzuzeigen. Das funktioniert aber leider auch nicht. threadsRunning ist immer = 1 wenn die Threads laufen.

    Hier das Minimalbeispiel:

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    #include <QThreadPool>
    
    #define _extern_
    #include "thread.h"
    #undef _extern_
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        MyThread c[100];
    
    private slots:
        void on_pushButton_2_clicked();
        void on_pushButton_clicked();
        void showThreads(int);
    
        void checking(QString proxy, int id);
        void checked(bool type, QString proxy);
    };
    
    #endif // MAINWINDOW_H
    
    mainwindow.cpp:
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QMessageBox>
    
    #define _extern_
    #include "thread.h"
    #undef _extern
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::showThreads(int threads)
    {
        ui->statusBar->showMessage("Threads running: " + QString::number(threads));
        update();
    }
    
    void MainWindow::on_pushButton_clicked()
    {
    
        id = 0;
    
        for(int i = 0;i < 100;i++)
        {
            connect(&c[i], SIGNAL(threadcount(int)), this, SLOT(showThreads(int)));
    
            connect(&c[i], SIGNAL(checking(QString,int)), this, SLOT(checking(QString,int)));
            connect(&c[i], SIGNAL(checked(bool,QString)), this, SLOT(checked(bool,QString)));
    
            c[i].start();
        }
    
    void MainWindow::checked(bool type, QString proxy)
    {
    
        if(type)
        {
           ui->proxy_good->addItem(proxy);
        }
        else
        {
           ui->Proxy_bad->addItem(proxy);
        }
    
    }
    
    void MainWindow::checking(QString proxy, int id)
    {
        ui->EThreads->addItem("Checking " + proxy + " from ID: " + QString::number(id));
    }
    
    }
    

    thread.h

    #ifndef THREAD_H
    #define THREAD_H
    
    #include <QThread>
    #include <QRunnable>
    
    #include <QMutex>
    #include <QStringList>
    
    #include <QNetworkProxy>
    #include <QNetworkReply>
    #include <QNetworkAccessManager>
    
    #ifdef _extern_
    extern int proxy_count;
    extern int current;
    extern int threadsRunning;
    extern int id;
    extern QMutex mutex;
    #else
    int proxy_count = 0;
    int current = 0;
    int threadsRunning = 0;
    int id = 0;
    QMutex mutex;
    #endif
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
    
        virtual void run();
    
    private:
    
        void ThreadPlus();
        void ThreadMinus();
    
    signals:
        void threadcount(int zahl);
        void checked(bool, QString);
        void checking(QString, int);
    };
    
    #endif // THREAD_H
    
    #define _extern_
    #include "thread.h"
    #undef _extern_
    
    void MyThread::ThreadPlus()
    {
        threadsRunning++;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::ThreadMinus()
    {
        threadsRunning--;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::run()
    {
        mutex.lock();
    
        ThreadPlus();
    
        id++;
        int threadId = id;
    
            while(current < 600)
            {
                    current++;
                    mutex.unlock();
    
                    emit checking("proxy-name", threadId);
                    emit checked(true, proxy);
    
                    mutex.lock();
            }
    
        ThreadMinus();
        mutex.unlock();
    }
    

    so sollte es kompilierbar sein.

    Grüße,
    Lusches AKA Schnurres



  • Bitte jetzt nochmal ohne dem ui-Kram (oder poste das .ui mit). Du hast da auto-connections drinnen (implizites connectSlotsByName aus dem ui), irgend welche anderen Widgets, etc.
    Außerdem fehlt die main. Du deklarierst irgendwo extern-Variablen, aber wo steht da die Definition?
    Extern ist sowieso nix gut (global eben, außerdem kann man nicht beliebig viele extern-Objekte erstellen). Kannst du das nicht in einer Klasse kapseln, eine Instanz davon erzeugen und den Threads mit auf den Weg geben?



  • Ich habe dir einfach das gesamte projekt unkompiliert hochgeladen (6kb). Hier ist der Link:
    http://www.xup.in/dl,11804133/untitled.zip/

    Bisher gibt es sowieso nur den Thread und noch eine funktion, die mir eine Datei öffnet und ausliest.

    Grüße,
    Lusches



  • Hat niemand eine Lösung für mich ?

    Wenn ihr wollt poste ich die vollständigen Dateien als Quellcode. Dann braucht ihr keine Angst vor Viren zu haben. 😕

    Grüße,
    Schnurres


Log in to reply