Cocoa Stop Button - multithreading

I load a file from the disk, chunk by chunk, and I would like to grant the user the opportunity to click on a button and stop loading. I already know how to do that with threads (e.g. detachDrawingThread) but here I wouldn't use that way. The loading method in facts should return a bool value, it's called from different points and it's usually followed by many other lines of code. So I can't launch the thread and leave it work in a separated thread. And I can't split my code so easily. It's really complicated.
I just need to detect if the user clicked on a given button. That's all.
Is a quick and simple way to do that without rewriting my whole app?

Your loading routine must be using some sort of loop. Create a boolean and in your loop test for the condition of the boolean. Then in your button selector, set the selector to change the status of the boolean. Once your loop goes around again, it will exit and stop loading data.

First rule of good Mac apps:
Don't block the main thread
Some options:
Do the work on a background thread. Sounds like you don't want to/can't in this case
Use something like NSURLConnection to process the data in small chunks on the main thread as it's read in, rather than running a continuous loop
Run the event loop periodically while loading data so UI events can be processed

Thanks, I usually use threads, but in this case in order to use a thread I should almost re-write my app... So I have found a quick solution. Within the loop I added:
while(event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]){
[NSApp sendEvent:event];
}
So when the user clicks on the button to stop the loop, I post a notification and exit the loop. It works well.

Related

Is it possible to Derive class from CWinThread Class in dialog based application

I am working with Dialog based application.
My Question is that, I want to show Waiting dialog, until some database operation carried out.
i Used Derived class from CWinThread, but problem is that, when this thread close, the background (Main application dialog) remains at deactivated means( it hide behind another window).
i am thinking that, this is happening because of WaitDialog used CWinThread class.
The problem is not unique to a dialog based application. Creating windows of any kind in more than one thread is difficult and not recommended. In your case it sounds like your wait dialog is modal, while its parent dialog is in another thread. That is even worse and can lead to deadlocks between threads.
The reliable solution is to put the wait dialog (and all other GUI) in the main thread, and the lengthy database processing in a secondary thread.
Another alternative would be to use a Modeless Dialogbox which can also optionally show the status and call the DestroyWindow function when the database operation is completed -- you may need to disable some operations of the main window while the Modeless Dialogbox is visible, though.
From the comments on my previous answer, it looks like that alternative is not viable in this situation.
Maybe a better way would be to create a normal modal "wait" dialog box, start the background thread in the dialog's InitDialog, periodically check the status of the thread using a timer and end the dialog when the thread completes?

Visual C Multi-Threading (Please Help)?

I have written a .NET program, using Windows form Application.
My application is fairly simple.
Basically, I have two simple buttons on my form.
When the form is first loaded, I set up a global variable (bool run = true).
And my first button is essentially a very simple while loop.
while(run)
{
// do some code
}
And what I want to do, is have the second button set the value of the boolean to false (bool run = false).
But, once I clicked the first button, I cannot even touch the second button!
I have read quite about this, and I think my solution is to use a multi-threading.
I have found some example codes on line for multi-threading, and I tried to incorporate those, but I don't know why I cannot get it to work. Once I click button #1, there is no way for me to be able to click button #2.
Your UI thread should not have any infinite or a wait-on-something - never! You must not block the UI for anything (other than simple calculations, validations, user confirmation etc). You should make a thread for performing length task, and let that thread communicate to UI thread using asynchronous (or synchronous, if you prefer) communication.
On native Windows GUI application, you can use PostMessage (async), or SendMessage (sync). For .NET GUI applications, you can use Control.BeginInvoke (async), or Control.Invoke (sync).
Please read this article on how this is done.

QWebView setContent in a separate thread

I have an application that requires to use QWebView::setContent() to load some HTML content to a QWebView. All of this happens on an embedded device with ARMv5 processor (think 400 MHz). Most of the time, I can load the page in reasonable time (up to 5 seconds), however sometimes I have content that takes long time to load (~30 seconds for 300KB of content).
The problem is that the setContent call blocks the main thread. I need to be able to process events during the loading, and maybe even cancel the load if the user decides not to wait any longer.
I was thinking about running the setContent call in other thread, so that it does not block the event processing and I can cancel it if necessary. However, I get the dreaded "widgets must be created in the GUI thread", and I see no way of solving this easily.
Is it possible to run QWebView::setContent in a separate thread? If so, how? If not, is it possible to handle GUI events while setContent is running? Is it possible to "cancel" the setContent call?
EDIT
To clarify a bit more, what really interests me is how to be able to stop the setContent call and/or handle GUI messages, so that the interface remains responsive, with large amounts of data passed using setContent.
EDIT 2
To clarify even further, I am dealing with long, static content, i.e. no JavaScript, just a lot of static HTML, through which the user wants to scroll even while it is loading more content. The main idea is to allow her/him to go down a page even when the page is not fully loaded.
Some time ago I faced a similar problem. As far as I know, only the main contents of the page is acting synchronously.
The fact is that the GUI core "paints" the page and this is time consuming. So, the main thread gets freezed until the main contents is loaded completely.
In my case, the solution was simple: make the main contents a secondary one and work with local files!!!
So, what is my proposal:
1) Prepare a local file (/tmp/loader.html) that contains something like this:
<html>
<body onload='setTimeout(function() { window.location="contents.html"; }, 1000);'>
Loading...
</body>
</html>
2) Each time you need to load a new content, save it to the secondary file (/tmp/contents.html) and force the update of the loader (maybe also a refresh). Easy:
QFile f("/tmp/contents.html");
if (f.open(QFile::WriteOnly)) {
qint64 pos = 0;
while (pos < contents.length()) {
pos += f.write(contents.mid(pos, 1024)); // chunk of 1024
qApp->processEvents();
}
f.close();
webview->setUrl(QUrl::fromLocalFile("/tmp/loader.html"));
}
Observe that I permit the event loop to process pending events if the file saving is also slow...
3) Anytime you need to cancel the loading, you can load another contents, remove the contents file, or other possible approaches.
Note that, as far as I know, you would never make asynchronous the painting of the contents. And that is the real issue in embedded systems.
Since QWebView::setContent() is a blocking call, I ended up using a work-around. The main idea is that XML processing is much faster than rendering the page. Therefore I do the following:
Parse the document as XML DOM document (a reasonable assumption in my case), and find the body element.
Keep only a pre-defined number of child elements of body (something like 20 elements). Store the remaining elements in another XML DOM document.
Show the initial document (serialized XML) using QWebView::setContent(), which is relatively fast. Start a timer with timeout 0 on SLOT(loadNextChunk()).
loadNextChunk() moves another 20 or so elements from the backup document at the end of the body using body->appendInside(html), where body is a QWebElement.
Stop when no more elements are available.
This works because in between the calls to loadNextChunk(), the GUI has a chance to react to events.
QWebView, as its name suggests, is a widget. QWebPage, on the other hand, is a plain old QObject, with all the threading goodness you could possibly want.
Now tie it together:
void QWebView::setPage ( QWebPage * page )

How to avoid use of timer when using TThread to communicate with UI thread

I have a TThread which receives and sends to a device on a COM port. After I read the data, I want to activate the GUI (not in the same thread) using Synchronize(function name). However, when I call the GUI's form function to perform a button click, I get an access violation. I checked to see if the form's value is null and it is not, since this would be an obvious reason for access violation. Right now, I am setting global flags and using a timer that continuously checks to see if a certain condition is met and if so, then I fire off the button click event in that form. That seems to be the only way to avoid getting the access violation.
I really don't like timers so is there a way to avoid having to use a timer on the form?
You can post a message to the window in question. The timer works in a similar manner. It just fires off a windows message inside the form. You obviously have a handle to the window.
CWnd::PostMessage(...) Don't use send message, it gets processed inline and could cause your thread to stop working.
Typically when you have a worker thread that attempts to access Guithread, they conflict. It's been a while since I've used MFC and threading but that's what I remember. I believe it's documented to work that way.
I found the problem. I thought I was checking if my Form was null, but I was not. I fixed it making sure the form I was referencing is not null.
Edit: Turns out that one of the forms that is called when I call Fbutton1Click() is Modal so it blocks my thread. I ended having to go back to a timer to call the button click instead.. oh well.

Automated Clicking Problem

I am coding up a program for automated testing which randomly clicks an open application window using various User32.dll library calls. My current problem is this, if a click would open a dialog, using Process.WaitForInputIdle() does not wait long enough for that dialog to be detected the next trip around the loop, which means several clicks get cued and if those clicks happen to be on something in the dialog I want to avoid (say an exit button) there is no way of telling that in advance. My question is this. Is there a way of waiting for the process or thread to finish all processing and only be waiting in the message loop again?
I hope that made sense.
Cheers
Ross
EDIT
Failing this, would it be somehow possible to set the process / threads of the target program and my program to both use the same processor and adjust the prioritorys of each so that the target program gets preference?
WaitForInputIdle will unfortunately return as soon as the app is in a message loop with no input messages waiting.
If you own the code to the dialog, you could have the dialog call SetEvent in its WM_INITDIALOG to signal your automation that it is ready for testing. Alternatively, you could look at using SetWinEventHook on the process and wait for the dialog to actually be created before sending input events to it.
The way around this it seems is to use the SendMessage API instead of the mouse_event or SendInput API. The reason for this is that SendMessage blocks until it has been processed. Just make sure you always get the handle of the window immediatly under where you want to click (using WindowFromPoint) and convert the mouse coordinates from screen to client coords using ScreenToClient. Pack the coordinates into the lParam parameter by using ((pt.Y << 16) + pt.X). This will block until processed and so any modal dialogs shown will block this call.

Resources