I tried to find answer, but I didn't find it.
I want to do something like this:
when I click button, I would like it to repeat actions till another button is clicked
I have something like this:
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
if(pole!=NULL){
pole->przesun_lidera(pole->wladca);
pole->rozstaw();
pole->rysuj_plansze();
}
}
and I want to repeat actions within "if", until I click another button.
Could someone tell me, how can I achieve this?
I think you have two possibilities here. One is to make a thread and execute your code in it until a condition, set by another button is set. Another possibility is to allow the message pump to process messages while inside the loop, by calling ProcessMessages(), e.g.
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
condition = false;
while( !condition && pole!=NULL){
pole->przesun_lidera(pole->wladca);
pole->rozstaw();
pole->rysuj_plansze();
Application->ProcessMessages();
Sleep(1); // don't be a processor hog
}
}
void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{
condition = true;
}
You will need to have a function that is executed in the "background".
Windows is an event driven system. Your functions are only activated when Windows receives an event. My understanding is that you want something to happen while waiting for a specific event (button press) to occur. This time between events is "background" time.
One idea is to have Windows execute your function while it is waiting. Search the web for "Windows spin wait". This will give you information on how to "hook" a function to the background or spin-wait loop.
You may also want to create another thread as a background task. Have your first button click turn on the background thread. The background thread will execute until a semaphore or wait-object is set. The second button press will set this semaphore / wait-object, informing the background task to stop. There are similar methods, but this is the foundation of the issue.
Related
I have a button with function onClicked. There is a C++ class Middle with function search_connection connected via qmlRegisterType.
What I want to do is to change the text of searchButton while the C++ function is calculating the return value and also disable the button for that time.
What happens is nothing. The button is enabled for the whole time with text "Search". I believe that what actually happens is, that search_connection function is executed first and than all the rest happens so fast I can't notice the change from "Search" to "Searching..." and back again.
TextField {
id: startStop
}
TextField {
id: finishStop
}
Button {
id: searchButton
text: qsTr("Search")
onClicked: {
text = qsTr("Searching...")
enabled = false;
searchResult.text = middle.search_connection(startStop.text,finishStop.text)
enabled = true;
text = qsTr("Search")
}
}
Does anyone know how to make the Qt to call the function after it changes the text to "Searching..."?
Your UI will repaint certain areas with the next call of the event loop. This never happen in your case, because the slot (your function) is called directly and blocks the application until it is finished. There are a few ways to avoid that blocking:
Move your task to another thread (QThread) and wait until finish
Start your task with an timer (QML-Timer). You can redraw the button before starting the method, but your GUI will still block until the method has finished (the change of enabled will be useless).
Call processEvents() within your method multiple times (not recommended, can cause problems).
If the method needs some time, I would use a new thread. So your gui isn't blocking and your button wil still receive events (painting, mouse, ...).
Edit 1:
If your C++-Code is simple and can be translated to JavaScript-Code, you can also use WorkerScript. It's the QML-Version of QThread. But it has some limitations. You can only use JavaScript and you can't interact with the Worker while running.
Thanks to folibis for the suggestion.
I am programming a GUI with wxWidgets. I got a button to open a serial port and receive data. In there is a while(1) loop to constantly receive the data.
Now I want to do a "Disconnect" button to stop receiving.
Is there an event handler or a callback function to interrupt the while and jump out of the loop from the first button, when I press another button?
A wxButton sends a message when it is clicked. Create a handler for this message where you do your "interrruption".
Now, a loop can be only exited from its inner guts. I mean, inside the loop you should check a flag, and depending on the value of this flag continue or exit.
My advice is that you create a worker thread. When the button "connect" is clicked then you create the thread that receives data.
This thread checks an extern flag and finishes depending on the value of the flag.
The "disconnect" button click-handler just sets that extern flag to a value that makes the thread exits when it checks that flag.
Take a look at the thread sample provided with wxWidgets sources.
If you have a while(1) loop in the callback function for "button pressed", you will hang the UI. Callback functions must return quickly.
The quickest solution is to put the while(1) loop into a worker thread. That way your GUI won't hang.
The next problem is how to stop the loop. That's quite easy. Change the loop into:
while (keep_going.load()) {
....
where keep_going is of type std::atomic_bool. Then your "stop" button just calls keep_going.store(false).
Basically exactly what the title says. I would like to update the text that a button contains every 1 second when the user presses that particular button. I have noted that when the program doesn't have focus it works alright and the text refreshes correctly but when I am hovering over the program or when I am trying to click on it's menu Windows inform me that the program is unresponsive and asks me if I want it terminated. When the loop finishes the program returns to its normal state. Also any action I might have done (like moving it around or closing it) while it was Sleep()-ing is executed after the loop. Here is a bit of code:
case ID_BUTTON_START:
// Code executed when pressing Start Button.
char startButtonText[30]; // Storing next loop text
for (int i=5; i>0; i--)
{
sprintf(startButtonText, "Starting in ... %d", i);
SendMessage(hwndButtonStart, WM_SETTEXT, 0, (LPARAM)(startButtonText));
Sleep(1000);
}
Is this normal? If not what's causing this?
The WndProc does not process messages asynchronously within an application which means all messages are expected to be handled quickly and a return value delivered immediately. You must not Sleep in the UI thread since it will block other UI events from being processed. Any heavy work or synchronous requests/jobs which are likely to take a long time should be performed in worker threads. There are at least three viable options:
Create a new (worker thread) for the task.
If the task is likely to be done often, use a thread pool instead.
Set and subscribe to timer events.
I think the call to Sleep() might be keeping you from returning from the WndProc, so your application is not processing the incomming events for 5 secs. I suggest you try to subscribe to 5 timer events in 1s, 2s,..., 5s. Like when the timer message is recieved the button text must change. I don't know a way how to do that off the top of my head.
I'm using c++ builder (bcb6) and on:
FormShow
event there is:
Application->ProcessMessages
I would like to know what exactly the responsibility of:
Application->ProcessMessages
What exactly it did? and when we shall use by that? when it can cause exp.?
Thanks!
The BDS 2006 IDE help states for Application->ProcessMessages this:
Interrupts the execution of an application so that it can process the message queue.
Call ProcessMessages to permit the application to process messages that are currently in the message queue. ProcessMessages cycles the Windows message loop until it is empty, and then returns control to the application.
Neglecting message processing affects only the application calling ProcessMessages, not other applications. In lengthy operations, calling ProcessMessages periodically allows the application to respond to paint and other messages.
ProcessMessages does not allow the application to go idle, whereas HandleMessage does.
so what for it is?
It allows to respond to Windows messages in case your app is blocking normal WindProc operation (inside VCL). For example if you got some lengthy computation on some event that takes minutes the application would freeze (can not click,move,resize,redraw,... until operation is done). If you once in a time call ProcessMessages from that long loop (timers would also not work during that time) that will allow to make your app responsive during this time... so it will not freeze.
I usually use threads or OnIdle event instead for such computations so the main App is not blocked at all.
I am reluctant to believe that OnShow is called during such blocking. I would place the ProcessMessages inside the computation that blocks the App (if the computations is inside the OnShow then it is OK otherwise it would be useless. Anyway OnShow is called only if your Form is turning to Visible do not mistake it for OnActivate or OnPaint.
small example
Create empty form app and place 2 buttons in it (btStart,btStop) then create on click event for them as following:
//---------------------------------------------------------------------------
bool go=false;
//---------------------------------------------------------------------------
void __fastcall TForm1::btStartClick(TObject *Sender)
{
int i=0;
for (go=true;go;)
{
Caption=i; i++;
Application->ProcessMessages();
Sleep(100);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btStopClick(TObject *Sender)
{
go=false;
}
//---------------------------------------------------------------------------
When you start app and click btStart it will start incrementing integer in Caption field of the Form1 and stop when you click btStop. during counting the App is still responsive (can click,move,resize,...). You need to stop before closing App is possible (destructors wait for returning from all events). if you rem out the Application->ProcessMessages(); then the App will count but will never stop because you can not click on btStop due to the freeze. To close click on the IDE and press CTRL+F2.
Hope it clears things a bit.
I need a wait cursor to be loaded when the second page OnWizardNext of a property sheet is clicked .This is how I had done.Actually I designed a property sheet and now when I Click on the Next button I had activated the hourglass ,till this point everything works fine ,here arises the actual problem i.e,during that wait cursor period if I click again on Next button the dialog is getting dismissed .So,my intention is even if I click Next during the wait cursor it should not react to the click event.
LResult OnWizardNext()
{
CWaitCursor wait_cursor();
Sleep(10000);
return CPropertyPage::OnWizardNext()
}
if I remove Sleep then no wait cursor is getting loaded.What I need is even though if click on any button anything the event for that button should not get triggered until unless i am out of sleep time.
Can anyone please let me know how to achieve this.
I think you have a problem with the design of your wizard. You should not be using "Sleep" as it will suspend the thread. Moreover, the wait cursor is nothing more than a UI mechanism to indicate to the user that the code is still active. You seem to want to use that as a determinant for when your code can continue. Take a look at using OnSetCursor to provide visual feedback. Depending on what it is you're waiting on, you may want to look at using a timer, or, perhaps a series of "flags" to indicate a "continue" condition.