In VS 2010 I'm trying to read a text file on button click and set that value as the status button value. The text file will always contain a single line with a number between 0 and 100. I'm trying to do this in C++/CLI because I'm familiar with C++ but this seems like a whole different lang! This is what I have but it causes the GUI to crash. I know it's the loops fault but I don't know why, what's the best (noob) way to approach this?
while (result<100)
{
StreamReader ^read=gcnew StreamReader("Status.txt");
String ^x=read->ReadLine();
read->Close();
Int32::TryParse(x, result);
progressBar1->Value= result;
}
You haven't said whether you're using WPF or WinForms for your GUI, but this answer applies equally to either.
If your while loop in in a button handler, that code is running on the UI thread. The UI thread is also responsible for redrawing the GUI. Since your button method isn't returning, it's never getting to the 'repaint' code, and the UI just stops.
You didn't mention what is writing those integers 0 to 100 to a file. If it's another thread in the same application, there are MUCH better ways of communicating the progress between threads.
I recommend that you replace that while loop with a Timer object of some sort. (There are appropriate classes, depending on whether you're using WPF or WinForms.) Set the interval to something like 500 milliseconds, start the timer when your background task begins, and stop the timer when it ends. In the timer method, don't have a while loop, just do it once.
Related
I'm working on a custom cross platform UI library that needs a synchronous "ShowPopup" method that shows a popup, runs an event loop until it's finished and automatically cancels when clicking outside the popup or pressing escape. Keyboard, mouse and scroll wheel events need to be dispatched to the popup but other events (paint, draw, timers etc...) need to be dispatched to their regular targets while the loop runs.
Edit: for clarification, by popup, I mean this kind of menu style popup window, not an alert/dialog etc...
On Windows I've implemented this fairly simply by calling GetMessage/DispatchMessage and filtering and dispatching messages as appropriate. Works fine.
I've much less experience with Cocoa/OS X however and finding the whole event loop/dispatch paradigm a bit confusing. I've seen the following article which explains how to implement a mouse tracking loop which is very similar to what I need:
http://stpeterandpaul.ca/tiger/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/chapter_5_section_4.html
but... there's some things about this that concern me.
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and timers might not fire". Might not? Why not, when not, how to make sure they do?
The docs for nextEventMatchingMask:untilDate:inMode:dequeue: states "events that do not match one of the specified event types are left in the queue.". That seems a little odd. Does this mean that if an event loop only asks for mouse events then any pressed keys will be processed once the loop finishes? That'd be weird.
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close the popup when it's clicked outside, but leaves the click event in the queue so that clicking outside the popup on a another button doesn't require a second click.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in NSApplication run loop does.
Another way of putting all this... what's the Cocoa equivalent of Windows' PeekMessage(..., PM_REMOVE), PeekMessage(..., PM_NOREMOVE) and DispatchMessage().
Any help greatly appreciated.
What exactly is a "popup" as you're using the term? That term means different things in different GUI APIs. Is it just a modal dialog window?
Update for edits to question:
It seems you just want to implement a custom menu. Apple provides a sample project, CustomMenus, which illustrates that technique. It's a companion to one of the WWDC 2010 session videos, Session 145, "Key Event Handling in Cocoa Applications".
Depending on exactly what you need to achieve, you might want to use an NSAlert. Alternatively, you can use a custom window and just run it modally using the -runModalForWindow: method of NSApplication.
To meet your requirement of ending the modal session when the user clicks outside of the window, you could use a local event monitor. There's even an example of just such functionality in the (modern, current) Cocoa Event Handling Guide: Monitoring Events.
All of that said, here are (hopefully no longer relevant) answers to your specific questions:
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and
timers might not fire". Might not? Why not, when not, how to make
sure they do?
Because timers are scheduled in a particular run loop mode or set of modes. See the answer to question 4, below. You would typically use the event-tracking mode when running an event-tracking loop, so timers which are not scheduled in that mode will not run.
You could use the default mode for your event-tracking loop, but it really isn't a good idea. It might cause unexpected re-entrancy.
Assuming your pop-up is similar to a modal window, you should probably use NSModalPanelRunLoopMode.
The docs for nextEventMatchingMask:untilDate:inMode:dequeue:
states "events that do not match one of the specified event types are
left in the queue.". That seems a little odd. Does this mean that if
an event loop only asks for mouse events then any pressed keys will be
processed once the loop finishes? That'd be weird.
Yes, that's what it means. It's up to you to prevent that weird outcome. If you were to read a version of the Cocoa Event Handling Guide from this decade, you'd find there's a section on how to deal with this. ;-P
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close
the popup when it's clicked outside, but leaves the click event in the
queue so that clicking outside the popup on a another button doesn't
require a second click.
Yes. Did you notice the "dequeue:" parameter of nextEventMatchingMask:untilDate:inMode:dequeue:? If you pass NO for that, then the event is left in the queue.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
It's hard to know what to tell you without knowing what you're confused about and how the Apple guide failed you.
Are you familiar with handling multiple asynchronous communication channels using a loop around select(), poll(), epoll(), or kevent()? It's kind of like that, but a bit more automated. Not only do you build a data structure which lists the input sources you want to monitor and what specific events on those input sources you're interested in, but each input source also has a callback associated with it. Running the run loop is like calling one of the above functions to wait for input but also, when input arrives, calling the callback associated with the source to handle that input. You can run a single turn of that loop, run it until a specific time, or even run it indefinitely.
With run loops, the input sources can be organized into sets. The sets are called "modes" and identified by name (i.e. a string). When you run a run loop, you specify which set of input sources it should monitor by specifying which mode it should run in. The other input sources are still known to the run loop, but just ignored temporarily.
The -nextEventMatchingMask:untilDate:inMode:dequeue: method is, more or less, running the thread's run loop internally. In addition to whatever input sources were already present in the run loop, it temporarily adds an input source to monitor events from the windowing system, including mouse and key events.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in
NSApplication run loop does.
There's old Apple sample code, which is actually their implementation of GLUT. It provides a subclass of NSApplication and overrides the -run method. When you strip away some stuff that's only relevant for application start-up or GLUT, it's pretty simple. It's just a loop around -nextEventMatchingMask:... and -sendEvent:.
I am trying to measure UI elements but don't want to add them to the visual tree. Is there ANY way that I can do this without dispatching to the UI thread?
For example - I have some code that needs to know how big a button with the text "Foo Button" in it with a certain font size, padding, etc. The kicker is, once I know the theortical size of that Button, I don't need it anymore.
Anytime I even try to create an instance of a Button (or any UIElement for that matter) I get a thread access exception.
My guess is there's no way around this but I'm really hoping I'm wrong!
I'm writing an extension for VS2010 that reorders a page of code by rearranging code sections and inserting #regions.
I want to be able to code in a call to the "Edit.CollapseToDefinitions" command after I've completed my text manipulations. I can invoke this command in the Visual Studio model by calling ExecuteCommand on my DTE2 object.
However, if I invoke the command immediately after moving my text around the document VS hasn't had time to update its outlining record. So, I want to be able to hook up to outlining events on the current Text Editor window. Does anyone know how to do this?
There's no great way to do it. You can listen for outlining region change events on the IOutliningManager (retrieved by [Import]ing an IOutliningManagerService), but there are no guarantees that the first event will be the one in which the language service re-introduces all the outlining regions it can. Most languages do it on the VS idle loop, but still at some delay so that it doesn't interrupt slow typing.
I would try playing around with something like:
Complete your text edits
Call collapse to definitions
Subscribe to IOutliningManager.RegionsChanged
If the next event is raised in, say, the next 5 seconds, call collapse to definitions again.
Base question: TStatusBar flickers when calling Update procedure. Ways to painlessly fix this
The executed code is in the questions first posts first part ( you can see light grey separating line ) ...
But - problem is that while this code is executed, form does not automatically activate and focus on the top of all other applications.
I have read these articles:
http://www.installationexcellence.com/articles/VistaWithDelphi/Original/Index.html
http://delphi.about.com/od/formsdialogs/l/aa073101b.htm
but according to them it should be working no matter what. I tried all the TApplicationEvents and TForm events with Show; Visible: Repaint; Refresh; BringToFront; ... nothing works.
So - I think I have two options - multithreading or trapping WM_SYSCOMMAND message and in the SC_ACTIVE event simply repaint form. Could this scenario become successful?
None of your linked articles deal with the problem you are having. What you see is the behaviour of a program that does not process Windows messages, so consequently it will not redraw parts that become invalid, and it will not react to keyboard or mouse input (for example moving or resizing with the mouse, or app activation using the taskbar button).
In your code you call StatusBar1.Update, so at least the status bar text is redrawn, but apart from coming to the foreground your application is probably also ignoring move or resize requests.
You need to process Windows messages in a timely manner, so any execution path that takes more than say 200 or 300 milliseconds needs to make sure that messages are handled, otherwise the application will appear unresponsive or hung.
You have basically three options:
Keep the long running code, and insert calls to Application.ProcessMessages - this will allow Windows messages to be processed. Make sure that you keep the code from being entered again, for instance by disabling all the controls that are used to start the operation.
Rework your code in a way that it appears as a sequence of steps, each taking no more than a few 10 milliseconds. Put calls to the code in a timer event handler, or call it from the Application.OnIdle handler.
Call your code in a worker thread, and post messages to the main GUI thread to update your UI.
All these options have their own pros and cons, and for multithreading especially there is a lot of questions and answers already here on SO. It is the most difficult but best option overall when you are working on anything more than a toy program.
I have two processes which exange messages each other.
Process A is a normal (i.e non-qt) program which sends messages to process B.
Process B is a QT GUI application showing received messages into a text box.
I created a customized widget (called ShowMessages) which inherits from QPlainTextEdit and reads messages from a pipe when a timer expires, and appends them in the text box.
Code is not really designed like this (which would be pretty bad design I think), but it's just to make things simple here.
For reasons I won't tell, process A cannot be shut down while I'm creating the form using qt-designer.
Problem is that while I'm using qt designer (thus selecting the ShowMessages widget and putting it within the window) the widget begins to show messages, even if I'm in the designer. This feature is cool but the problem is that when I save the form, already present messages are saved in .ui file, which results in turn in bad behaviour when I start process B (because process starts showing messages I received during the creation phase).
I could clean the text box just after process B starts, but I think that avoiding messages to be present in the .ui file is much better. What I want is to be able to write code like this for the widget:
if <I'm not in the designer>
timer = QtCore.QTimer(self)
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self, QtCore.SLOT("on_timer()"));
timer.start(2000)
Is there an qt function to know if I'm in the designer? Do you think that distinguishing between designer and runtime code is "bad"?
(Sorry for mistakes, but English is not my primary language)
Maybe your widget should have a flag for whether it's "active" and default it to False so while you're in the designer, it doesn't do anything at all. In code you would set it to active when you want to see the messages. Then you also have the ability to turn it off in other scenarios as well.
But I have to say, it sounds like you're putting "controller" code into a "view" widget which can and probably will spell trouble for you down the road (including the current Qt designer problem you're having now).
Consider reading up on the MVC (model-view-controller) design pattern, if you haven't already.
Update:
To be fair, your question did ask how to detect whether you're in designer :)
http://doc.trolltech.com/4.3/designer-creating-custom-widgets.html#creating-well-behaved-widgets
To give custom widgets special
behavior in Qt Designer, provide an
implementation of the initialize()
function to configure the widget
construction process for Qt Designer
specific behavior. This function will
be called for the first time before
any calls to createWidget() and could
perhaps set an internal flag that can
be tested later when Qt Designer calls
the plugin's createWidget() function.
According to the doc, you basically could set your "inDesignerFlag" to true in the initialize() function of your widget. Then detect that flag where required in your widget's code.