BCB 6 und ProgressBars unter Vista



  • Ich habe in meinem Programm eine ProgressBar, die beim Transfer einer Datei den Fortschritt anzeigt. Aktualisiere ich unter Vista die ProgressBar oft (also alle ca. 32768 bytes) so flimmert sie nur noch zeigt aber die Position pixelgenau an. Die von links nach rechts laufende Animation wird dann überhaupt nicht "abgespielt". Ändere ich die Position des Fortschrittsbalkens nur alle paar Pixel so wird zwar die Animation abgespielt es flickert aber trotzdem ab und zu...

    Hat jemand irgend ne Ahnung warum das flickert?

    Eine Vermutung von mir wäre, dass ich den Dateitransfer auf nen anderen Thread legen muss und nicht das GUI mit Application-ProcessMessages() aktualisieren darf. Alledings wäre diese Änderung sehr kompliziert 😮



  • Weist du wie das geht, also den Transfer in einen anderen Thread verschieben? Weil meiner Meinung nach ist das am "Saubersten". Ich stehe vor einem ähnlichen Problem. Bei mir sind die Rechner beide voll ausgelastet während dem Transfer.

    Wäre echt nett wenn du mir nenn Tip geben könntest wie ich den Transfer in einen eigenen Thread verlagere.



  • Du musst aus nem Thread (dafür gibt ne Komponente) deine Transfer-Funktion aufrufen...

    Da die VCL aber nicht Thread-save ist musst du dann alle VCL aufrufe (d.h. GUI-Veränderungen) durch Syncronize machen. Das geht erstens langsamer, da er auf den Hauptthread warten muss und zweitens ist es ein enormer Aufwand.

    Ich würde aber davon abraten Threads für solche sachen zu benutzen, weil trotz der anfänglichen Eleganz Threads durch das Syncronisieren viel komplizierter sind als select und co.
    Z.B. Lese ich die Daten in meinem Programm per select non-blocking und schreibe die Dateien über die OVERLAPPED-IO API von Windows, damit habe ich relativ wenig Probleme. Und bevor ich das alles (was funktioniert) wegen so dummen geflacker umprogrammiere Implementiere ich lieber meine eigene ProgressBar!



  • ?? Kann ich nicht nachvollziehen.

    Das Problem dürfte das massiv übertriebene Updaten der ProgressBar sein. Diese sollte 10 bis __maximal__ 100 Mal aktualiesiert werden. Aber ganz bestimmt nicht 32000 mal...

    Du kannst noch versuchen DoúbleBuffered des Forms auf true zu setzen, aber dennoch solltest Du die Updates auf die ProgressBar drastisch reduzieren.

    Und natürlich kann es Sinn machen, das Ganze in einen Thread auszulagern, schon alleine, weil der Hauptthread dann losgelöst von der Arbeit ist. Allerdings, wenn Du aus dem Thread heraus die GOI 32000 mal aktualisierst, hat Tobias recht, das ist Unsinn. Aus Threads heraus, sollte nur ein Minimum an GUI-Aktivität ausgeführt werden. Ich würde in diesem Fall auch gar nicht direkt das GUI aus dem Thread heraus aktulisieren, sondern mit PostMessage eine Nachricht senden, die die Aktualisierung des GUI aufruft. Aber auch das auf gar keinen Fall 32000 Mal...



  • Ich hab im ersten Post geschrieben, dass ich die Position des Fortschrittsbalkens nur alle paar Pixel ändere und es trotzdem flackert...

    DoubleBuffered bringt auch nichts...

    Ich hab mal ne Versuchsreihe gestartet:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
            for(int i=0;i<100;++i)
            {
                    Sleep(100);
                    ProgressBar1->Position+=1;
                    Application->ProcessMessages();
            }
    }
    

    flackert und ist ruckelig in Vista

    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
            for(int i=0;i<100;++i)
            {
                    int tt=GetTickCount();
                    while(GetTickCount()-tt<100 )
                            Application->ProcessMessages();
                    ProgressBar1->Position+=1;
            }
    }
    

    flackert stärker, ruckelt aber nicht mehr... braucht aber 100% CPU (bzw. 50% bei DualCore 😉 )

    void __fastcall TForm1::Button4Click(TObject *Sender)
    {
            Timer1->Enabled=true;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
            ProgressBar1->Position+=1;        
    }
    

    Flackert auch 😮 Dann kann ich das mit dem extra Thread wohl vergessen...

    Das es an der GraKa oder so liegt kann ich eigentlich ausschließen, weil alle anderen ProgessBars in anderen Programmen solche Symptome nicht zeigen...



  • So... hab den Bug gefunden... Hier ist er beschrieben: http://qc.borland.com/wc/qcmain.aspx?d=38178

    Zum beheben des flackerns also einfach in die .h-Datei:

    private:	// Anwender-Deklarationen
            Classes::TWndMethod ProgressBar1WndProc;
    public:		// Anwender-Deklarationen
            __fastcall TForm1(TComponent* Owner);
            void __fastcall ProgressBar1NewWndProc(Messages::TMessage& msg);
    

    Und in die Cpp-Datei:

    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
            ProgressBar1WndProc=ProgressBar1->WindowProc;
            ProgressBar1->WindowProc=Form1->ProgressBar1NewWndProc;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ProgressBar1NewWndProc(Messages::TMessage& msg)
    {
            switch(msg.Msg)
            {
            case WM_ERASEBKGND:
                    DefaultHandler(&msg);
                    return;
            }
            ProgressBar1WndProc(msg);
    }
    

    War wohl doch nicht mein Fehler 😉


Log in to reply