Seite 1 von 1

[gelöst] Eigener QDialog -> Texte aktualisieren

Verfasst: 19. Mai 2005 17:13
von dani.80
Hallo,
was ich machen will, ist ein eigener Dialog, der aus 3 Texten besteht (QLabels, die mit Hilfe von setText mit verschiedenen Werten belegt sind), und aus 2 ProgressBars.
Jetzt ist es so, dass ich während die ProgressBars durchlaufen (was wunderbar funktioniert) an bestimmten Stellen die Texte der Labels ändern will.
Ich erzeuge mir an den Stellen eine neue QString Variable und möchte das Label mit dem neuen Text belegen. Leider zeigt der Dialog aber durchgehend den ersten Text an, obwohl ich zwischendurch mit setText einen neuen Text für das Label festlege.
Woran könnte das liegen?

Danke schonmal,
Viele Grüße,
Dani

Verfasst: 19. Mai 2005 19:25
von FlorianBecker
Das liegt daran, das die Funktionen alle nach einander durchlaufen.

Eine Funktion fängt an und läuft bis sie zu Ende ist. Ein Progressbar läuft bis er zu Ende ist. Die einzigste Klasse, die ich auswendig weiß ist die HTTP Klasse von Qt, die nicht nach diesen Regeln arbeitet. Die Dokumentation sagt dazu async oder so ähnlich.

Da helfen die Threads, was gerade für einen Progressbar sehr sinnvoll ist. Ein Thread ist ein Unterprozess deines Programmes der unabhängig von dem Hauptprogramm läuft.
QThread name;
name.start();
und vererben um run() eine Funktion zu geben, das steht nochmal ein bischen detaillierter in der Dokumentation zu QThread drin.

Verfasst: 19. Mai 2005 23:00
von dani.80
Vielen Dank, das werd ich mir mal anschauen.
Vielleicht kannst du mir folgendes Phänomen erklären:
Wenn ich statt QDialog QProgressDialog nehme und diesem dann die gewünschten Labels und Progressbars hinzufüge, so dass der eigentlich ProgressBar, der schon im QProgressDialog enthalten ist und der Cancel-Button gar nicht angezeigt werden.
Wenn ich dann in diesem "unsichtbaren" ProgressBar setTotalSteps(0) aufrufe, und in den Schritten, wo ich die Texte verändern will mit setProgress diesen "unsichtbaren" ProgressBar einen Fortschritt zuweise, funktioniert es, dass sich die Texte verändern an dieser Stelle.
Deswegen dachte ich, dass es doch mit einem normalen QDialog auch irgendiwe funktionieren müsste.

Danke für deine Hilfe,
viele Grüße,
Dani

Verfasst: 19. Mai 2005 23:05
von FlorianBecker
Dabei wird kein Ablauf der Schritte aufgerufen, sondern du ruft manuell die Schritte auf und auch da macht er eins nach dem anderen, es kommt dir nur so vor, als wenn es parallel laufen würde.

Verfasst: 19. Mai 2005 23:13
von dani.80
Hm, okay. Also hier verändert sich der Text schon während der ProgressBar läuft, eigentlich genau so, wie ich das auch möchte. Aber die Lösung ist natürlich nur irgendwie hingemogelt.... :-)

Verfasst: 19. Mai 2005 23:56
von dani.80
Nochmal:
Muss ich dann die Abläufe, in denen ich die Texte verändere und neu setzen möchte als Threads deklarieren. Blick da noch nicht ganz durch.
Ich hab hier auch nochmal nen Teil Code, mit dem es nicht funktioniert. (der ohne QThreads)

Code: Alles auswählen

.....
prog_dialog=new QProgressDialog(this,"progress",TRUE);
        prog_dialog->setGeometry(200,200,300,200);
        prog_layout=new QVBoxLayout(prog_dialog);
        titel = new QLabel(prog_dialog);
        sequenz_titel=new QLabel(prog_dialog);
        titel->setText("Fortschrittsanzeige:");
        prog_layout->addWidget(titel);
        prog_layout->addWidget(sequenz_titel);
        sequenz_titel->setText("Gesamtfortschritt:");
        int size=filenames.size();
        int size_dirs=dirs.size();
        if (size!=0) {
                bar1=new QProgressBar(3*size+1,prog_dialog);
        }
        else {
                bar1=new QProgressBar(3*size_dirs+1,prog_dialog);
        }
        prog_layout->addWidget(bar1);
        sequenz_index=0;
        bar1->show();
        schritt_titel=new QLabel(prog_dialog);
        prog_layout->addWidget(schritt_titel);
        schritt_titel->setText("Aktuelle Sequenz:");
        bar2=new QProgressBar(prog_dialog);
        prog_layout->addWidget(bar2);
        bar2->show();
        prog_layout->activate();
        prog_dialog->show();
..........
         QString s2="Name";
         schritt_titel->setText("Aktuelle Sequenz:"+s2);
          
        

Und diesen neu zugewiesenen Text möchte ich sofort sichtbar machen. Aber ich verstehe noch nicht ganz, weshalb das an dieser Stelle nicht möglich ist.
Aber dazu habe ich mich vielleicht auch nur zu wenig mit den Eigenschaften von Threads etc. beschäftigt.

Trotzdem danke für Erklärungsversuche.

:D

Verfasst: 20. Mai 2005 00:37
von FlorianBecker
Hi, dein Code sieht umständlicher aus, als er sein könnte. Kommentare im Code.

Code: Alles auswählen

..... 
        prog_dialog=new QProgressDialog(this,"progress",TRUE); 
        prog_dialog->setGeometry(200,200,300,200); 
        prog_layout=new QVBoxLayout(prog_dialog); 
        titel = new QLabel(prog_dialog); 
        sequenz_titel=new QLabel(prog_dialog); 
        titel->setText("Fortschrittsanzeige:"); 
        prog_layout->addWidget(titel); 
        prog_layout->addWidget(sequenz_titel); 
        sequenz_titel->setText("Gesamtfortschritt:"); 
        int size=filenames.size(); 
        int size_dirs=dirs.size(); 
       /* if ( !size ) und ohne Klammern? - Naja, das ist wie eine Krankheit immer alles zu verbessern :D */
        if (size!=0) { 
                bar1=new QProgressBar(3*size+1,prog_dialog); 
        } 
        else { 
                bar1=new QProgressBar(3*size_dirs+1,prog_dialog); 
        } 
        prog_layout->addWidget(bar1); 
        sequenz_index=0; 
        /* Nicht nötig */
//        bar1->show(); 
        schritt_titel=new QLabel(prog_dialog); 
        prog_layout->addWidget(schritt_titel); 
        schritt_titel->setText("Aktuelle Sequenz:"); 
        bar2=new QProgressBar(prog_dialog); 
        prog_layout->addWidget(bar2); 
        /* Ebenfalls nicht nötig */
//        bar2->show(); 
        /* Mh, wozu genau ist das? Ich glaube ebenfalls nicht nötig, lass es aber erstmal stehen. */
        prog_layout->activate(); 
        /* Wenn du einen Dialog mit exec ausführst, wird der modal=true, was eigentlich der Sinn eines Dialoges ist. Sonst kann man auch gleich ein normales Widget nehmen. */
        prog_dialog->show(); 
        /* Was genau passiert denn hier? So wie das aussieht läuft das doch alles prima, wo werden denn die ProgressBars gestartet? */
.......... 
         /* Also wenn das all dein Code ist, sind die ProgressBars still und bewegen sich nicht. Hier kann keines der beschriebenen Probleme liegen... */
         QString s2="Name";
         /* siehe auch QString::arg() */
         schritt_titel->setText("Aktuelle Sequenz:"+s2);

Verfasst: 20. Mai 2005 10:38
von dani.80
Ok, also da sind ein paar überflüssige Sachen drin. Gut, aber das worauf es mir ankam waren die letzten Zeilen, wo der Text gesetzt wird.
Die ProgressBars laufen eben auch einwandfrei, nur die Texte nicht:
Außerdem hatte ich das Beispiel gepostet, wo es es bei mir funktioniert, weil es das mit QProgressDialog war.
Hier das eigentliche Problem (Sorry):

Code: Alles auswählen

 /*Mit diesem QProgressDIalog gehts*/
//prog_dialog=new QProgressDialog(this,"progress",TRUE);
        prog_dialog=new QDialog(this,"myDialog",TRUE);
        prog_dialog->setGeometry(200,200,300,200);
        prog_layout=new QVBoxLayout(prog_dialog);
        titel = new QLabel(prog_dialog);
        sequenz_titel=new QLabel(prog_dialog);
        titel->setText("Fortschrittsanzeige:");
        prog_layout->addWidget(titel);
        prog_layout->addWidget(sequenz_titel);
        sequenz_titel->setText("Gesamtfortschritt:");
        int size=filenames.size();
        bar1=new QProgressBar(3*size+1,prog_dialog);
        prog_layout->addWidget(bar1);
        sequenz_index=0;
        schritt_titel=new QLabel(prog_dialog);
        prog_layout->addWidget(schritt_titel);
        schritt_titel->setText("Aktuelle Sequenz:");
        bar2=new QProgressBar(prog_dialog);
        prog_layout->addWidget(bar2);
        prog_layout->activate();
        prog_dialog->show();
        for ( QStringList::Iterator it = filenames.begin(); it != filenames.end(); ++it ) {
                        D2JPEG(*it,i,1);
                }
        bar1->setProgress(3*size+1);


               
und hier der relevante Teil der Methode DJPEG, die aufgerufen wird:

Code: Alles auswählen


.........
int p=0;
QString s2="Name Sequenz";
QString text="Aktuelle Sequenz: "+s_2;
DicomImage *image = new DicomImage(eingabe_datei);
int x = image->getFrameCount();
bar2->setTotalSteps(2*x+anzahl-1);
//Dieser Text erscheint nicht, es steht immer noch der alte Wert im LAbel
schritt_titel->setText(text);
HImageArray sequenz;
sequenz_index++;
for (int a=0; a<=x-1; a++) {
                bar2->setProgress(p);
                bar1->setProgress(sequenz_index);
                QString text2=text+"\nFrames werden extrahiert";
                //Dieser Text erscheint auch nicht, sondern immer der alte
                schritt_titel->setText(text2);
}
.................


Ich gehe in dieser Methode noch durch 3 For-Schleifen, in denen die Prgressbars weiterlaufen und jeweils ein neuer Text angezeigt werden soll.

Ich hoffe, das war jetzt alles ein bisschen verständlicher....


Danke,
viele Grüße,
Dani

Verfasst: 20. Mai 2005 10:58
von FlorianBecker
Ja, ziemlich klar, hier wird solange gearbeitet, bis es abgelaufen ist:

Code: Alles auswählen

for ( QStringList::Iterator it = filenames.begin(); it != filenames.end(); ++it ) {
                        D2JPEG(*it,i,1);
}
Und warum er den Text nicht setzt, weil du nicht wartest bis die ProgressBars fertig sind. Du kannst das umgehen wenn du folgendes machst:

Code: Alles auswählen

for (int a=0; a<=x-1; a++) {
                bar2->setProgress(p);
                bar1->setProgress(sequenz_index);
                QString text2=text+"\nFrames werden extrahiert";
                //Dieser Text erscheint auch nicht, sondern immer der alte
                schritt_titel->setText(text2);
-->            qApp -> processEvents();
} 

Verfasst: 20. Mai 2005 11:10
von dani.80
Super! Vielen vielen Dank, für die schnelle Hilfestellung.
Also muss man, wenn ein Prozess länger läuft und man zwischendurch die GUI trotzdem aktualisieren möchte immer ein
qApp -> processEvents();
setzen?

Dann war die Lösung ja doch ganz einfach.

Funktioniert bestens!

Verfasst: 20. Mai 2005 11:22
von FlorianBecker
Das processEvents ist dafür, dass die GUI flexibel bleibt und ausstehende Abläufe weiterlaufen und wirklich ausgeführt werden, bis der nächste Ablauf kommt. Das processEvents ist eigentlich eine Funktion um Thread Programmierung zu umgehen, allerdings stößt man auf Grenzen, in deinem Beispiel z.B. wenn du einen Abbruch Knopf hättest, der den dialog abbricht, wäre dieser nicht drückbar, bzw. nur mich sehr sehr langer Verzögerung und meistens ist bis dahin der Dialog bereits abgelaufen. Da helfen nur noch Threads, damit die Anwendung benutzbar bleibt, während der Main/Neben Process läuft.