2

Ich möchte einen Fortschrittsbalken erstellen, der den Status einer Datei lesen zeigt. Ich lese die Datei mit einem C++ - Klassenleser, der eine Variable _progress enthält.Datei lesen mit Fortschrittsbalken in Cocoa

Wie kann ich Cocoa sagen, die Fortschrittsleiste mit dem Wert von reader._progress zu aktualisieren, ohne einen ObjC-Code in der Reader-Klasse zu schreiben?

Jede Hilfe würde geschätzt.

ProgressController *pc = [[ProgressController alloc] init]; 
[pc showWindow:sender]; 


// Create the block that we wish to run on a different thread 
void (^progressBlock)(void); 
progressBlock = ^{ 
    [pc.pi setDoubleValue:0.0]; 
    [pc.pi startAnimation:sender]; 

    Reader reader("/path/to/myfile.txt"); 
    reader.read(); 

    while (reader._progress < 100.) 
    { 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [pc.pi setDoubleValue:reader._progress]; 
      [pc.pi setNeedsDisplay:YES]; 
     }); 
    } 
}; // end of progressBlock 

// Finally, run the block on a different thread 
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 
dispatch_async(queue, progressBlock); 

So, hier ist mein zweiter Versuch.

Der Leser Code:

class PDBReader 
{ 
public: 
Reader(const char *filename); 
Reader(string filename); 
~Reader(); 

int read(); 

string _filename; 
float _progress; 

void setCallback(void (^cb)(double)) 
{ 
    if (_cb) 
    { 
     Block_release(_cb); 
     _cb = Block_copy(cb); 
    } 
} 
void (^_cb)(double); 

protected: 
private: 
}; 



int Reader::read() 
{ 
string buffer; 
unsigned atomid = 0; 
ifstream file; 
file.open(_filename.c_str(), ifstream::in); 

if (!file.is_open()) 
{ 
    return IOERROR; 
} 

file.seekg(0, ios_base::end); 
float eof = (float) file.tellg(); 
file.seekg(0, ios_base::beg); 

while (getline(file, buffer)) 
{ 
    _progress = (float) file.tellg()/eof * 100.; 
    if (_cb) 
    { 
     _cb(_progress); 
    } 
     // some more parsing here... 
    } 
file.close(); 
return SUCCESS; 
} 

PDBReader::~PDBReader() 
{ 
if (_cb) 
{ 
    Block_release(_cb); 
} 
} 

Und der Cocoa Teil:

-(IBAction) test:(id) sender 
{ 
ProgressController *pc = [[ProgressController alloc] init]; 
[pc showWindow:sender]; 

Reader reader("test.txt"); 

reader.setCallback(^(double progress) 
{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [pc.pi setDoubleValue:progress]; 
     [pc.pi setNeedsDisplay:YES]; 
    }); 
}); 

reader.read(); 
} 

Vielen Dank für Ihre Hilfe.

+0

Welche Probleme sehen Sie, wenn Sie den von Ihnen geposteten Code verwenden? –

+0

das Hauptproblem ist, dass es nicht funktioniert! überhaupt meine ich! Grundsätzlich scheint es in einer Endlosschleife zu sein. – blaurent

Antwort

0

Endlich !!!!!

Es funktioniert gut, wenn es nicht in eine Warteschlange gestellt wird.

Aber warum sagst du "Das ist schlecht, weil es den Hauptfaden blockiert"? Weil im Grunde mein Programm warten muss, bevor die Datei gelesen wird. Gibt es einige grundlegende Optimierung, die ich hier vermisse?

Vielen Dank für Ihre Hilfe.

+0

Warum hast du deine eigene Antwort geschrieben und akzeptierst sie statt meiner? –

7

Nur weil Sie nicht wollen, dass Reader Objective-C-Code enthält, bedeutet das nicht, dass Sie es nur von außen beobachten können. Es kann eine C-Funktion über einen übergebenen Funktionszeiger aufrufen. Es kann einen allgemeineren Funktor (Funktionsobjekt) -Mechanismus verwenden. Es kann sogar blockieren.

Sie wollen definitiv nicht, dass while (reader._progress < 100.) Schleife zu tun. Das ist eine geschäftige Schleife. Es dreht sich darum, den Fortschritt so schnell wie möglich zu aktualisieren. Es wird einen CPU-Kern mit 100% Auslastung binden. In der Tat werden Aufgaben wahrscheinlich schneller in die Haupt-Dispatch-Warteschlange eingereiht, als sie ausgeführt werden können.

Sie möchten nur die Fortschrittsanzeige aktualisieren, wenn der Reader sein _progress Mitglied aktualisiert hat, was eine Art Zusammenarbeit der Reader-Klasse erfordert.

+0

Vielen Dank für Ihre Antwort. Ich kam zu diesem Schluss, aber ich weiß nicht, wie ich das machen soll. Haben Sie einen Beispielcode zum Vorschlagen? – blaurent

+0

Zum Beispiel, erstellen Sie eine 'setCallback (void (^ cb) (double))' Member-Funktion in der 'Reader' Klasse. Erstellen Sie auch eine 'void (^ _cb) (double)' Membervariable. Der Setzer würde 'if (_cb) Block_release (_cb); _cb = Block_copy (cb); '. Immer wenn 'Reader' '_progress' aktualisiert, sollte es auch' if (_cb) _cb (_progress); '. Der Destruktor sollte auch 'if (_cb) Block_release (_cb);'. –

+0

Danke, ich werde es versuchen und Sie wissen lassen. – blaurent