alle 1000 ms eine Zeile in eine Textdatei schreiben
-
Luftballon
- Beiträge: 29
- Registriert: 10. Mai 2009 20:03
alle 1000 ms eine Zeile in eine Textdatei schreiben
Hallo zusammen!
Ich bin Anfänger in Sachen C++/Qt-Programmierung, finde dies jedoch sehr spannend und versuche es an einem kleineren Programm zu erlernen.
Dieses Programm soll ersteinmal alle 1000 ms einen Datensatz (die Sekundenangabe der aktuellen Zeit) in eine Textdatei schreiben. Dabei soll jeder Datensatz eine Zeile in der Textdatei einnehmen. Anbei als Attachment meine ersten Gehversuche.
Drei Punkte funktionieren aktuell nicht:
1.
Das Einfügen von der Sekundenangabe in die Textdatei ( void Thread::threadAction() )
2.
Der repetitive Aufruf und/oder das repetitive Schreiben in die Textdatei ( void Thread::threadAction() )
3.
Das Anhalten des Threads (void Thread::threadStop() )
Was muss ich ändern, damit diese drei Punkte funktionieren? Über eure Hilfe würde ich mich sehr freuen!
Beste Grüße,
der Luftballon
Ich bin Anfänger in Sachen C++/Qt-Programmierung, finde dies jedoch sehr spannend und versuche es an einem kleineren Programm zu erlernen.
Dieses Programm soll ersteinmal alle 1000 ms einen Datensatz (die Sekundenangabe der aktuellen Zeit) in eine Textdatei schreiben. Dabei soll jeder Datensatz eine Zeile in der Textdatei einnehmen. Anbei als Attachment meine ersten Gehversuche.
Drei Punkte funktionieren aktuell nicht:
1.
Das Einfügen von der Sekundenangabe in die Textdatei ( void Thread::threadAction() )
2.
Der repetitive Aufruf und/oder das repetitive Schreiben in die Textdatei ( void Thread::threadAction() )
3.
Das Anhalten des Threads (void Thread::threadStop() )
Was muss ich ändern, damit diese drei Punkte funktionieren? Über eure Hilfe würde ich mich sehr freuen!
Beste Grüße,
der Luftballon
- Dateianhänge
-
- Mousometer.cpp
- (1.59 KiB) 183-mal heruntergeladen
-
- Thread.cpp
- (592 Bytes) 189-mal heruntergeladen
Das sagt uns leider wenig... versuche, so genaue Fehlerbeschreibungen wie möglich zu geben, wie z.B.Drei Punkte funktionieren aktuell nicht:
"Die Datei "test.txt" wird erstellt, aber leider wird dort immer nur eine einzelne Zeile reingeschrieben".
Dann könnten wir die Antwort schreiben: "Du öffnest die Datei ja auch beim jeden Durchgang neu, daher wird immer der alte Inhalt überschrieben. Entweder du öffnest die Datei nur einmal (beim Threadstart) und hast im Slot nur noch "file.write(...)" oder du öffnest die Datei so, dass die Daten angehängt werden (siehe Flags http://doc.trolltech.com/4.5/qiodevice. ... eFlag-enum).
Oder du hättest schreiben können:
"Die Datei wird nicht erstellt".
Dann würden wir schreiben: "Zeig mal die Headerdatei, vermutlich funktioniert der Slot wegen fehlendem "Q_OBJECT" nicht, aber das müsstest du anhand der Konsolenausgabe oder durch die Kontrolle des Returnwertes von connect(...) auch selbst rausgefunden haben..."
Zum Thema Thread:
* Warum überhaupt ein Thread? Der Timer könnte doch in jeder normalen QObject-Klasse laufen..
* "quit()" muss vermutlich aus dem Thread aufgerufen werden. Du musst dem Thread also mitteilen, er solle sich beenden. Wie, bleibt (vorerst) deiner Fantasie überlassen...
Hth...
[EDIT]
zu "seconds() funktioniert nicht": übe den Umgang mit QStrings... (lies die Doku, http://doc.trolltech.com/4.5/qstring.html#arg-10).. dann klappt das.
-
Troll.Soft
- Beiträge: 190
- Registriert: 18. Juni 2008 09:52
- Wohnort: Hamburg
QTimer
Hallo,
möglicherweise suchst Du QTimer. Diese Klasse hat alles was Du brauchst und ein Beispiel gibt es auch.
tschüß
der Trollsoft
möglicherweise suchst Du QTimer. Diese Klasse hat alles was Du brauchst und ein Beispiel gibt es auch.
Code: Alles auswählen
Example for a one second (1000 millisecond) timer (from the Analog Clock example):
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
From then on, the update() slot is called every second.
der Trollsoft
-
Luftballon
- Beiträge: 29
- Registriert: 10. Mai 2009 20:03
Vielen Dank für eure Antworten!
Die Datei "test.txt" wir jetzt nicht mehr bei jedem Durchgang neu geöffnet und somit klappt nun auch das Schreiben mehrerer Zeilen in diese Datei.
Das Schreiben der Sekundenangabe funktioniert allerdings nicht. Hier habe ich jetzt
ausprobiert, aber das produziert folgende Fehlermeldung:
=============
MouseOMat/Thread.cpp:17: error: no matching function for call to `QFile::write(QString)'
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:123: note: candidates are: qint64 QIODevice::write(const char*, qint64)
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:124: note: qint64 QIODevice::write(const char*)
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:126: note: qint64 QIODevice::write(const QByteArray&)
=============[/code]
Einen Thread wollte ich verwenden, damit später zu diesem repetitiven Schreiben in die Textdatei noch etwas anderes parallel ausgeführt werden kann. Dieses "etwas anderes" ist das Auslesen einer USB-Gerätes, dass in unregelmäßigen Abständen wohl eine 1 senden wird. Die Einsen sollen dann gezählt und deren Anzahl pro Zeitintervall in die Textdatei geschrieben werden.
Das "quit()" habe ich jetzt an eine andere Stelle gesetzt (void Mousometer::stopMouse()).
Wenn ich das Programm starte, dann bekomme ich folgende Meldungen in der Konsole
Die 2. und 4. Zeile gibt mir das Gefühl, als würde das noch nicht 100%ig richtig sein. allerdings habe ich aktuell keine Idee was ich verändern könnte.
Über weitere Hilfe freue ich mich sehr.
Beste Grüße,
der Luftballon
Die Datei "test.txt" wir jetzt nicht mehr bei jedem Durchgang neu geöffnet und somit klappt nun auch das Schreiben mehrerer Zeilen in diese Datei.
Das Schreiben der Sekundenangabe funktioniert allerdings nicht. Hier habe ich jetzt
Code: Alles auswählen
void Thread::timerAction() {
QTime t = QTime::currentTime();
QFile file("test.txt");
file.open(QIODevice::Append | QIODevice::Text);
file.write( file.write( QString("Sekunde = %1\n").arg(t.second() )) );
file.close();
}=============
MouseOMat/Thread.cpp:17: error: no matching function for call to `QFile::write(QString)'
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:123: note: candidates are: qint64 QIODevice::write(const char*, qint64)
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:124: note: qint64 QIODevice::write(const char*)
MouseOMat/../../../../Qt/2009.02/qt/include/QtCore/../../src/corelib/io/qiodevice.h:126: note: qint64 QIODevice::write(const QByteArray&)
=============[/code]
Einen Thread wollte ich verwenden, damit später zu diesem repetitiven Schreiben in die Textdatei noch etwas anderes parallel ausgeführt werden kann. Dieses "etwas anderes" ist das Auslesen einer USB-Gerätes, dass in unregelmäßigen Abständen wohl eine 1 senden wird. Die Einsen sollen dann gezählt und deren Anzahl pro Zeitintervall in die Textdatei geschrieben werden.
Das "quit()" habe ich jetzt an eine andere Stelle gesetzt (void Mousometer::stopMouse()).
Wenn ich das Programm starte, dann bekomme ich folgende Meldungen in der Konsole
Code: Alles auswählen
Starting MouseOMat/debug/MouseOMat.exe...
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Thread(0x5217670), parent's thread is QThread(0x3e4728), current thread is Thread(0x5217670)
QObject::killTimer: timers cannot be stopped from another threadÜber weitere Hilfe freue ich mich sehr.
Beste Grüße,
der Luftballon
- Dateianhänge
-
- Mousometer.cpp
- (1.61 KiB) 172-mal heruntergeladen
-
- Thread.cpp
- (661 Bytes) 177-mal heruntergeladen
-
- Thread.h
- (351 Bytes) 165-mal heruntergeladen
Schau dir an, welche write() Varianten du hast.. und danach http://doc.trolltech.com/4.5/qstring.html#toAsciino matching function for call to `QFile::write(QString)'
Zu "quit()".. das ist ja ein Slot des Threads. Du soltlest IMHO darauf achten, dass dieser Slot auch wirklich aus dem Kontext des Threads aufgerufen wird. Eine Variante waere daher eine Signal/Slot-"QueuedConnection" (Die Applikation "bittet" mit einem Signal den Thread, sich zu beenden. Der Thread fuehrt den Slot "quit" dann in _seinem_ Eventloop aus.). Keine Ahnung ob das ueberhaupt funktioniert, "quit" aus einem anderen Thread (wie du das tust) aufzurufen. Falls das ueberhaupt funktioniert, muesste das unbedingt noch mittels Mutex synchronisiert werden.
Threads sind nicht einfach, wie pfid schon hingewiesen hat
-
Luftballon
- Beiträge: 29
- Registriert: 10. Mai 2009 20:03
Mit der Zeile
funktioniert es.
Das mit dem QThread ist wirklich nicht einfach. Ich werde mir deine letzte Antwort zu diesem Thema später genauer anschauen. Was ich hier ja eigentlich möchte ist, dass
1. nach Betätigung eines QPushButton ein neuer Thread entsteht und gestartet wird und
2. nach Betätigung eines weiteren QPushButton dieser Thread wieder beendet wird
Zu sowas müsst es doch eigentlich Beispiele im Netz geben, oder versuche ich QThread so zu benutzen, wie es eigentlich nicht gedacht ist?
Code: Alles auswählen
file.write( QString("Sekunde = %1\n").arg(t.second()).toUtf8() );Das mit dem QThread ist wirklich nicht einfach. Ich werde mir deine letzte Antwort zu diesem Thema später genauer anschauen. Was ich hier ja eigentlich möchte ist, dass
1. nach Betätigung eines QPushButton ein neuer Thread entsteht und gestartet wird und
2. nach Betätigung eines weiteren QPushButton dieser Thread wieder beendet wird
Zu sowas müsst es doch eigentlich Beispiele im Netz geben, oder versuche ich QThread so zu benutzen, wie es eigentlich nicht gedacht ist?
kein Problem, Beendet wird doch einfach mit:1. nach Betätigung eines QPushButton ein neuer Thread entsteht und gestartet wird und
2. nach Betätigung eines weiteren QPushButton dieser Thread wieder beendet wird
* Signal "clicked()" des "Beenden-Buttons" mit Slot "quit" des Threads
* Signal "finished()" des Treads mit einem eigenen Slot der GUI, in welchem du die Instanz loescht (thread->deleteLater()); thread = NULL);
-
Luftballon
- Beiträge: 29
- Registriert: 10. Mai 2009 20:03
Jetzt funktioniert es schonmal seh gut. Ich kann mit dem Button "Programm starten..." den Thread und dessen Timer starten und mit dem Button "Programm beenden..." selbige wieder beenden bzw. stoppen.
Allerdings bekomme ich in der Debug-Konsole dabei folgende Meldungen:
1. beim Starten -> "QObject: Cannot create children for a parent that is in a different thread. (Parent is Thread(0x22fde4), parent's thread is QThread(0x3e4748), current thread is Thread(0x22fde4)"
2. beim Beenden -> "QObject::killTimer: timers cannot be stopped from another thread"
Warum ist das so und wie kann ich das verbessern?
Dann habe ich noch in der Klasse die Methode "closeEvent(QCloseEvent *event)" reimplementiert (so heißt das glaube ich). Damit wollte ich eigentlich verhindern, dass das Programm geschlossen wird, wenn der Thread noch läuft. Jedoch wird diese Methode nicht aufgerufen, wenn ich das Programm schließe. Was läuft hier falsch?
Würde mich über eure Hilfe sehr freuen!
Beste Grüße,
der Luftballon
Mousometer.cpp:
Thread.cpp
Allerdings bekomme ich in der Debug-Konsole dabei folgende Meldungen:
1. beim Starten -> "QObject: Cannot create children for a parent that is in a different thread. (Parent is Thread(0x22fde4), parent's thread is QThread(0x3e4748), current thread is Thread(0x22fde4)"
2. beim Beenden -> "QObject::killTimer: timers cannot be stopped from another thread"
Warum ist das so und wie kann ich das verbessern?
Dann habe ich noch in der Klasse die Methode "closeEvent(QCloseEvent *event)" reimplementiert (so heißt das glaube ich). Damit wollte ich eigentlich verhindern, dass das Programm geschlossen wird, wenn der Thread noch läuft. Jedoch wird diese Methode nicht aufgerufen, wenn ich das Programm schließe. Was läuft hier falsch?
Würde mich über eure Hilfe sehr freuen!
Beste Grüße,
der Luftballon
Mousometer.cpp:
Code: Alles auswählen
#include "Mousometer.h"
Mousometer::Mousometer(QWidget *parent) : QMainWindow(parent) {
w = new QWidget;
layout = new QGridLayout(w);
spin = new QSpinBox;
slider = new QSlider(Qt::Horizontal);
label = new QLabel("Anzahl der Durchläufe");
button1 = new QPushButton("Programm starten...");
button2 = new QPushButton("Programm stoppen...");
edit = new QTextEdit;
edit->setFixedWidth(500);
edit->setFixedHeight(300);
spin->setMinimum(1);
spin->setMaximum(100);
slider->setMinimum(1);
slider->setMaximum(100);
layout->addWidget(label, 0, 0);
layout->addWidget(slider, 0, 1);
layout->addWidget(spin, 0, 2);
layout->addWidget(button1, 1, 1);
layout->addWidget(button2, 2, 1);
layout->addWidget(edit, 3, 0, 1, 3);
QObject::connect( spin, SIGNAL( valueChanged(int) ), slider, SLOT( setValue(int) ) );
QObject::connect( slider, SIGNAL( valueChanged(int) ), spin, SLOT( setValue(int) ) );
QObject::connect( button1, SIGNAL( clicked() ), this, SLOT( letMouseRun() ) );
QObject::connect( button2, SIGNAL( clicked() ), this, SLOT( stopMouse() ) );
QObject::connect( &thread, SIGNAL( finished() ), this, SLOT( threadReady() ) );
QMenu *fileMenu = new QMenu(tr("&Datei"), this);
menuBar()->addMenu(fileMenu);
fileMenu->addAction(
QIcon("./images/cancel.png"),
tr("Beenden..."), qApp, SLOT(quit()),
QKeySequence(tr("Ctrl+X", "Datei|Beenden")));
resize(320, 200);
setCentralWidget(w);
setWindowTitle("Mousometer");
}
Mousometer::~Mousometer() {}
void Mousometer::letMouseRun() {
if( thread.isRunning() ) {
edit->moveCursor(QTextCursor::End) ;
edit->insertPlainText(tr("QThread laeuft bereits\n"));
return;
}
slider->setValue(55);
thread.start();
edit->moveCursor(QTextCursor::End) ;
edit->insertPlainText(tr("QThread gestartet\n"));
}
void Mousometer::stopMouse() {
slider->setValue(66);
thread.timerStop();
}
void Mousometer::threadReady() {
edit->moveCursor(QTextCursor::End) ;
edit->insertPlainText(tr("QThread ist fertig\n"));
}
void Mousometer::closeEvent(QCloseEvent *event) {
qDebug() << "xxxxxxxxxxxxxxxx";
if( thread.isRunning() ) {
edit->moveCursor(QTextCursor::End) ;
edit->insertPlainText(tr("QThread laeuft noch\n"));
return;
}
//thread.wait();
}
Code: Alles auswählen
#include "Thread.h"
#include <QtGui>
Thread::Thread() {}
void Thread::run() {
timer = new QTimer(this);
QObject::connect( timer, SIGNAL(timeout()), this, SLOT(timerAction()) );
timer->start(500); // alle 500 ms ein Methodenaufruf
exec();
}
void Thread::timerAction() {
qDebug() << "i am alive!";
QTime t = QTime::currentTime();
QFile file("test.txt");
file.open(QIODevice::Append | QIODevice::Text);
file.write( QString("Sekunde = %1\n").arg(t.second()).toUtf8() );
file.close();
}
void Thread::timerStop() {
timer->stop();
quit();
}
Es mach überhaupt keinen Sinn, da einen Pointer zu nehmen. Besonders, weil du ja eh nur den Thread beenden möchtest und daher gar kein stop() notwendig wäre:
fertig.. die erste Meldung erhälst du, weil "this" genaugenommen vom Mainthread erstellt wird und auch diesem gehört...
Die zweite, weil du versuchst, den Thread aus dem Kontext eines anderen zu steuern ("timerStop()" wird vom Mainthread her aufgerufen und wird daher auch im Mainthread ausgeführt, _nicht_ im nebenläufigen Thread!).
Ich kann mich daher nur wiederholen: Beeende den Thread nicht direkt, sondern teile dem Thread (über ein Flag ("bool terminateMe") oder besser ein SIGNAL) mit, dass er sich beenden soll.. mit einem Flag würde dann in "timerAction()" stehen "if (terminateMe) quit();"...
Code: Alles auswählen
void Thread::run() {
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(timerAction()) );
timer.start(500); // alle 500 ms ein Methodenaufruf
exec();
}
Die zweite, weil du versuchst, den Thread aus dem Kontext eines anderen zu steuern ("timerStop()" wird vom Mainthread her aufgerufen und wird daher auch im Mainthread ausgeführt, _nicht_ im nebenläufigen Thread!).
Ich kann mich daher nur wiederholen: Beeende den Thread nicht direkt, sondern teile dem Thread (über ein Flag ("bool terminateMe") oder besser ein SIGNAL) mit, dass er sich beenden soll.. mit einem Flag würde dann in "timerAction()" stehen "if (terminateMe) quit();"...