I have an app originated from "DirectX and XAML" project template. The main processing is made in a worker thread, and when some input event occures on main thread (like touch or back button pressing), I save it in a special storage and then process on the worker thread's game tick.
Due to that deferred nature of input handling, I cannot immediately decide should back button pressing be consumed or passed through. And I always mark it as consumed.
But if worker thread later decides that back button should be handled naturally (it means exiting the app), how do I achieve this? I know about Application.Current.Terminate();, but I hope there should be more elegant way to programmatically "press back button".
I suppose you would want to use the NavigationService
if (NavigationService.CanGoBack)
NavigationService.GoBack();
Related
I have a library that needs to call the main windows thread in UWP when it receives a message from a communication channel (let say, a message indicating a check box should be checked). The library saves a copy of the SynchronizationContext when it starts up, so it can Post back to it when the data comes in, but the trouble is, I'm not guaranteed that the caller of this library is on the main thread when it's initialized.
Is there some simple, guaranteed way to obtain the Main Window Thread (that is, the Windows' SynchronizationContext) so I don't need to rely on the caller to make sure the contexts aren't switch?
Trying to push something onto "the main window thread" will fail eventually when you pick the wrong window / thread. A better design is to have the library expose an event and then any consumer (including the main window) can listen to that event and do the appropriate thread marshalling (if any) for itself.
If you absolutely must get "the main window" then CoreApplication.MainView.CoreWindow will do it.
There are 2 forms.
Form2 isn't auto-created.
Form2:=TForm2.Create(Application);
Form2.Show;
If to do Sleep(10000); inside any forms then another one will be frozen. How to prevent this behavior?
My problem: a big text file (3 Mb) is continuously assigned (Lines.Assign) into a text editor, so a form is frozen.
Can I use another unfrozen form (not modal) to show a progress bar (a style is pbstMarquee)?
All GUI code should be run from the main thread, and it looks like you are following that rule.
If you call Sleep then the calling thread will not execute code until the timeout elapses. If you call Sleep from the main thread, then the message queue will not be pumped until the timeout elapses. Hence the entire app appears frozen.
Why does calling Sleep from one form affect another form? Because all GUI components are served from the single message queue of the main thread. Once you stop pumping that queue, all GUI components stop receiving queued messages like WM_PAINT, WM_KEYDOWN etc.
As I understand it your problem is that your application appears hung when you are loading a 3MB text file into an edit control. That size of file doesn't sound very large to me and one obvious solution would be to find an edit control that performs the load better. For example I'm pretty sure that Notepad, Notepad++ etc. do not take steps like showing progress when loading such files. I rather suspect that those apps don't pump the queue when loading files but you just don't notice because of the short time taken.
What you don't want to happen is for you to pump your queue to keep your GUI responsive and in turn allow the user to start loading another file whilst the first one is still loading. You need to disable your UI whilst processing a load operation. A modal progress dialog is one way to do that.
If you can't switch to a better performing control, you could show a modal progress dialog and use a background thread like this. The background thread would have load the file in small chunks, say into a string list. After each chunk of the file was ready it would then call Synchronize and get the main thread to add the contents of the string list to the edit control, and then clear the string list. The thread would then continue and load the next chunk. Adding to the edit control in small chunks would allow you to keep the message queue serviced.
You could show progress in a status bar rather than a modal dialog which would be less intrusive. But just remember to disable any UI that would cause re-entrant execution.
Better load your file in a separate thread. Or you will have to create your second form in a plain WinAPI, because VCL doesn't support multithreading.
I have simple window in Tcl/Tk which on hitting OK button runs simulation. I am using Linux. The window is destroyed when the simulation finishes. The problem is window lingers on while the simulation is running. I want the window to vanish after I hit OK button.
I tried using wm withdraw .mywindow but it makes the area where the window was displayed (containing OK button) to be white.
I found update while googling but it is said to be harmful.
If you do wm withdraw .mywindow, the window won't actually vanish until the event loop is entered, because it is the event loop that handles redrawing the screen.
You have a couple of choices to solve your problem. For one, you can call update idletasks. That is a variation on update that just handles "idle" tasks such as painting the screen, but not tasks like responding to buttons and other user-generated events. So, solution one is to do:
wm withdraw .mywindow
update idletasks
run_simulation
By the way, the reason update is harmful is because it essentially starts a new event loop -- another infinite loop. If during that event loop an event comes in that causes the same code to run again, you start a third, and a fourth, and so on. As a general rule, nested infinite loops are never a good thing. Remember: tcl is single threaded so those event loops don't run in parallel.
The other solution is to enter the event loop naturally, and schedule your simulation to run once all other events have been processed. Do do this, start your simulation by using the after command. Using after will place an event in the event queue. When the event loop gets to that event your simulation will begin.
For example:
wm withdraw .mywindow
after idle run_simulation
When the above code exits -- assuming it was called as a result of an event such as pressing a button or key -- the event loop will be re-entered, any pending events will be processed, then your run_simulation command will run.
By the way -- if you have a GUI that needs to be responsive while your simulation is running, you should read Keep a GUI alive during a long calculation on the tcler's wiki. There's a lot to read there which makes the problem seem harder than it is, but it's not as complicated as it might first seem.
Actually i am using this code and works ok, but i 'am wondering if is the correct way.
while WaitForSingleObject(MyThread.Handle, 0) = WAIT_TIMEOUT do
Application.ProcessMessages;
ShowMessage('i am done');
The VCL TThread class has its own WaitFor() method that pumps the main message queue internally when called within the main thread context:
MyThread.WaitFor;
ShowMessage('i am done');
Calling Application.ProcessMessages is generally considered a code smell. Let your main thread idle if it's got nothing to do.
If you ran a company and needed one of your workers to run to the store and grab some much-needed supplies, would you then pace by the door until he got back, or would you prefer to sit in your office and rest and wait for him, and find out that the supplies are here because you hear him walk through the door? Either way, he'll take the same amount of time, but the first way's gonna wear your legs out.
Similarly, instead of having your UI watch the thread, have the thread report back to the UI. One way to do this is to have the thread use PostMessage to send a custom message to the form that launched it once it's finished, and put a message handler on the form to respond to it.
It looks correct (if correct means it do the work). What I would change is to wait for a bit more time (50ms looks good to maintain the application responsive) while not eating CPU.
while WaitForSingleObject(MyThread.Handle, 50) = WAIT_TIMEOUT do
Application.ProcessMessages;
ShowMessage('i am done');
Sure there are other ways to do it... <joke>but I usually apply one of the main engineering principles:
if it works, don't touch it!</joke>
I agree with Mason Wheeler's remark, the main thread is best left to do its job, but I would suggest using the OnTerminate event on the thread. It is more 'Delphi natural' and the internal logic does the PostMessage bit for you. Since TThread is not a component, you can't view it in the object inspector and have to write and attach an event handler yourself. It gets called (in the main thread!) after the thread has completed/terminated.
While it looks okay, like jachguate I would use a bigger time-out value than 0 too. If you use WaitForSingleObject(MyThread.Handle, 100) then the main thread will wait a bit longer, thus eating up less CPU cycles.
A better solution would be the use of messages, though. Your application starts the thread and then puts all controls in disabled mode. The thread then executes and when it's finished, use SendMessage or PostMessage to the main window to notify it that the thread is done again. Then your application will just enable every control (and whatever else) again. This has as advantage that you keep the "natural" messageloop for the application alive, instead of running your own messageloop with this solution.Unfortunately, the message-method has one drawback: if the thread crashes then no message will be sent back, so a backup plan would be practical. For example, by adding a timer control to your mainform which checks every second if the thread is still alive. If not, it too would just activate the form again, disabling itself again.
I have a multi-threaded Delphi 6 Pro application that I am currently working on heavily. If I set a breakpoint on any code that runs in the context of the Main thread (VCL thread) I don't have any problems. However, if a breakpoint is triggered on any code in one of my other threads, after I continue the application from the breakpoint, all repaints to the VCL components on the main thread (including the main form) don't happen anymore. The application isn't dead because other background code keeps running, just the main thread. It's as if the windows message dispatcher has been corrupted or rendered dormant.
Note, in this application I allocate my own WndProc() via allocateHwnd() on the main form because I need to catch certain registered messages. From that WndProc() I dispatch any custom messages I handle and if the current message is not handled by my code, I pass the message on by calling the main form's inherited WndProc(). If I do handle the current message I simply return from my WndProc() with Msg.Result set to 1 to tell the dispatcher that the message was handled. I can't simply override the TForm WndProc() instead of allocating my own WndProc() because for some reason the Delphi VCL does not pass through registered messages instantiated with the Windows API RegisterWindowMessage() call.
Has anybody experienced this in similar context and if so, what did you do to fix it?
-- roscherl
Since you call AllocateHWnd, that means you've created another window. You mustn't just take the messages that were addressed to that window and forward them to your form's window. Doing that, you're bound to screw things up in your program, although I'm not sure exactly how. Painting problems sound plausible. You should make sure it's really just painting problems and not that your main thread is still suspended. The debugger should be able to tell you that. (You should call DefWindowProc to make your allocated window handle messages you're not prepared to handle yourself. And returning 1 doesn't tell the dispatcher anything; the dispatcher doesn't care — whoever called SendMessage wants to know the result.)
I promise you that forms are completely capable of receiving registered window messages. Override WndProc or assign a new value to the WindowProc property (and remember to save the old value so you can call it after handling your own messages). The source of your problem lies elsewhere.
UPDATE: I'm not saying the way I got past the problem is a good solution. I need to take Rob Kennedy's notes and do some refactoring. However, to get past the problem for now I gave the thread it's own Window and WndProc() and at the top of the thread Execute loop I have a PeekMessage() while loop with calls to TranslateMessage() and DispatchMessage(). I no longer have a problem with setting breakpoints in the thread, but obviously this compounding of WndProc() methods indicates a structural problem in my code. I wanted to add this reply to fill out the discussion. I'm hoping that once I put Rob's suggestions to work when I clean up my WndProc() methods on the relevant forms, especially the main form, I can get rid of the this new WndProc() that I just added to the thread.
Robert.