Seite 1 von 1

qt Anfänger Netzwerk, Thread und andere Fragen?

Verfasst: 23. Mai 2011 15:31
von prinzenrolle
Hallo,
ich habe bezüglich qt noch ein paar Fragen,
da mir so einiges nocht nicht ganz klar ist.

1) Destruktor
Ich habe im qt Buch gelesen,
das es nicht notwendig ist Objekte zu zerstören,
wenn diese im Konstruktor this übergeben bekommen.
Wann wird denn nun Überhaupt ein Destruktor benötigt?
Oder habe ich etwas falsch verstanden.

2) QStackedwidget
Ich habe einige Bildschirme/Seiten erstellt und diese alle in ein QStackedwidget hinzugefügt. Die erstellten Widgets sind alles eigene Bildschirme/Seiten und werden mit einem Signalmapper und dem Signal clicked umgeschaltet. Da die Objekte,Widgets in den Stack eingefügt werden, existieren alle Bildschirme schon von Anfang an. Nun läuft das Programm auf einem embedded Device und ich Frage mich nun:
Je mehr "Bildschirme/Seiten" ich erstelle, desto langsamer muss doch das Programm werden, da die freien Ressourcen weniger werden oder?
Wie kann ich verhindern oder was muss ich abändern damit die Objekte erst beim Anzeigen erstellt werden und beim verlassen (umschalten des Bildschirms) zerstört werden, oder ist dies nicht nötig?

3) Single Thread oder mehrere Threads?
Das embedded Device soll ca. alle 500 mSec mithilfe von TCP/IP ein paar Pakete senden und empfangen ca 1-5 kByte also nicht so viele Daten. Da die Zielhardware ein single core arm9 ist Frage ich mich
ob mehrere Threads überhaupt Sinn machen?
Im Buch steht das auf einem einzelnen Prozessor Multithread Anwendungen langsamer laufen können und erst auf Mehrkern Systemen ihren Vorteil ausspielen. Was empfehlt Ihr mir?


Vielen dank für die Antworten.

Gruß

Verfasst: 23. Mai 2011 15:49
von yarikata
konnichiwa

Zu Punkt zwei:

Erstelle für StackedWidget eine sperate Methode, die dann während des Startens aus dem Contrucktor aufrufen kannst.
In der Methode erstellst du das eigentliche Widget.
Bsp.:

Code: Alles auswählen

 //Index 0 Start

    qlbild =new QLabel;
    qlbild->setScaledContents(true);
    qlbild->resize(600,400);
    qpmbild =new QPixmap("image\\logo_itc_programm_start");
    qlbild->setGeometry(0,0,640,400);
    qlbild->setPixmap(*qpmbild);
    qDebug()<<qpmbild->size();
 //   this->setCentralWidget (qlbild);

//   qlcentral =new QLabel;
    qswstacked =new QStackedWidget(this);
    qswstacked->addWidget (qlbild);
    qswstacked->setCurrentIndex (0);
    this->setCentralWidget (qswstacked);

    //Index 1
    qlbild =new QLabel;
    qlbild->setScaledContents(true);
    qlbild->resize(800,500);
    qpmbild =new QPixmap("image\\logo_itc_programm");
    qlbild->setGeometry(0,0,640,400);
    qlbild->setPixmap(*qpmbild);

    QStringList qslbaloheader;
    qslbaloheader<<"Nutzer-ID"<<"Name"<<"Recht"<<"Abteilung"<<"Status";


    qpbBLNeu =new QPushButton("Neu",qlbild);
    qpbBLAbb =new QPushButton("Abbrechen",qlbild);
    qtwAllNutzer =new QTableWidget(qlbild);
    qtwAllNutzer->setColumnCount (5);
    qtwAllNutzer->setHorizontalHeaderLabels(qslbaloheader);
    qtwAllNutzer->setAlternatingRowColors (true);
    qtwAllNutzer->resizeColumnsToContents ();

    qtwAllNutzer->setGeometry (25,10,450,400);
    qpbBLNeu->setGeometry (240,415,35,25);
    qpbBLAbb->setGeometry (275,415,75,25);
    qswstacked->addWidget(qlbild);
    connect (qpbBLNeu,SIGNAL(clicked()),this,SLOT(slotBenutzeranlegen()));
    connect (qpbBLAbb,SIGNAL(clicked()),this,SLOT(slotIndex0()));

    //Index 2 Posteingang anlegen
    qlbild =new QLabel;
    qlbild->setScaledContents(true);
    qlbild->resize(600,400);
    qpmbild =new QPixmap("image\\logo_itc_programm");
    qlbild->setGeometry(0,0,640,400);
    qlbild->setPixmap(*qpmbild);

   qglPEAnlegen =new QGridLayout;
   qlVorgangPE =new QLabel("Vorgang",qlbild);
   qleVorgangPE =new QLineEdit("PE.100.100.1",qlbild);
    qlDatumPE =new QLabel("Datum",qlbild);
    qlVnamePE =new QLabel("Vorname",qlbild);
    qlNnamePE =new QLabel("Nachname",qlbild);
    qlFirmaPE =new QLabel("Firma",qlbild);
    qleFirmaPE =new QLineEdit(qlbild);
    qlStrPE =new QLabel("Strasse",qlbild);
    qlHnrPE =new QLabel("Hausnummer",qlbild);
    qlPlzPE =new QLabel("Postleitzahl",qlbild);
    qlOrtPE =new QLabel("Ort",qlbild);
    qlInhaltPE =new QLabel("Inhalt",qlbild);
    qlBearbeiterPE =new QLabel("Bearbeiter",qlbild);
    qleDatumPE =new QLineEdit(qlbild);
    qleVnamePE =new QLineEdit(qlbild);
    qleNnamePE =new QLineEdit(qlbild);
    qleStrPE =new QLineEdit(qlbild);
    qleHnrPE =new QLineEdit(qlbild);
    qlePlzPE =new QLineEdit(qlbild);
    qleOrtPE =new QLineEdit(qlbild);
    qleBearbeiterPE =new QLineEdit(pUser,qlbild);
    qteInhaltPE =new QTextEdit(qlbild);
    qpbPEAnlegenOK =new QPushButton("OK",qlbild);
    qpbPEAnlegenAbbrechen =new QPushButton("Abbrechen",qlbild);
    connect (qpbPEAnlegenAbbrechen,SIGNAL(clicked()),this,SLOT(slotIndex0()));
    qleVorgangPE->setStyleSheet (QString("Font: bold; background: lightgrey;"));
    qleBearbeiterPE->setReadOnly (true);

        QDate date;
        QString n=date.currentDate ().toString ("dd.MM.yyyy");
        qleDatumPE->setReadOnly (true);
        qleVorgangPE->setReadOnly (true);
        qleDatumPE->setText (n);

        qlVorgangPE->setGeometry (25,10,50,25);
        qleVorgangPE->setGeometry (100,10,100,25);
        qlDatumPE->setGeometry (25,40,50,25);
        qleDatumPE->setGeometry (100,40,70,25);
        qlFirmaPE->setGeometry (25,70,50,25);
        qleFirmaPE->setGeometry (100,70,150,25);
        qlVnamePE->setGeometry (25,100,50,25);
        qleVnamePE->setGeometry (100,100,150,25);
        qlNnamePE->setGeometry (260,100,55,25);
        qleNnamePE->setGeometry (345,100,150,25);
        qlStrPE->setGeometry (25,130,50,25);
        qleStrPE->setGeometry (100,130,150,25);
        qlHnrPE->setGeometry (260,130,75,25);
        qleHnrPE->setGeometry (345,130,50,25);
        qlPlzPE->setGeometry (25,160,75,25);
        qlePlzPE->setGeometry (100,160,75,25);
        qlOrtPE->setGeometry (260,160,75,25);
        qleOrtPE->setGeometry (345,160,150,25);
        qlInhaltPE->setGeometry (25,190,50,25);
        qteInhaltPE->setGeometry (100,190,175,55);
        qlBearbeiterPE->setGeometry (25,250,50,25);
        qleBearbeiterPE->setGeometry (100,250,150,25);
        qpbPEAnlegenOK->setGeometry (25,425,70,25);
        qpbPEAnlegenAbbrechen->setGeometry (100,425,100,25);
         connect (qpbPEAnlegenOK,SIGNAL(clicked()),this,SLOT(slotsetPostEingang()));

        qswstacked->addWidget(qlbild);
Die Einzelnen Seiten rufst durch Methoden auf, in dem du in der Methode (die aufgerufen wird) folgendes schreibst:

void MainWindow::slotBenutzerBearbeitenLoeschen ()
{
qswstacked->setCurrentIndex (1);
this->setWindowTitle ("[Benutzer anlegen | bearbeiten | löschen]");
}

zu anderen Punkten weiß ich im moment keinen Rat

matane

Verfasst: 23. Mai 2011 16:15
von RHBaum
Ui das koennt hier länger werden, ich antwort aber nur ganz "kurz"

zu 1.
Du musst begreifen, das "zerstoeren" und "Destruktor" 2 unterschiedliche Dinge sind.
das erste ist der Vorgang, der nach dem allokieren (anfordern) von speicher vom Programmierer (dynamische allokation) oder vom compiler automatisch (Statische Allokation) angestossen wird.

der Destruktor ist aber wiederum ist eine Methode, die bei dem Vorgang zerstoeren des Objects(undabhaengig ob dynamisch oder statisch), wenn es sich um eine Klasse handelt, getriggert wird.

Instanzen von Klassen haben immer einen Destruktor. Wenn Du bei einer Selbstgeschriebenen Klasse keinen Definierst, baut dir der compiler einen (der nix macht) Guter Stil ist es den Destruktor selber zu definieren, auch wenn er nix macht. Weil man damit noch einige Dinge steuert (virtualitaet).

Bei der QT, diese Obhjecthirarchie nimmt dir halt arbeit ab. Der Parent loescht alle seine Clients. Das kann in deiner Programmstruktur eine Menge Arbeit sparen.

Trotz das die QT (oder besser der Parent deines Objectes dann), das loeschen deines Objectes Uebernimmt, ist immer garantiert, das der Destruktor aufgerufen wird.

zu 3.

Ja, Threads erfüllen 2 Zwecke.
- Hardwareseitige nebenlaufigkeit bei Prozessoren die mehrere Prozessunits haben.
- Aufbrechen von langwierigen Operationen in kleinere Teile, Ohne dass man mit hohem Programmieraufwand und uebel complexxen code arbeiten muss. Das unterbrechen von der langwierigen Operation uebernimmt dann das threading. Hauptanwendung ist, wenn du deine GUI nicht einfrieren lassen willst, wenn etwas langwieriges getan wird.
Als Fingerübung kannst ja mal eine funktion zur berechnung der fakultaet (rekursiv) hernehmen und ueberlegen wie du die funktion zerhacken muesstest, damit du in reglemaessigen abstaenden einen rueckruf fuer die GUI bekommst, damit das ding ned einfriert.
Mit multithreading wird das ding ned schneller, eher andersrum, aber deine funktion bleibt um welten einfacher, und damit besser wartbarer.

Multithreading Programme auf singelcore prozessoren wird immer (gering) langsamer sein, als wenn multithreading nicht verwendest und direkt rueckruffunktionen einbaust.

Ob es auf multikern System performance Vorteile bringt ist wieder von den konkreten gegebenheiten abhaengig. Tauschen 2 Threads imens daten untereinander aus, kann die synchronisation dir mehr overhaed bescheren, als wie dir multithreading vorteile bringt.
Der absolute Positivfall wiederum ist, wenn der Thread am anfang und an seinem ende nur daten austauscht, dazwischen nur mit seinen lokalen daten über einen langen zeitraum arbeitet. Dann lohnt sich das auslagern auf mehrere Prozessoren mittels threading (oder auch multiprozessing) extrem.
Empfehlen wuerd ich dir zuerst ohne multithreading, eventbasierend zu programmieren (bissi gewoehnungsbedeurftig fuer c++ programmierer, die meist strikt linear denken). Weil nebenlaeufigkeit bekommst auch schon, wenn du die sockets assynchron ansprichst. Dann hasst du schon nebenlaufiggkeit auf einen Thread flachgeklopft. Was eigentlich recht einfach zuhaendeln ist ....

Ciao ...

Verfasst: 23. Mai 2011 17:19
von prinzenrolle
yarikata hat geschrieben:konnichiwa

Zu Punkt zwei:

Erstelle für StackedWidget eine sperate Methode, die dann während des Startens aus dem Contrucktor aufrufen kannst.
In der Methode erstellst du das eigentliche Widget.
Bsp.:

Die Einzelnen Seiten rufst durch Methoden auf, in dem du in der Methode (die aufgerufen wird) folgendes schreibst:

void MainWindow::slotBenutzerBearbeitenLoeschen ()
{
qswstacked->setCurrentIndex (1);
this->setWindowTitle ("[Benutzer anlegen | bearbeiten | löschen]");
}

zu anderen Punkten weiß ich im moment keinen Rat

matane


Hallo,
vielen dank für die Antwort!
Aber leider verstehe ich nicht was du genau meinst.
Momentan werden bei mir die Objekte alle im Konstruktor erzeugt,
dieser ist von QStackedwidget abgeleitet.

Code: Alles auswählen

Stack::Stack(QWidget *parent) : QStackedWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint);
    this->setGeometry(QRect(0,0,640,480));

    sm = new QSignalMapper(this);

    S_Main = new MainScreen;
    S_Port = new PortSetup;
    S_Config = new Config;
    S_AP = new AP;
    S_APWeb = new AP_Website;

    addWidget(S_Main);
    addWidget(S_Port);
    addWidget(S_Config);
    addWidget(S_AP);
    addWidget(S_APWeb);
    setCurrentIndex(0);

    connect(S_Main->B_PortSetup, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Main->B_Logo, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Main->B_Exit, SIGNAL(clicked()), this, SLOT(exit()));
    connect(S_Port->B_Main, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Config->B_Main, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Config->B_AP, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_AP->B_Config, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_AP->B_Website, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_APWeb->B_AP, SIGNAL(clicked()), sm, SLOT(map()));

    sm->setMapping(S_Main->B_PortSetup, 1);
    sm->setMapping(S_Main->B_Logo, 2);
    sm->setMapping(S_Config->B_AP, 3);
    sm->setMapping(S_AP->B_Config, 2);
    sm->setMapping(S_AP->B_Website, 4);
    sm->setMapping(S_APWeb->B_AP, 3);
    sm->setMapping(S_Port->B_Main, SAVE_AND_BACK_TO_MAIN);
    sm->setMapping(S_Config->B_Main, SAVE_AND_BACK_TO_MAIN);

    connect(sm, SIGNAL(mapped(int)), this, SLOT(setIndex(int)));

    show();
}
void Stack::setIndex(int index)
{
    setCurrentIndex(index);
    if(index == SAVE_AND_BACK_TO_MAIN)
    {
        if(S_Port->SaveSettings())
            S_Port->writecfg();
        setCurrentIndex(0);
    }
}

Verfasst: 24. Mai 2011 07:38
von prinzenrolle
so in etwa?
oder hat jemand einen besseren Vorschlag?
Vielen dank!

Code: Alles auswählen

Stack::Stack(QWidget *parent) : QStackedWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint);
    this->setGeometry(QRect(0,0,640,480));

    sm = new QSignalMapper(this);

    S_Main = new MainScreen;
    S_Port = new PortSetup;



    addWidget(S_Main);
    addWidget(S_Port);
    setCurrentIndex(0);

    connect(S_Main->B_PortSetup, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Main->B_Logo, SIGNAL(clicked()), sm, SLOT(map()));
    connect(S_Main->B_Exit, SIGNAL(clicked()), this, SLOT(exit()));

    sm->setMapping(S_Main->B_PortSetup, 1);
    sm->setMapping(S_Main->B_Logo, 2);

    connect(sm, SIGNAL(mapped(int)), this, SLOT(setIndex(int)));

    connect(S_Port->B_Main, SIGNAL(clicked()), sm, SLOT(map()));
    sm->setMapping(S_Port->B_Main, SAVE_AND_BACK_TO_MAIN);


    show();
}

void Stack::setIndex(int index)
{
    int cnt,i;

    cnt = this->count();

    if(cnt > 3)
    {
        for(i=2;i<cnt;i++)
            delete widget(i);
    }

    switch(index)
    {
        case 2:
            S_Config = new Config;
            addWidget(S_Config);
            this->setCurrentWidget(S_Config);
            connect(S_Config->B_Main, SIGNAL(clicked()), sm, SLOT(map()));
            connect(S_Config->B_AP, SIGNAL(clicked()), sm, SLOT(map()));
            sm->setMapping(S_Config->B_AP, 3);
            sm->setMapping(S_Config->B_Main, SAVE_AND_BACK_TO_MAIN);
            break;
        case 3:
            S_AP = new AP;
            addWidget(S_AP);
            this->setCurrentWidget(S_AP);
            connect(S_AP->B_Config, SIGNAL(clicked()), sm, SLOT(map()));
            connect(S_AP->B_Website, SIGNAL(clicked()), sm, SLOT(map()));
            sm->setMapping(S_AP->B_Config, 2);
            sm->setMapping(S_AP->B_Website, 4);
            break;
        case 4:
            S_APWeb = new AP_Website;
            addWidget(S_APWeb);
            this->setCurrentWidget(S_APWeb);
            connect(S_APWeb->B_AP, SIGNAL(clicked()), sm, SLOT(map()));
            sm->setMapping(S_APWeb->B_AP, 3);
            break;
        default:
            setCurrentIndex(index);
            break;
    }




    if(index == SAVE_AND_BACK_TO_MAIN)
    {
        if(S_Port->SaveSettings())
            S_Port->writecfg();
        setCurrentIndex(0);
    }
}