A blocking but non-modal QDialog? - c++

I have a stack of images on which I want to perform some operations. After processing each image, my program should pop up a dialog to prompt the user if they want to proceed with the next image or to abort. Before that, they should have an opportunity to do some manual changes either on the images or on the parameters. Anyway, they must have access to the windows of the applications, while the execution of the method that called the dialog should be blocked until the dialog is closed.
I tried to solve this with a QMessageBox, but if I open it via exec(), it blocks the entire application, and if I use show(), the execution of the program goes on without waiting for user's reaction.
Is there a convenient way to block the calling method or function with a dialog but permit the user to interact with other windows?
Thanks in advance for any hint.

You should split your method that you want to block into two parts. In the end of first part you need to show your dialog without blocking and connect "Next" button (for example) of the dialog to the slot that must contains second part of your old method. This slot will be executed only when user presses the button.
It's the right way to do it in Qt. You need posibly to change your code logic to implement this.
Also, do you really need the second dialog? You can place "Next" button to your main widget. You can also create another modal dialog that will contain some settings and "Next" button.

Related

Display and use the same MFC CList control in multiple dialogs

I am coding a test application for a windows CE device. This is the first time I am programming for a handheld device. I use MFC VC++ on Visual Studio 2008. I have found that there are many restrictions in the controls and what I could do with them when running the program on a handy versus when I run a similar program on a desktop computer.
Now, the device I am currently deploying my test program to, does not have a touchscreen and has few extra keys other that the numberpad 0-9 keys. So, I have to do with a simple GUI that uses keydowns to call specific functions like add, edit, delete etc... It also forces me to use separate dialogs for each of these functions so as to avoid unnecessary mouse cursor usage.
This leads me to my current problem: The 'ADD' dialog of my test app adds some user data to a CListCtrl that is on the 'MAIN' dialog. The 'EDIT/DELETE' dialog is to allow the user to select the desired data from its own CListCtrl and press the "ENTER" key, which thereby deletes the selected data from the 'MAIN' dialog's CListCtrl. Thus, both the main dialog and the 'EDIT/DELETE' dialog have CListCtrl with the exact same data. So, instead of having to use 2 separate list controls and using loops to copy the data to and fro among them, is there a way in which i could use the exact same CListCtrl (one and only one instance of the CListCtrl exists), but display it on 2 separate dialogs? This would remove all the copying code, as well as halve the amount of data in memory.
I tried passing a pointer to the MAIN dialog's CListCtrl to the 'EDIT/DELETE' dialog in hopes that I could redraw the control there, but in vain. I could call the RedrawWindow, RedrawItems commands, but they seem to have no effect in the 'EDIT/DELETE' dialog (I think it is because the control itself is not present on the edit/delete dialog). Any other suggestions?
You could temporarily change the parent of the ListCtrl using CWnd::SetParent to the EDIT/DELETE dialog, and set the position with CWnd::SetWindowPos to where you want to have it. When the dialog gets closed, set the parent back to the MAIN dialog.

C++ Modal dialog box continuing adding texts

I have dialog box and in it, it has OK and Cancel buttons then it also has a ListBox to display text in two columns. I would like to continue adding text into the ListBox after the dialog box is shown. How can I do that? Because after I call DoModal() to show the dialog box, the code does not continue to execute. Or should I create two threads (one is display dialog box while another thread continues adding text to dialog box)?
Make your dialog 'pull' the data it needs, maybe polling the data source with window messages every second, or every 100ms or so. Or, if you go the 'two threads' route (the better but more complicated option), have your data source post a window message to your dialog when there is new data, and then have the dialog fetch the data it needs. The reason for this is that it's much easier to use the existing CDialog infrastructure to get a window that behaves like an actual dialog, compared to building a modal window that acts like a dialog but isn't really.
If you do go the two threads route, your division of labor should be: one thread that does all the UI work (including showing the dialog), and one that 'generates' data and lets the UI know when there is new data. So the worker thread should not do anything related to the UI, nor call any methods on the dialog directly - you can't access windows from several threads. The only cross-thread window communication should happen through window message (i.e., use ::SendMessage()). So certainly don't do something like myDialog->m_theList.AddString("blah") from another thread, or something like it.
Showing a dialog box modally halts further execution until you close the box. Instead of showing it modal, show it normal but make it always on top so you can continue executing the code after the call to DoModal(). Alternatively, populate the box with all the info it will need before you call DoModal().
If you decide to take the "two threads" approach you will discover that the controls on MFC dialogs should not be updated or accessed from a thread other than the one that created the dialog. Even if you have pointers to these controls available in another thread it is not thread-safe to access them. This rule applies whether or not the dialog is modal.
Instead, your second thread would need to PostMessage or SendMessage to the dialog window, so the updates occur on the thread that created the dialog (most likely the main UI thread of the application).

How to sync a Progress Control with a set of data which is loading in a Dialog Box in Visual C++

I'm trying to add a progress control in my dialogs, that will step upon every iteration of a loop until completion. I've never played around with progress controls before, so I'm totally clueless as to where I should start. I've added a progress control resource view into my dialog, but it just shows up as an empty progress control. I'd like to have the progress control dynamically appear/update when after pressing a button an image from somewhere stars being loaded.
I am trying to add a progress control on a dialog box in Visual c++ environment.
After adding this tool the following code added to main.cpp :
void CPanoramicsampleDlg::OnNMCustomdrawProgress1(NMHDR *pNMHDR, LRESULT *pResult){
}
I can show procedure of loading in a Text control as follow:
sprintf_s(pack1,"Data%d%%",Event);
::SetWindowText(GetDlgItem(IDC_Static)->m_hWnd,pack1);
so in this way I can see loading process as %d in a text window but I don't know how to show loading procedure by progress control and how and where to define range or even progress bar handle for this progress control so on.
finally I would like to know is there any function for progress control for example:
::EnableWindow(GetDlgItem(IDC_Progress1)->m_hWnd);
You should first add a variable for the control, by right-clicking on the progress bar in the dialog editor, and choosing Add Variable... Your dialog class will then have an instance of a CProgressCtrl class on which you can then call the members that IInspectable has mentioned in his answer. Delete the OnNMCustomdrawProgress1 handler, you don't need it.
e.g.
m_progressCtrl.EnableWindow(TRUE);
m_progressCtrl.SetRange(0, 100);
m_progressCtrl.SetPos(75);
Then whatever that eventParam1 value is that you mention, proportion it between your start and stop value, and call SetPos with it.
Update after comment:
Do the SetRange() in the OnInitDialog() function. If you don't already have an OnInitDialog you need to override it, follow the instructions in the accepted answer of this question to do it.
VS 2008, MFC: add OnInitDialog - how?
As for where you put the SetPos(): You describe that you can already track loading progress in a text control using some or other eventParam1. That sounds like a handler or callback from what ever loading you're doing, and that is where you will instead SetPos() on the progress bar instance.
The CProgressCtrl Class provides the following members that you will have to use:
CProgressCtrl::SetRange: Allows you to set lower and upper bound. These values ideally reflect your starting state and finishing condition.
CProgressCtrl::SetPos: Used to update the current position. You would update the current position where you used to output progress in your edit control.
As an alternative to calling CProgressCtrl::SetPos with an explicit position value, you can set a step increment, calling CProgressCtrl::SetStep, and update the control with a call to CProgressCtrl::StepIt. If you know the step increment ahead of time, this is an easier way to go about updating the current position.
Additional information is available at the MSDN: Using CProgressCtrl.

Interpreting QCloseEvent differently

I have a desktop windows application programmed in C++ with Qt. The application has several top - level windows which occasionally need to be closed and recreated programmatically. Also, when the user of the program clicks on the close button (the one next to the minimize and maximize buttons) the whole program is supposed to exit.
The problem I have is that in both cases the top level windows receive a closeEvent() call with a QCloseEvent object. I'd like to quit the program when I see that happen (because the user might have clicked the close button), but it's also possible that the window is closing because I'm deleting it programmatically to recreate it.
Is there a way of distinguishing between these two cases in QMainWindow::closeEvent()?
Is there a way of distinguishing between these two cases in QMainWindow::closeEvent()?
Yes: the close event triggered by the user clicking on the window's close button will be a spontaneous event, the one triggered by you calling window->close() will not. See the documentation of QEvent::spontaneous() for more information.
When you need to close your window programmatically, use deleteLater() instead of close. The window will be closed and deleted. To reopen the window you will need to create another window object.
You can also use hide() method. The window will be hidden but not destroyed. It can be shown again using show().
In both described cases the close event does not happen and closeEvent() isn't called. So when closeEvent is called, you know that the user has pressed the close button.

Best approach to retrieve values from a QML Modal dialog

In my QT C++ application i call a QML ModalDialog with 2 buttons (OK/CANCEL), which displays correctly on screen and so, no problem there.
However i'm struggling to find a way to retrieve in my QT C++ application which button was pressed.
I'm unable to somehow "freeze" when i call the QML ModalDialog, to wait there until the user press OK Button or Cancel Button
What i see is that application calls the QML ModalDialog, and immediately exit that part and continue.
QMetaObject::invokeMethod can call a QML function and have a return value, but it just doesn't wait for the user press one of the buttons, it just exits immediately, so no use.
I want to use this QML ModalDialog in several places of my application (the QML modal
dialog can have different text passed from my QT C++ application), so i was looking to a generic solution for this.
Basically and generic speaking i'm looking for something like this:
C/C++
return_value = QML_Modal_Dialog(....)
Can someone point me in the right direction? Thanks
QML modal dialog comes with two signals 'accepted' and 'cancelled'. If you provide handlers for these two signals in your code, you would be able to know which button got pressed.
You can refer to the below for reference.
Modal Dialog Ref 1
Modal Dialog Ref 2
Hope this helps!
Despite that the question is too old maybe my answer will help someone else.
I faced the same problem with Dialogs in QML. You think about it in imperative way, while QML is a declarative language that doesn't allow you to stop the flow of program and wait for the user's choice.
As Purnima suggested you should use signal handlers (you can find the list of them for Qt 5.6 here). Move some of your app's logic to the signal
handlers.
For example - if your function a() is executed based on the user's choice in dialog you should instead call it inside the dialog in its signal handlers (e.g. onAccepted or onRejected) with two different parameters based on the type of signal handler. Think about it as splitting the flow in two streams.