GUI friert ein

Alles rund um die Programmierung mit Qt
Antworten
reinki0013
Beiträge: 174
Registriert: 11. November 2008 09:37
Wohnort: AUT

GUI friert ein

Beitrag von reinki0013 »

hallo zusammen,

ich habe ein programm, welches dateien an einen ftp-server sendet.
in diesem zuge habe ich auch einen fortschrittsbalken gemacht. ich habe jetzt allerdings das problem, z.b. mit windows 7 friert mir die GUI ein sobald ich außerhalb des Programms wo hinklicke. Bei einem weiteren klick kommt sofort die meldung (keine Rückmeldung) und der Inhalt meiner GUI wird weiß...

hat da jemand schon erfahrungen in diese richtung gemacht bzw. kann mir da jemand weiterhelfen?

lg
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: GUI friert ein

Beitrag von franzf »

Wenn du uns zeigst, wie du es machst (Code!) können wir dir vielleicht sagen, was du ändern kannst, damit es funktioniert.
Da ich nicht weiß, unter welchen Umständen Windows diese Meldung raushaut, kann ich nur in Richtung "du hängst in einer blockierende Funktion" mutmaßen.
reinki0013
Beiträge: 174
Registriert: 11. November 2008 09:37
Wohnort: AUT

Re: GUI friert ein

Beitrag von reinki0013 »

hi,

also ich habe einen QTcpSocket und einen QTextStream.
in einer while-schleife schicke ich die daten von meinem QTextStream an meinen QTcpSocket bis nichts mehr im QTextStream drinnen steht.
Währenddessen friert mir dann die GUI ein, wenn ich während dieser Schleife etwas anderes mache bzw. wo anders hinklicke...

hiflt dir das schon weiter?
sonst hier der code von der funktion

Code: Alles auswählen

bool eModem::Send(QString Name, QByteArray data)
{                            
  out << "re\r";
  out.flush();

  sock.waitForReadyRead(3000);    // max. 3 Sekunden warten
  QString empfang;
  while(!in.atEnd())
  {
    in >> empfang;

    if(empfang == "start")
    {
      quint32 len = data.size();
      qint64 maxlen = len;
      qint64 pos = 0;

      out << Name << '\0' << len << '\0';
      out.flush();

      while(len)
      {
        sock.waitForReadyRead(10000);
        in >> empfang;

        if(empfang.size() == 0)
          return false;

        if(empfang == "fin")
          pos = maxlen;
        else
          pos = empfang.toInt();

        emit Progress(pos, maxlen);

        len = data.size();
        if(len > 512)
          len = 512;
        QByteArray buf;
        buf.append(data.constData(), len);
        data.remove(0, len);

        sock.write(buf);
        //out << buf;   // out funktioniert nicht wegen TextStream
        //out.flush();
        sock.flush();
        sock.waitForBytesWritten(3000);
      }

      return true;
    }
  }

  return false;
}

lg
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: GUI friert ein

Beitrag von franzf »

QIODevice::waitForReadyRead() ist blockierend, deine Gui reagiert nicht. Es steht auch noch ganz klar dabei:
It is useful when writing non-GUI applications and when performing I/O operations in a non-GUI thread.
Also: entweder lagerst du das ganze in nen eigenen Thread aus, oder du nimmst gleich die asynchrone API (also über SIGNAL/SLOT), letzteres wäre die zu bevorzugende Methode.
Du hast auch ganz schön lange Timeouts gesetzt, in jedem Durchlauf der inneren Schleife blockierst du zusammen 13 Sekunden.
GottfriedSp
Beiträge: 4
Registriert: 18. Oktober 2010 12:57

Re: GUI friert ein

Beitrag von GottfriedSp »

In der Schleife ist ein

Code: Alles auswählen

emit Progress(pos, maxlen);
Welcher das Signal zum Slot in das Hauptfenster leitet und damit der Fortschrits-Balken aktualisiert wird (ca. 500ms pro Aktualisierung).
Das Programm funktioniert im Debug-Modus perfekt, allerdings das Release funktioniert nicht.
Bei Windows XP funktioniert sogar das Release noch so einigermassen.

Mit Thread hatten wir es auch schon versucht, welcher bei Windows 7 mit dem Debug-Binaries perfekt funktioniert, allerdings bei Release wird der QMutex irgend wie nicht beachtet oder durchgeführt. (statische QMutex).

Wir haben die 4.7.4 und 4.7.1
reinki0013
Beiträge: 174
Registriert: 11. November 2008 09:37
Wohnort: AUT

Re: GUI friert ein

Beitrag von reinki0013 »

Kann uns beiden wer einen Tipp geben?
reinki0013
Beiträge: 174
Registriert: 11. November 2008 09:37
Wohnort: AUT

Re: GUI friert ein

Beitrag von reinki0013 »

also ich habs jetzt mal probiert mit QThread - aber da bin ich überfordert...

ich habe jetzt folgendermaßen probiert:

Code: Alles auswählen

bool eModem::Send(QString Name, QByteArray data)
{   

  QThread *thread = new QThread; 
  this->moveToThread(thread);
  thread->start();

  out << "re\r";
  out.flush();

  sock.waitForReadyRead(3000);    // max. 3 Sekunden warten
  QString empfang;
  while(!in.atEnd())
  {
    in >> empfang;

    if(empfang == "start")
    {
      quint32 len = data.size();
      qint64 maxlen = len;
      qint64 pos = 0;

      out << Name << '\0' << len << '\0';
      out.flush();

      while(len)
      {
        sock.waitForReadyRead(10000);
        in >> empfang;

        if(empfang.size() == 0)
          return false;

        if(empfang == "fin")
          pos = maxlen;
        else
          pos = empfang.toInt();

        emit Progress(pos, maxlen);

        len = data.size();
        if(len > 512)
          len = 512;
        QByteArray buf;
        buf.append(data.constData(), len);
        data.remove(0, len);

        sock.write(buf);
        //out << buf;   // out funktioniert nicht wegen TextStream
        //out.flush();
        sock.flush();
        sock.waitForBytesWritten(3000);
      }
      return true;
    }
  }
  return false;
}
das funktioniert aber leider auch nicht - die GUI friert trotzdem ein beim Release...

lg
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: GUI friert ein

Beitrag von brax »

Du startest zwar jetzt tatsächlich einen Thread, der hat aber nichts mit dem zu tun, was Deine eModem Klasse macht. Du müsstest Deine gesamte eModem Klasse in eine von QThread abgeleitete Klasse überführen.

Aber das ist eigentlich auch gar nicht notwendig. Wie franzf gesagt hat, bietet QTcpSocket ja schon alles, was Du für asynchrone Kommunikation brauchst (über QIODevice). Du musst in eModem auf das readyRead() Signal des Sockets reagieren und erst dann aus dem Socket lesen, wenn es ankommt. Ein Mögliches Timeout solltest Du dann allerdings selbst implementieren über einen QTimer, den Du jedesmal beim Empfangen von Daten killst und nach dem Senden neuer Daten anwirfst. Wenn der Timer irgendwann feuert, kappst Du die Verbindung, damit der Server auch bescheid weiß.
GottfriedSp
Beiträge: 4
Registriert: 18. Oktober 2010 12:57

Re: GUI friert ein

Beitrag von GottfriedSp »

Das mit readyRead() funktioniert einwandfrei!
Auf die Einfachsten Dinge kommt man immer zuletzt :)
Antworten