QThread Problem - QLabel Actualisieren

Alles rund um die Programmierung mit Qt
Antworten
Darklink2000
Beiträge: 16
Registriert: 3. Februar 2011 18:52
Kontaktdaten:

QThread Problem - QLabel Actualisieren

Beitrag von Darklink2000 »

Hallo Leute,

ich stehe gerade bei meinem aktuellen Projekt vor einem Problem...
Und zwar ist dem Hauptprogramm ein LoginFenster Vorgeschallten. Dieses ist soweit fast fertig. Ich möchte jetzt aber noch das der MySQL-Server Status und der FTP-Server Status unten angezeigt wird. Das hatte ich auch schon fertig (QTimer triggerte alle 3 Sekunden die neuen Status Werte). Da gab es aber ein Problem...
Das Programm blieb dann alle 3 Sekunden für nichtmal ca 0.3 Sekunden hängen aber das nevt trotzdem stark...

Jetzt habe ich nach einer anderen Lösung gesucht und bin auf QThreads in der Hilfe gestoßen.
Jetzt ist mein Problem aber das die QLabel ja dann theoretisch IN der QThread::run() verändertw erden müssen. Diese sind aber in meiner
LoginWindow Klasse (als QLabel* ....) definiert.
Jetzt wollte ich versuchen in der Klasse wo ich die run() Methode überschreibe diese als Zeiger in der Parameter Liste zu übergeben aber da bekomm ich dann später viele Fehler...

Hier mal die Wichtigen Code Ausschnitte... (ich glaube daher das ich es vorher alles in der LoginWindow Klasse geändert habe und jetzt umgeschrieben habe, hab ich jetzt die ganzen Fehler. Ich würde mich über ein paar Tipps freuen)

spaceboxdb.cpp:

Code: Alles auswählen

#include "spaceboxdb.h"

SpaceboxDB::SpaceboxDB()
{
    database = new QSqlDatabase();
    database->addDatabase("QMYSQL", "Spacebox-DB");
    refreshServerStatusTimer = new QTimer();
    refreshServerStatusTimer->setInterval(3000);
}

void SpaceboxDB::run(QLabel *spaceboxSystemStatus, QLabel *fileServerStatus)
{
    refreshServerStatus(spaceboxSystemStatus, fileServerStatus, getSpaceboxSystemStatus());
}

void SpaceboxDB::startServerRefresh()
{
    //refreshServerStatusTimer->start();
    this->start();
}

bool SpaceboxDB::initDBC(QString host, QString user, QString pass, int port, QString db)
{
    database->setHostName(host);
    database->setUserName(user);
    database->setPassword(pass);
    database->setPort(port);
    database->setDatabaseName(db);

    if(database->open())
    {
        database->close();
        return(true);
    }
    database->close();
    return(false);
}

int SpaceboxDB::getSpaceboxSystemStatus()
{
    // -------------------------------------------------
    // 0 = Offline, Stoped
    // 1 = Online, Started
    // 2 = Wartungs Arbeiten (MaintenanceWork)
    // 3 = Not Wartung (CriticalMaintenanceWork)
    // 4 = Not Abschalltung (HadCriticalShutdown)
    // 5 = Vorübergehend Eingestellt (TempUnavaileble)
    // 6 = Unknown
    // -------------------------------------------------

    if(database->open())
    {
        QSqlQuery query(*database);
        query.exec("SELECT Status FROM system WHERE system.System = 'Service'");
        if(query.next())
        {
            if((query.value(0).toString().compare("Offline", Qt::CaseInsensitive) == 0) || (query.value(0).toString().compare("Stoped", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(0);
            }
            if((query.value(0).toString().compare("Online", Qt::CaseInsensitive) == 0) || (query.value(0).toString().compare("Started", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(1);
            }
            else if((query.value(0).toString().compare("MaintenanceWork", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(2);
            }
            else if((query.value(0).toString().compare("CriticalMaintenanceWork", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(3);
            }
            else if((query.value(0).toString().compare("HadCriticalShutdown", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(4);
            }
            else if((query.value(0).toString().compare("TemporaryUnavaileble", Qt::CaseInsensitive) == 0))
            {
                query.clear();
                database->close();
                return(5);
            }
            else
            {
                query.clear();
                database->close();
                return(6);
            }
        }
    }
    else
    {
        // Offline
        database->close();
        return(0);
    }
}

void SpaceboxDB::refreshServerStatus(QLabel *spaceboxSystemStatus, QLabel *fileServerStatus, int statusValue)
{
    if(statusValue == 0)
    {
        spaceboxSystemStatus.setText("Offline");
        spaceboxSystemStatus.setStyleSheet("color: red");
    }
    if(statusValue == 1)
    {
        spaceboxSystemStatus.setText("Online");
        spaceboxSystemStatus.setStyleSheet("color: green");
    }
    if(statusValue == 2)
    {
        spaceboxSystemStatus.setText("Wartung");
        spaceboxSystemStatus.setStyleSheet("color: orange");
    }
    if(statusValue == 3)
    {
        spaceboxSystemStatus.setText("Notfall Wartung");
        spaceboxSystemStatus.setStyleSheet("color: red");
    }
    if(statusValue == 4)
    {
        spaceboxSystemStatus.setText("Not Abgeschalltet");
        spaceboxSystemStatus.setStyleSheet("color: red");
    }
    if(statusValue == 5)
    {
        spaceboxSystemStatus.setText("Nicht Verfügbar");
        spaceboxSystemStatus.setStyleSheet("color: orange");
    }
    if(statusValue == 6)
    {
        spaceboxSystemStatus.setText("Unbekannt");
        spaceboxSystemStatus.setStyleSheet("color: purple");
    }

    // File Server Status
    QFtp ftpTester(this);
    ftpTest.connectToHost("xyz");
    ftpTest.login("abc", "defg");
    if(ftpTester.state() == QFtp::Connected || QFtp::LoggedIn)
    {
        fileServerStatus.setText("Online");
        fileServerStatus.setStyleSheet("color: green");
    }
    else
    {
        fileServerStatus.setText("Offline");
        fileServerStatus.setStyleSheet("color: red");
    }
}
Fehlermeldung: (immer die selbe für die ganzen QLabel Objecte in der SpaceboxDB Klasse)

Code: Alles auswählen

C:/Users/Tom - Henry Coursow/Documents/Qt_Projects/ToxxDream-Spacebox/spaceboxdb.cpp:113: Fehler: Abfrage des Elementes »setText« in »spaceboxSystemStatus«, das vom Nicht-Klassentyp »QLabel*« ist
Mir ist aufgefallen das er die QLabels nicht als Dynamische Objekte in der refreshServerStatus Funktion siht aber wiso sie sind doch als Zeiger angegeben...
Ach keine Ahnung ich hab gestern glaube ich in der Klasse nen Blackout gehabt :lol:
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: QThread Problem - QLabel Actualisieren

Beitrag von brax »

Pointer werden durch den "->" Operator dereferenziert, also z.B. spaceboxSystemStatus->setText("Offline");

Ein weiteres Problem, dass Du noch haben wirst, ist, dass Du GUI Elemente nur aus dem Mainthread verändern darfst. Du musst also von Deinem Thread dem Mainthread mitteilen, dass er die Textbox bitte verändern soll (am besten per SIGNAL vom Thread zu einem SLOT eines Objektes aus dem MainThread).

Ist Dir klar, dass

Code: Alles auswählen

void SpaceboxDB::run(QLabel *spaceboxSystemStatus, QLabel *fileServerStatus)
nicht wirklich die run() Methode (ohne Parameter!) von QThread überschreibt?
Darklink2000
Beiträge: 16
Registriert: 3. Februar 2011 18:52
Kontaktdaten:

Re: QThread Problem - QLabel Actualisieren

Beitrag von Darklink2000 »

Ja weiß ich. wie gesagt ich hab die letzen 2 tage fast schlaflos gearbeitet an meinen projekten ich bin total kaputt^^

Ich hab mir grade mal mein QT 4.6 Buch geholt und QThread Beispiel angeschaut dabei ist mir das ein wneig klarer geworden (das mir das jetzt erst einfällt wozu liegt das da im schrank... naja meist versuch ich immer alles selbst hinzubekommen und meist klappts auch^^).
Ich wollte in meiner LoginWindow Klasse jetzt ne public methode machen die den int wert "statusValue" erhält vom thread aber das mit dem
connect ist glaub ich noch besser. Ich werds nacher mal ausprobieren. Aber erstmal mach ich PAUSE :mrgreen:

Ich schreib denn heute abend mal wies gelaufen ist oder ob ich noch frustrierter werde^^
Aber ich bin eigentlich zuversichtlich. Danke für die Tipps das wird mir glaub ich weiterhelfen.

Sonstiges: Ich weiß das ich dann -> schreiben muss aber er erkennt das nicht... wenn ich . drücke schreibt er den auch und nicht -> oder hat Qt ein paar errors und ich hätte das manuel trotzdem machen können?
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: QThread Problem - QLabel Actualisieren

Beitrag von brax »

Darklink2000 hat geschrieben: Sonstiges: Ich weiß das ich dann -> schreiben muss aber er erkennt das nicht... wenn ich . drücke schreibt er den auch und nicht -> oder hat Qt ein paar errors und ich hätte das manuel trotzdem machen können?
Moderne IDEs bieten zwar viel Komfort, aber sie sind leider nicht unfehlbar. Der Compiler ist es zwar auch nicht, aber er ist verdammt nah dran ;)

Jedenfalls kannst Du Dich nicht darauf verlassen, dass, nur weil die IDE (ich nehme mal an, Du benutzt den QtCreator) es nicht korrekt auflöst, es auch nicht geht, bzw. andersrum geht nicht alles durch den Compiler, was die IDE meint auflösen zu können. An der Stelle hat auch nicht Qt die Fehler sondern eben Deine IDE. Und ja, wenn Du einen Pointer auf ein Objekt hast und auf dem Objekt eine Methode aufrufen möchtest, dann kannst, nein MUSST, Du das über -> machen, auch wenn der QtCreator anderer Meinung ist und Du es "manuell" einfügen musst.

Na dann, schlaf Dich erstmal aus ;)
Darklink2000
Beiträge: 16
Registriert: 3. Februar 2011 18:52
Kontaktdaten:

Re: QThread Problem - QLabel Actualisieren

Beitrag von Darklink2000 »

Ich hab jetzt alles weitestgehend richtig denke ich mal.

Nur irgendwie bleibt der Thread hängen... Kann es sein das ich nicht die exec() funktion aufrufen muss weil wenn ich alles
mit qDebug() meldungen versehe bleibt er ab dem aufruf exec() stecken...
Ich dachte das exec() die run methode aufruft und wenn ich in der run() methode z.b ein exit(3) habe dass das dann das ergebnis vom exec ist.

Im LoginWindow hab ich ein Object meiner Subklasse die von QThread abgeleitet ist.
Dieses ruft die Public methode getStatus() und das ergebnis wirdin einer in variable gespeichert / naja soll jedenfalls...
Aber soweit kommt er ja nicht wie oben erwähnt.

Oder wie muss ich in meinem Fall vorgehen?

Meine Thread Klasse:

Code: Alles auswählen

#include "serverstatusthread.h"

ServerStatusThread::ServerStatusThread()
{
    spaceboxDB = new SpaceboxDB(); // QSqlDatabase
    spaceboxDB->initDBC("host", "user", "pw"); // Set connection settings
    complete = false;
}

void ServerStatusThread::run()
{
    qDebug() << "IM THREAD RUN"; // wird auch nie angezeigt :-(
    if(complete)
    {
        complete = false;

        // File Server Status
        QFtp ftpTester(this);
        ftpTester.connectToHost("morh-kasis.de");
        ftpTester.login("user", "pw");
        if(ftpTester.state() == QFtp::Connected || QFtp::LoggedIn)
        {
            this->exit(1);
        }
        this->exit(0);
    }

    complete = true;
    this->exit(spaceboxDB->getSpaceboxSystemStatus());
}

int ServerStatusThread::getStatus()
{
    qDebug() << "Will threat aufrufen...";
    return(this->exec());
    qDebug() << "Kommt das noch?"; // Nein leider nicht...
}
Weiß jemand von euch wiso? Sry in Sachen Threads bin ich auf neuland...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QThread Problem - QLabel Actualisieren

Beitrag von Christian81 »

Wie man einen Thread startet steht in der Doku - samt Beispielen. Die sollte man sich erstmal durchlesen bevor man mit Programmieren anfängt und auch bevor man Fragen stellt die zeigen dass dies so unter keinen Umständen funktionieren kann.

/edit: Abgesehen davon braucht man für QFtp nicht unbedingt einen Thread - QFtp arbeitet asynchron.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Darklink2000
Beiträge: 16
Registriert: 3. Februar 2011 18:52
Kontaktdaten:

Re: QThread Problem - QLabel Actualisieren

Beitrag von Darklink2000 »

Bei mir funktioniert der Thread jetzt eigentlich einwandfrei nur jetzt kann meine Datenbank Klasse die QSqlDatabase nichtmehr öffnen durch die open() methode. (gibt false zurück - alle Verbindungsoptionen hab ich aber richtig eingegeben)
Liegt das daran das ich in einem Thread Eventuel keine Datenbank Arbeiten machen kann?
Als ich meine Datenbak Klasse noch Statisch aufgebaut hatte ging noch alles erst seitdem es nichtmehr Static ist und in der Thread Klasse das Datenbank Object liegt gehts nichtmehr...
Antworten