signal handling by sigaction - unix

i was reading about the use of pselect system call when i came across this code and comments...
static void handler(int sig) { /* do nothing */ }
int main(int argc, char *argv[])
{
fd_set readfds;
struct sigaction sa;
int nfds, ready;
sa.sa_handler = handler; /* Establish signal handler */
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGINT, &sa, NULL);
/* ... */
ready = select(nfds, &readfds, NULL, NULL, NULL);
/* ... */
}
this solution suffers from a race condition: if the SIGINT signal is delivered after
the call to sigaction(), but before the call to select(), it will fail to interrupt
that select() call and will thus be lost.
now i am not sure about sigaction system call...initially i thought that it sort of saves a handler corresponding to a signal and that's it...when signal arrives it looks for its handler and handler is executed...but if that is correct then the handler corresponding to the signal would be saved for the entire program and it would be executed whenever the signal arrives...so however small the duration between sigaction and select, the signal would be handled...
but this code makes it seem like the signal is handled only when it coincides with the call/execution of sigaction...after the call is completed signal will not be handled by handler set by sigaction for the rest of the program(which i know, sounds absurd)
please explain!!

You need to look at that code in the context of the article - the code is attempting to arrange for a signal to interrupt select(). The race condition mentioned does not cause sigaction() or the signal handler to fail in any way - it was just noting that there's a possibility that the signal could be delivered between the sigaction() call and the select() call, which makes that pattern unacceptable for achieving the desired outcome. You are right that a signal arriving any time after sigaction() will be handled, whether it's before, during, or after signal(). However, that can't be used to reliably provide an early interruption path for select(), which is what the context of the article is about.

Related

Qt event loop and unit testing?

I'we started experimenting with unit testing in Qt and would like to hear comments on a scenario that involves unit testing signals and slots.
Here is an example:
The code i would like to test is (m_socket is a pointer to QTcpSocket):
void CommunicationProtocol::connectToCamera()
{
m_socket->connectToHost(m_cameraIp,m_port);
}
Since that is an asynchronous call i can't test a returned value. I would however like to test if the response signal that the socket emits on a successful connection (void connected ()) is in fact emitted.
I've written the test below:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
QTest::qWait(250);
QCOMPARE(spy.count(), 1);
}
My motivation was, if the response doesn't happen in 250ms, something is wrong.
However, the signal is never caught, and I can't say for sure if it's even emitted. But I've noticed that I'm not starting the event loop anywhere in the test project. In the development project, the event loop is started in main with QCoreApplication::exec().
To sum it up, when unit testing a class that depends on signals and slots, where should the
QCoreApplication a(argc, argv);
return a.exec();
be run in the test environment?
I realize this is an old thread but as I hit it and as others will, there is no answer and the answer by peter and other comments still miss the point of using QSignalSpy.
To answer you original question about "where the QCoreApplication exec function is needed", basically the answer is, it isn't. QTest and QSignalSpy already has that built in.
What you really need to do in your test case is "run" the existing event loop.
Assuming you are using Qt 5:
http://doc.qt.io/qt-5/qsignalspy.html#wait
So to modify your example to use the wait function:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
// wait returns true if 1 or more signals was emitted
QCOMPARE(spy.wait(250), true);
// You can be pedantic here and double check if you want
QCOMPARE(spy.count(), 1);
}
That should give you the desired behaviour without having to create another event loop.
Good question. Main issues I've hit are (1) needing to let app do app.exec() yet still close-at-end to not block automated builds and (2) needing to ensure pending events get processed before relying on the result of signal/slot calls.
For (1), you could try commenting out the app.exec() in main(). BUT then if someone has FooWidget.exec() in their class that you're testing, it's going to block/hang. Something like this is handy to force qApp to exit:
int main(int argc, char *argv[]) {
QApplication a( argc, argv );
//prevent hanging if QMenu.exec() got called
smersh().KillAppAfterTimeout(300);
::testing::InitGoogleTest(&argc, argv);
int iReturn = RUN_ALL_TESTS();
qDebug()<<"rcode:"<<iReturn;
smersh().KillAppAfterTimeout(1);
return a.exec();
}
struct smersh {
bool KillAppAfterTimeout(int secs=10) const;
};
bool smersh::KillAppAfterTimeout(int secs) const {
QScopedPointer<QTimer> timer(new QTimer);
timer->setSingleShot(true);
bool ok = timer->connect(timer.data(),SIGNAL(timeout()),qApp,SLOT(quit()),Qt::QueuedConnection);
timer->start(secs * 1000); // N seconds timeout
timer.take()->setParent(qApp);
return ok;
}
For (2), basically you have to coerce QApplication into finishing up the queued events if you're trying to verify things like QEvents from Mouse + Keyboard have expected outcome. This FlushEvents<>() method is helpful:
template <class T=void> struct FlushEvents {
FlushEvents() {
int n = 0;
while(++n<20 && qApp->hasPendingEvents() ) {
QApplication::sendPostedEvents();
QApplication::processEvents(QEventLoop::AllEvents);
YourThread::microsec_wait(100);
}
YourThread::microsec_wait(1*1000);
} };
Usage example below.
"dialog" is instance of MyDialog.
"baz" is instance of Baz.
"dialog" has a member of type Bar.
When a Bar selects a Baz, it emits a signal;
"dialog" is connected to the signal and we need to
make sure the associated slot has gotten the message.
void Bar::select(Baz* baz) {
if( baz->isValid() ) {
m_selected << baz;
emit SelectedBaz();//<- dialog has slot for this
} }
TEST(Dialog,BarBaz) { /*<code>*/
dialog->setGeometry(1,320,400,300);
dialog->repaint();
FlushEvents<>(); // see it on screen (for debugging)
//set state of dialog that has a stacked widget
dialog->setCurrentPage(i);
qDebug()<<"on page: "
<<i; // (we don't see it yet)
FlushEvents<>(); // Now dialog is drawn on page i
dialog->GetBar()->select(baz);
FlushEvents<>(); // *** without this, the next test
// can fail sporadically.
EXPECT_TRUE( dialog->getSelected_Baz_instances()
.contains(baz) );
/*<code>*/
}
I had a similar issue with Qt::QueuedConnection (event is queued automatically if the sender and the receiver belongs to different threads). Without a proper event loop in that situation, the internal state of objects depending on event processing will not be updated. To start an event loop when running QTest, change the macro QTEST_APPLESS_MAIN at the bottom of the file to QTEST_MAIN. Then, calling qApp->processEvents() will actually process events, or you can start another event loop with QEventLoop.
QSignalSpy spy(&foo, SIGNAL(ready()));
connect(&foo, SIGNAL(ready()), &bar, SLOT(work()), Qt::QueuedConnection);
foo.emitReady();
QCOMPARE(spy.count(), 1); // QSignalSpy uses Qt::DirectConnection
QCOMPARE(bar.received, false); // bar did not receive the signal, but that is normal: there is no active event loop
qApp->processEvents(); // Manually trigger event processing ...
QCOMPARE(bar.received, true); // bar receives the signal only if QTEST_MAIN() is used

Qt can not respond key Press event immediately

Environment: Ubuntu, Qt Creator
In my Qt app, I found that sometimes Qt doesn't respond to my key press event immediately, but if I wait a while, it eventually responds.
I think something is blocking the UI.
As I know, if a Qt's component (QWidget etc.) is being destroyed, the Qt UI will be blocked. I have checked my code, there is no component being destroyed at the time I'm pressing the up/down key.
I really want to know is there any other things can block Qt UI.
{
...
connect(webViewWidget, SIGNAL(loadfinished()), this, SLOT(addItem()));
...
}
void addItem()
{
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}
void keyPressEvent(QKeyEvent *event)
{
switch(event->key)
{
case UP_KEY:
scroll up;
break;
case DOWN_KEY:
scroll down;
break;
default:
break;
}
}
In general, your key press event will not be processed before all other events which were put into the application's event queue before pressing your key are processed.
Therefore it could be any kind of event which has not finished processing. Maybe you can figure out if there are any events, e.g. by using QApplication::hasPendingEvents or by inheriting from QApplication and adding debug output whenever an event is added or fully processed.
Destruction of objects is usually not a concern, unless you are doing a lot of work in the destructor. Destroying a webview may take long. You probably should not be destroying it like you do. Instrument that delete (see code below) and see how long it takes.
Your own code may be calling APIs that block. Are you calling any third party libraries? Are you calling any wait... methods in Qt's own API?
If you're unsure, you can instrument every slot and every reimplemented virtual method like xxxEvent(...). You'd need to instrument only slots and reimplemented QObject/QWidget methods, not every method in your code.
You may be producing an event storm, perhaps by posting lots of events in a loop, or by sending a lot of signals that are hooked up to slots connected via a Qt::QueuedConnection. Make sure you're not calling repaint() from within paintEvent() for example.
The instrumentation example below uses RAII and is very easy to apply. Alternatively, you can use a profiler.
#include <QElapsedTimer>
#define INSTRUMENT() Instrument instr__ument(__FUNCTION__)
#define INSTRUMENTLIM(lim) Instrument instr__ument(__FUNCTION__, (lim))
class Instrument {
QElapsedTimer timer;
int limit;
const char * function;
public:
Instrument(const char * name, int timeLimitMs = 20) :
function(name), limit(timeLimitMs) { timer.start(); }
~Instrument() {
if (timer.elapsed() > limit) {
qDebug("%s was slow, took %d ms", function, timer.elapsed());
}
}
}
void slot(...)
{
INSTRUMENT();
...
}
void addItem()
{
INSTRUMENT();
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}

What's the QMetaCallEvent for and how to access its details?

I have an event filter and I noticed when I click to expand/collapse a tree branch I get QEvent::MetaCall. I was thinking about using this to roll my own expand/collapse code, but I don't know how to get any information, such as the index of the item.
Is there anything available from this MetaCall event type?
I found someone had asked this same question on another site, but without an answer, here:
http://www.qtcentre.org/threads/37525-How-to-filter-QEvent-MetaCall
What is this event typically used for?
The biggest question are: What exactly are you trying to do? What is the Qt class that received those events? As far as I'm concerned, you're trying to do things the hard way, so why bother?
The QMetaCallEvent is the event representing a slot call whenever a queued connection is used to invoke a slot. This might be due to a signal firing that was connected to a slot, or due to the use QMetaObject::invoke or QMetaObject::invokeMethod. The queued connection bit is the important part! Queued connections are not used by default for calls between objects in the same thread, since they have the event queue management overhead, unless either of the two conditions below holds true:
You provide Qt::QueuedConnection argument to QObject::connect or QMetaObject::invoke[Method], or
The receiving object's thread() is different from the thread where the call is originating - at the time of the call.
The QMetaCallEvent event class carries the information needed to invoke a slot. It contains the sender QObject and its signal id (if the call comes from a signal-slot connection), as well as the target slot identifier, and the arguments needed to be passed into the slot.
Thus, you could check if the called slot is the one you wish to intercept, as well as what arguments were passed to it. For example, if you're calling a slot with a single int parameter, then *reinterpret_cast<int*>(metaCallEvent->args()[1]) will give you the value of that integer. The zero-th argument is used for the return value, if any, so the parameters are indexed with base 1.
Disclaimer Since the QMetaCallEvent class is internal to Qt's implementation, you're making your application's binary tied to the particular Qt version in full (entire major.minor version) and you lose the benefits of binary compatibility offered by Qt across the major version. Your code may still compile but cease to work properly when you switch to another minor version of Qt!
The below applies to Qt 5.2.0, I have not looked at any other versions!
So, suppose you want to intercept a call to QLabel::setNum. You'd catch such events as follows:
#include <private/qobject_p.h> // Declaration of QMetaCallEvent
bool Object::eventFilter(QObject * watched, QEvent * event) {
QLabel * label = qobject_cast<QLabel*>(watched);
if (! label || event->type() != QEvent::MetaCall) return false;
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
static int setNumIdx = QLabel::staticMetaObject.indexOfSlot("setNum(int)");
if (mev->id() != setNumIdx) return false;
int num = *reinterpret_cast<int*>(mev->args()[1]);
// At this point, we can invoke setNum ourselves and discard the event
label->setNum(num);
return true;
}
If you want to see, globally, all slots that are called using the metacall system, you can do that too. Template parametrization of the base class allows flexibility to use any application class - say QCoreApplication, QGuiApplication, QApplication, or a user-derived type.
template <class Base> class MetaCallWatcher : public Base {
MetaCallWatcher(int& argc, char** argv) : Base(argc, argv) {}
bool notify(QObject * receiver, QEvent * event) {
if (event->type() == QEvent::MetaCall) {
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
QMetaMethod slot = receiver->metaObject()->method(mev->id());
qDebug() << "Metacall:" << receiver << slot.methodSignature();
}
return Base::notify(receiver, event);
}
}
int main(int argc, char ** argv) {
MetaCallWatcher<QApplication> app(argc, argv);
...
}
The QEvent::MetaCall-type event is created whenever a signal has been emitted that is connected to a slot in the receiving QObject. Reacting to this event in a custom filter/event handler seems to circumvent Qt's mightiest feature, the signal-slot architecture. It's probably better to find out which slot is called and if that slot is virtual so you can overload it.
QEvent::MetaCall is used for delivering cross-thread signals.

Help me understand the QThread usage

I have the MainWindow w windows and TestThread testThread as a member of w. I know it i simple, but I cannot run the testThread.foo() method in testThread thread (not in window thread). In another words: I don't understand the QThread behavior.
Please help correct the next test application. There is a QProgressBar *MainWindow::ui::progressBar and QPushButton *MainWindow::ui::startButton (write simply). I want to start (by startButton click) TestThread::foo(int* progress) which will increment int progress each second.
MainWindow:
MainWindow::MainWindow(QWidget *parent) : // ...
{
// ...
ui->progressBar->setRange(0, 5);
progress = 0; // int MainWindow::progress
this->connect(ui->startButton, SIGNAL(clicked()), SLOT(startFoo()));
connect(this, SIGNAL(startFooSignal(int*)), &testThread, SLOT(foo(int*)));
// TestThread MainWindow::testThread
testThread.start();
}
// ...
void MainWindow::timerEvent(QTimerEvent *event)
{
ui->progressBar->setValue(progress);
}
void MainWindow::startFoo() // this is a MainWindow SLOT
{
startTimer(100);
emit startFooSignal(&progress);
// startFooSignal(int*) is a MainWindows SIGNAL
}
TestThread:
void TestThread::foo(int *progress) // this is a TestThread SLOT
{
for (unsigned i = 0; i < 5; ++i) {
sleep(1);
++*progress; // increment MainWindow::progress
}
}
I know, this is simple. I am doing something wrong :)
P.S. I want to run the simpliest (as possible) example to understand the QThread behavior.
Thanks!
The critical issue is to have the object containing the foo()-function be owned by that thread, so that slot calls are dispatched from the right thread's event-loop.
(Note that there's no need to actually have foo() on the TestThread object. You can use separate objects for QThread and WhatEver::foo() function. It might be easier too, I'm not sure..)
IIUC, this is what you have to do:
Use QObject::moveToThread() to assign the object containing the foo-function to TestThread (that means that Qt::AutoConenction (the default) signal/slots calls will run correctly across thread, being dispatched from each thread's own event loop).
By having the object "owned" by the right thread, slots calls will be scheduled on that thread's event loop, rather than executed directly.
Hope it helps. :)
One alternative solution: If you just want to run a function in another thread, and don't insist using QThread, you should check out the QT Concurrent Namespace.
The following example will run the function foo() in separate thread and will not block on the line where calling the function. Of course there are mechanisms to understand when a function ends, to get a result, to wait for it, to control execution.
void foo(int &progress) {...}
int progress;
QtConcurrent::run(foo, progress);
Hope this helps
See QThread::start and QThread::run.

Qt: How to delay a program while QTimer is active?

Please refer to the following link as I tried to simplify the problem I was having and now have run into a problem that I cannot solve.
Link: Qt: How to use QTimer to print a message to a QTextBrowser every 10 seconds?
In the posting for the link above I simplified the task I am trying to do by simply saying that I wanted to push a button and have it display something in a QTextBrowser every 10 seconds. I was having trouble getting QTimer working at the time so I thought that if I could get QTimer to work then I could finish my task.
What I am really trying to do is read lines from a file and after every 2500 lines I would like to print a message and then wait 10 seconds.
Pseudocode:
while(not at the end of the file)
{
read in 2500 lines
print a message
wait 10 seconds
}
QTimer is nice but it does opposite of what I want it to do. Instead of transmitting a message and waiting 10 seconds, first they wait 10 seconds, timeout and then send the message.
So to get it to work the way I want I first called the printMessage() SLOT and then I made a SLOT called stopTimer() that simply stops the timer. So after the 10 seconds has passed it will simply call stopTimer() and then continue processing the input file.
Onto the REAL problem:
Qt does not wait for a QTimer to finish before it moves on through the code. I want the code to wait the full 10 seconds before it reads the next 2500 lines of code. I found that QTimer has an isActive() function that returns a bool value.
So in the place where I wanted the 10 second delay to finish I put the following:
while(timer->isActive());
I figured the program would stay in this loop for 10 seconds and then exit after the QTimer timed out because the condition would then be false. The problem is that it doesn’t exit the loop because the status of the timer never changes regardless of how long it waits in this loop! I checked with the debugger and isActive( ) remains true regardless of elapsed time.
I then omitted the while(timer->isActive()) loop and observed the timer in the debugger. It seems that the timer does not actually start timing until it exits the while(not at the end of the file). So I believe that since the while(timer->isActive()) loop is nested inside this, it is causing it to never timeout. I could be wrong but this is what seems like is happening. Also, what is annoying is that the QTimer object has no field that shows the elapsed time of the timer when it is active. Therefore, I cannot check the elapsed time at all to further debug.
Someone please test this out or let me know a workaround for this!
For something that sounds so easy, this has been the biggest pain I have had in recent time, but I generally don’t use Qt so it could be my lack of experience.
Here is an excerpt from code I have which currently freezes as stated above:
void Form::startBtn_pushed()
{
QTimer *timer = new QTimer(this);
QFile file(“file.txt”);
QTextStream stream(&file);
QString line;
int lineCount = 0;
connect(timer, SIGNAL(timeout()), this, SLOT(stopTimer()));
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
printMessage();
timer->start(10000);
while(timer->isActive()); //Wait for timer to timeout before continuing
}
}
}
Sorry for the long post and if I might have made any grammatical errors with my code here. I do not have internet access on my dev machine so I had to retype this here.
Doing something like while(timer.isActive()) is not a good idea at all as it will cause your application to consume around 100% CPU time. It will also cause your application to never return to the event processing loop where the actual code for timer is executed, that's why it freezes.
If you still want to use this approach, you should call QCoreApplication::processEvents() in the loop. It will temporarily pass control back to the event loop, so it will cause timer to time out. Instead of connecting timeout() to stopTimer(), you can just call timer.setSingleShot(true) before you start it, it will cause it to stop automatically after the first timeout.
Note that you have a memory leak there as you create a new timer on each button push. Surely they are children of your form and will be destroyed, but only when the form is destroyed.
If you want a more elegant approach, you can create a separate class for reading that file. In the constructor you'd open your file and stream which should be fields in this class. This class should also have a sort of readMore() slot which will read 2500 lines, then put a message and return. If it doesn't reach the end of the stream, then it would call QTimer::singleShot(10000, this, SLOT(readMore())), which will cause the event loop to call readMore() again in 10 seconds. The code would looks something like this (didn't check for errors):
// myfilereader.h
class Form;
class MyFileReader: public QObject {
Q_OBJECT
public:
MyFileReader(const QString &fileName);
// this should be called after you create an instance of MyFileReader
void startReading() {readMore();}
private:
QFile file;
QTextStream stream;
private slots:
void readMore();
signals:
void message(); // this should be connected to printMessage() in the Form
void finished();
};
// myfilereader.cpp
MyFileReader::MyFileReader(const QString &fileName):
file(fileName),
stream(&file),
{
// open the file, possibly throwing an exception
// or setting some sort of "invalid" flag on failure
}
void MyFileReader::readMore()
{
QString line;
int lineCount = 0;
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
emit message();
break;
}
}
if (stream.atEnd())
emit finished();
else
QTimer::singleShot(10000, this, SLOT(readMore()));
}
This is a kind of more heavyweight approach, but this is the price of asynchronous event handling. You could also put all this stuff into the Form class, but I think using a separate class is better.
As Daniel points out, if reading 2500 lines takes a long time, say 5 seconds, the message will be printed after 10 seconds after the reading has finished, that is, 15 seconds after it has started. If you want the message to be printed approximately each 10 seconds no matter how long reading takes, you should add a QTimer timer field to the class, connect it's timeout() signal to the readMore() slot in the MyFileReader constructor, then in the startReading() method call timer.start() before calling readMore(). Now, at the end of readMore() do this:
if (stream.atEnd()) {
timer.stop();
emit finished();
}
You need a QTimer field in this case because you can't cancel a QTimer::singleShot() call, but you need to do it if you have reached the end of the stream, otherwise your readMore() will just keep on getting called again and again, even if there is nothing more to read. Note that even in this case, it is still possible for the message to appear less frequently than every 10 seconds in case if reading 2500 lines takes longer than these 10 seconds. If you want exactly 10 seconds, you should probably check the elapsed time in the loop instead, but I think that's an overkill, unless you expect reading to be very slow.
Slightly off topic, but if you want an easy way to avoid memory leaks, you can also do this in the constructor:
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
It will automatically mark your reader for deletion when you emit finished(), and, once that happens, the reader will be deleted as soon as the control goes back to the event loop. That is, after all slots connected to the finished() signal return. This approach allows you to just allocate a MyFileReader on the heap, then discard the pointer without worrying about memory leaks.
QTimer has a signal called timedout(). If you connect a slot to this, you can set the initial timer to a REALLY short interval (1 MS maybe). When the timer expires, inside the slot, you can send your message. At the end of the slot, set the interval to 10 seconds, set singleshot to false, and the start the timer again.
If you don't want to do the setting each and every time the slot is called, you can simply make 2 slots. The first time, the slot does the setup for the rest of the calls. It also disconnects itself from the QTimer and connects the second slot. Then things continue merrily on their way.
Edit:
Also, realize that when slots are called they are called on the event thread. So, by clicking a button and putting a loop that spin-blocks/busy-waits until the timer expires, you are guaranteeing that you will not enter this state because you are blocking the very thread that the timeout signal will be processed on.
QTimer does all of its processing inside Qt's event loop, so your code must return to the event loop to cause the timer to time out. So what you want to do is have startBtn_pushed set up the timer, connect a slot to the timer's timeout signal, then probably call that slot itself (so that it is called immediately). It would look something like this:
// timer, file, and stream are now instance variables (or maybe file and stream
// are broken out into their own class... up to you.
void Form::startBtn_pushed()
{
// timer has been allocated before (but not started)
file.open(“file.txt”);
stream.setDevice(&file);
connect(timer, SIGNAL(timeout()), this, SLOT(readAndPrint()));
timer->start(10000);
readAndPrint(); // respond to the button press immediately
}
void Form::readAndPrint()
{
int lineCount = 0;
while(!(stream.atEnd() && lineCount < 2500)
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
printMessage();
}
}
}
I have figured out a solution that is much simpler than those proposed here.
I realized it was much easier to use a QTime object instead of a QTimer object.
Basically you start a QTime object and then you use its elapsed() function to check how much time has passed to since it was started.
Thanks to everyone for taking the time to help. I did try to implement a couple of your solutions into my code but had some trouble since I am not a pro at Qt and they were more complex than I would have thought. In the end I find this solution to be a easy solution to what should have been an easy problem.
I certainly learned a lot from this problem and I hope you all did too.
My question to you is why didn't anyone suggest using QTime from the start?
Thanks again!
My solution:
void Form::startBtn_pushed()
{
QTime *timer = new QTime();
QFile file(“file.txt”);
QTextStream stream(&file);
QString line;
int lineCount = 0;
connect(timer, SIGNAL(timeout()), this, SLOT(stopTimer()));
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
timer->start();
while(1)
{
QApplication::processEvents();
if(timer->elapsed() == 10000)
{
printMessage();
break;
}
}
}
}
}
QEventLoop l;
connect( timer, SIGNAL( timeout() ), &l, SLOT( quit() ) );
l.exec(); // Waiting without freezing ui

Resources