Progress Bar doesn't move - c++

I need such logic:
ShowProgressBar();
Sleep(1000); //---> do here some work
HideProgressBar();
MessageBoxW(_T("Wait"), _T("Title"), MB_OK);
ShowProgressBar();
Sleep(1000); //---> do here some work
HideProgressBar();
I call this code in separate thread (not main GUI thread). I got normal dialog window but it's progress bar is immobilized:
Then:
And then:
This is ShowProgressBar function:
progressBarWindow = new Progress(this);
if (!progressBarWindow->Create(IDD_PROGRESSBAR, this))
{
AfxMessageBox(TEXT("BAD PROGRESS BAR"));
return;
}
if(!progressBarWindow->ShowWindow(SW_SHOWNA))
{
AfxMessageBox(TEXT("BAD PROGRESS BAR"));
return;
}
this->BeginModalState();
This is HideProgressBar implementation:
progressBarWindow->EndDialog(0);
this->EndModalState();
Progress - is a class of Progress Bar dialog window. It is absolutely standart, has progress bar element with marque setting:
m_ProgressBar.SetMarquee(TRUE, 10)
in OnInitDialog function

Windows have thread affinity.
You’re calling progressBarWindow->Create() on a background thread. The progress bar now lives in your background thread, and expects the thread to have a message pump.
It doesn’t matter it’s parent window belongs to another thread, Windows is OK doing multi-threaded GUI. However you’re not OK. You’re sleeping with Sleep(1000), so the thread ain’t processing windows messages. I think that’s why no GUI updates in your app.
For most applications, the right way to do threading — do all the GUI in the main thread. Even progress bars logically related to the background threads should still be created in the main GUI thread.
To fix, create all your GUI in the main GUI thread, and only use your separate thread for computations, or IO, or whatever else your work is.
P.S. If your next question going to be “But how to notify the GUI thread when my background thread needs to change progress, or completes its job?” — one method is custom windows messages.
For example, you can send WM_USER + 11 to some window (e.g. to your Progress dialog) when your thread finishes the processing, and WM_USER + 12 when your thread needs to update the progress bar position, passing progress position in lParam or wParam. The message handler will be called in the main thread, where you can update progress, or close the progress popup, or do anything else with your GUI.

Related

Will UI block when waiting for QThread / How to use QThread properly

If I have a progressbar in the ui thread (window), which shall run endless until a method finishes it's work, will the ui thread block and so the progress bar if I'm waiting for a second QThread to finish? If the ui thread blocks waiting, then i would not to wait for the second thread. I thought to implement a callback method which will be called when the second thread finished, but then: How can i connect to the callback method?
What do I want to do?
I have a window, this window has a progressbar which is first not visible. When the user presses a certain button to request data, a method will be called which returns a RequestPointer which contains a method which returns the request status.
When the user presses the button, i want to make the progress bar visible, running infinitely till the request is finished and i can print the data to the window.
To the Worker i want to pass this pointer and the worker checks in a while (flag) loop, if the status is still running and sleep if so. When the worker finishes, i want to stop the progressbar and make it unvisible again. Do i have to pass the progress bar to the thread, or can i wait for the thread without blocking the ui?
I'm not quite a Qt pro. Really new to it. I tried to get some info from the https://doc.qt.io/Qt-5/qthread.html website, but it's a bit hard for me to understand the code example.
Method in my worker class:
void Worker::watchRequest(RequestPtr r_ptr)
{
bool exit = true;
while (!exit)
{
ErrorCode errorCode = r_ptr->Test();
switch (errorCode)
{
case Request_RUNNING:
QThread::msleep(10);
break;
case Request_ABORTED:
exit = true;
break;
case Request_SUCCESS:
exit = true;
break;
}
}
QThread has a finished signal. Connect this one to some appropriate slot, which will trigger any action necessary on thread completion.
I suppose best candidate to know how far the progress went is the worker thread itself. You might create your own signal that sends the current progress to some slot that will do the update of the progress bar appropriately.
Alternatively, you might use a QTimer to read the current progress from time to time (this resembles closer to what you have now, but does not block the UI).
If you don't want to block the user interface, all you have to do is to call QApplication::processEvents(); in your while-loop.
I have some code which uses std::future instead of QThread and my code looks like this:
while (!progressIndicator->UserBreak()
&& (future.wait_for(std::chrono::seconds(0)) != std::future_status::ready))
{
QApplication::processEvents();
}
This works well.
To update the UI Thread's progress bar while the operation is running, use a QTimer object to increment the progress bar's value (Max value will be :One less than Progress bar's value when the operation completes). Also connect the QThread to a slot by Signal/Slot method to signal the UI thread when the operation has ended. When the QThread finishes the operation, send a signal to a Slot in the UI Thread, which will set the final value of the progress bar and also stop the QTimer.

How to make a thread in MFC for moving slider control with respect to audio file that is being played?

I was able to move SliderControl according to the position using CSliderCtrl::GetPos , being played by the program. (This is a part of my Music Player MFC project).
But I need to do this automatically without any notification/events ....
I thought of creating a thread that will move slider after clicking on play button.
You generally want to have exactly one thread updating the UI (and doing as little else as possible).
It would almost certainly work better to have a secondary thread playing the music. It can send a message to the UI thread, and the UI thread updates the slider control position when it receives that message.
It is always good to update the UI from the main thread instead of adding a new thread for updating UI. Better you can perform your background tasks by using a worker thread and update the UI by sending a message to the main thread when ever required.
In your case, you can have a worker thread to play the music and send a message to the main thread to update the slider position.
::SendMessage( AfxGetMainWnd()->m_hWnd, Message_Id, ( WPARAM )&String, 0 );
You can use the APIs CSliderCtrl::SetPos() to update the position.

Displaying window from ui-thread sometimes blocks the main ui-thread

I am not an MFC expert, and definately not a multithread expert but still, I want to understand this strange behavior. At some places when I create an MFC ui thread in my application it is started and can display a messagebox no problem, with the main ui thread blocked. However sometimes if I create the thread, then the thread execution stops until the main ui thread non-blocked again.
Of course the situation is made up. The main ui thread's blocking, symbolizes some kind of synchronisation, while the ui thread's messagebox symbolizes some more complex ui dialog.
This is more of a theoretical question. I am primary interested in the reason why this could happen? Here is an example :
class MessageBoxThread : public CWinThread
{
DECLARE_DYNCREATE( MessageBoxThread );
public:
virtual BOOL InitInstance()
{
CWinThread::InitInstance();
AfxMessageBox(_T("Some text"));
return TRUE;
}
};
IMPLEMENT_DYNCREATE( MessageBoxThread , CWinThread );
void testing()
{
MessageBoxThread* pMessageBoxThread = new MessageBoxThread ();
pMessageBoxThread->CreateThread();
Sleep(10000);
AfxMessageBox(_T("It Worked!"));
}
So in terms of the example, if I put 'testing' function into CWinApp::InitInstance it is working as expected (showing 'Some text' first then after 10 sec showing 'It Worked!'). However if I put it into a random place deep inside my application, it might happen that the two messageboxes appear at the same time after the 10 sec sleep. What could cause such behavior?
I am not an MFC fan, but knowing Win32 I can see what is happening. By putting it "deep" you probably mean calling the testing() function in some window message processing code - a code that runs on the main UI thread and processes pumped messages. So you are putting your UI thread to sleep which in this case is similar to what a message box or a modal dialog would do. So, your message pump (implemented in CWinApp I think) is blocked by this Sleep() waiting you to complete processing the message in response to which your code is executed (does not matter what message).
Okay, I finally found the answer. When someone creates a ui thread, that person must initialize the m_pMainWnd member which contains the ui threads base window. If you fail to do so, the framework will use the application provided main window, which is the one in the main ui thread. Since that one is blocked because of the Sleep() method, the other ui thread will only respond when the main thread is not blocked.

How do I create Modal dialog in worker thread(Non-UI thread)?

I have written a sample MFC application in which there are two threads:
-Main thread ( UI thread)
-Worker thread ( non-UI thread)
I have a specific requirement to create a Modal dialog in Non-UI ( worker thread).
When I create the CDialog object and call DoModal on the same, it works. The dialog gets created and acts as Modal to the application. ( Win XP SP2 machine) But this does not work in Windows 2003 server machine.
The behavior in 2003 server is that, the Modal Dialog goes behind the application main Window and dialog will be brought to front only when I click on Main Window. It is not acting as Modal dialog to my application.
What could be the problem -- any ideas?
If creating UI controls in non-UI thread is the issue then is there any Win32 API which will allow me to link my worker thread to Main UI thread such that DoModal happens in Main thread. I tried AttachThreadInput but it is not working.
There is no reliable way to spread GUI modality across multiple threads. Every window is represented by an object referenced through a HWND which in turn has thread affinity. This is a left-over from the 16-bit days of Windows, where there was no multi threading. Consequently the HWNDs are not protected against concurrent access. The Old New Thing has an excellent series on "Thread affinity of user interface objects" (Part 1 2 3 Addendum).
Modality is implemented by first enabling the dialog window and then disabling its parent. The first step is safe while the second attempts to disable a window from a thread which is not the window's owning thread. Since en-/disabling windows modifies the object referenced through the HWND it represents a race condition.
The suggested solution is to confine your GUI to a single thread and communicate from your worker thread to the GUI thread to have it perform user interaction on the worker thread's behalf. The easiest way to accomplish this is to call SendMessage from the worker thread to block until the GUI thread's message handler returns. If the worker thread should continue to run while the dialog is displayed you could use PostMessage instead and communicate back to the worker thread using PostThreadMessage or signaling a synchronization object like an Event Object.
First of all, I'd like to agree with other posters that it's probably better to show the dialog on the main UI thread.
However, if you must, you can make a dialog on another thread modal with the following steps:
Pass your active window as an owner when creating the dialog.
When dialog is showing, iterate over your other windows and do them EnableWindow(FALSE). When the dialog is hiding, do the reverse. You will probably have to remember windows' enabled state and restore the original state, not just EnableWindow(TRUE).
Ensure that accelerators and other global commands will be ignored while the dialog is shown.
Note that (2) shouldn't be necessary provided that you do (1), but you've mentioned MFC, and I don't remember exactly how it behaves. It has it's own modal dialog implementation which may not exactly match Win32. If you're lucky, (1) and (3) will be enough.
While i don't know about the specifics of dialog handling on Server 2003, the simplest workaround to get on the main thread would be to use a custom window message, do ::SendMessage() and display the dialog in the message handler.
I recommend you not to do what the question subject suggests, and confine all UI to one thread. If you need the other thread to communicate with the user, create some messaging mechanism that will ask the UI thread to do it, and transport the results back.

MoveWindow deadlock?

I have a window on thread A, which at some point (as a result of a message being received on its wndproc) triggers an action on thread B, and then waits for the action to complete (using some sort of sync mechanism). Thread B then calls MoveWindow(), to move a child window within thread A's window (a standard textbox, for example). At this point the program goes into a state of deadlock for some reason. If MoveWindow() is being called from thread A, everything works. Any ideas why?
You could use SetWindowPos with the flag SWP_ASYNCWINDOWPOS, instead of MoveWindow.
The reason may be that ThreadA waits for ThreadB to handle some event but meanwhile ThreadB wait for ThreadA (the thread owning the window) to return the result of MoveWindow.
What is the "some sort of sync mechanism"? If it is WaitFor(Multiple)Object(s), you can use [MsgWaitForMultipleObjects](http://msdn.microsoft.com/en-us/library/ms684242(VS.85).aspx)(Ex instead to wake up when you have a message and dispatch it as Lucero suggests.
I think that #1800's explanation is the closest yet.
When you move a window from a thread that does not own the window, I think that Windows does not use SendMessage to deliver things like WM_WINDOWPOSCHANGING to the window procedure of the moved window. Instead, to ensure that the window procedure is only called on the right thread, it posts the WM_WINDOWPOSCHANGING message and blocks untill it's picked by event loop running in the right thread. However, that event loop is not running - it's blocked, waiting for MoveWindow to complete.
The solutions from #totaland and from #Logan Capaldo will work.
May be you don't need to wait until your window has moved. Or, if you do need to be sure, use MsgWaitForMultipleObjectsEx and run a small event loop to process posted messages.
You need to make sure that the message pump of the thread is running while you are waiting.
You may want to loop with PeekMessage() (or maybe GetMessage()) and DispatchMessage().
Thread affinity of user interface objects, part 1: Window handles:
Different objects have different
thread affinity rules, but the
underlying principles come from 16-bit
Windows.
The most important user interface
element is of course the window.
Window objects have thread affinity.
The thread that creates a window is
the one with which the window has an
inseparable relationship. Informally,
one says that the thread "owns" the
window. Messages are dispatched to a
window procedure only on the thread
that owns it, and generally speaking,
modifications to a window should be
made only from the thread that owns
it. Although the window manager
permits any thread to access such
things as window properties, styles,
and other attributes such as the
window procedure, and such accesses
are thread safe from the window
manager's point of view,
load-modify-write sequences should
typically be restricted to the owner
thread.