How to show Cdialog with std::async - c++

I have a derive class named A was inheritance from CDialog, I created the object to A named a and want to utilize the member function domodal to show dialog. Nonetheless, this dialog cannot show and parent window was block.
A a(this);
auto DlgResult = std::async(std::launch::async, &A::DoModal,&a);
DlgResult.wait();
if (DlgResult.get() == IDOK)
{
std::wstring ss = a.get_text_fromdlg();
}
Can someone help me, thanks!

If I were you, I wouldn't wrestle w/ the Async and DoModal since the purpose of DoModal() is to wait for the response from the dialog to let the app know how to move forward..
Below, I've added a simpler option. Just create member variable pointer to a Dialog class, and then use Show Window. Also, in this instance, you may consider making the dialog topmost so you don't lose focus of it.
MFCClass1* m_pDlg = new MFCClass1();
void CMFCApplication1Dlg::OnBnClickedButton1()
{
m_pDlg->Create(IDD_DIALOG1);
m_pDlg->ShowWindow(SW_SHOWNORMAL);
SetWindowPos(&m_pDlg->wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

Related

Apply button in CDialog

I have a dialog in which after pressing button OK, the program uses the data in the dialog and draws a plot. I need to draw the plot without having to close the dialog as with IDOK, hence the apply button.
The code with drawing the dialog is,
INT_PTR val = dlg->DoModal();
if ( val == IDOK) {
//draw plot
}
The code of onOK and onApply
void DLg::OnOK() {
GetDataGrid();
CDialog::OnOK();
}
void DLg::OnBnClickedApply()
{
GetDataGrid();
}
How do I get DoModal() to return a value on onApply() without closing the dialog?
Any help would be appreciated.
A modal dialog can't return a value and leave the dialog open. You could either make your dialog non-modal, or post your main window a message from the OnBnClickedApply function that makes it draw the plot.
I tend to put drawing into a separate thread and would call it wherever needed. So you can either
(1) call the OnDrawPlot again in your Apply button
if ( val == IDOK) {
AfxBeginThread(...);//draw plot
}
void DLg::OnBnClickedApply()
{
AfxBeginThread(...);//draw plot
}
(2) send the return value back to the DoModal using EndDialog method
What parameters are there in EndDialog ?
An example can be found here.
Declare a variable in CDialog derived class preferably public. Then just at OnOK assign this variable to appropriate value. The caller would use it directly.
class Dlg : public CDialog
{
public:
int TheVariable;
...
};
Call site:
if(dlg.DoModal()==IDOK)
{
dlg.TheVariable; // Use the variable
}
However, if you need to draw on the dialog itself (and not to other window, which has launched the dialog), then don't call CDialog::OnOK or EndDialog in your OnOK override. In this case, you need to do painting in dialog itself.

Subclassing descendant of VCL TWinControl

Using pseudo funcs for subclassing:
CreateSpecialHandle(TWinControl *Control, const TCreateParams &Params, const AnsiString SubClass)
{
......;
set Control DefWndProc to SubClass.lpfnWndProc
set Control WindowHandle from CreateWindowEx
......;
subclass(TWinControl *Control);
}
subclass(TWinControl *Control)
{
......;
oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
oldDefWProc = (void*)(Control->DefWndProc);
oldWindowProc = Control->WindowProc;
MakeObjectInstance(newWProc) for SetWindowLong
MakeObjectInstance(newDefWProc) for Control->DefWndProc
Control->WindowProc = newWindowProc;
......;
}
Now, we have unexpected behavior of subclassed control.
WM_NCHITTEST result 0, etc...
For example when newWProc intercepts WM_NCHITTEST and sets Result to HTCLIENT
we have mouse response, but, is that not responding without setting msg.result to 1 for msg.msg WM_NCHITTEST consequence of my mistake and wrong subclassing, what else we need to handle manually?
newWProc make callback of oldWProc
newDefWProc make callback of oldDefWProc
newWindowProc calls oldWindowProc
Do we have to subclass parent control of subclassed control as well?
Also, sending WM_GETTEXT results with empty buffer.
Obviously, we are doing something wrong here. We need explanation,
Thank You all in advance
Update:
in TDCEdit:public TCustomEdit overriding CreateWindowHandle
void __fastcal CreateWindowHandle(const TCreateParams &Params)
{
CreateSpecialHandle(this,Params,TEXT("EDIT"));
}
void CreateSpecialHandle(TWinControl *Control,const TCreateParams &Params, AnsiString SubClass)
{
...
Control->WindowHandle = CreateWindowEx(...,"EDIT",....);
....
subclass(Control);
}
subclass(TWinControl* Control)
{
......;
oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
oldDefWProc = (void*)(Control->DefWndProc);
oldWindowProc = Control->WindowProc;
MakeObjectInstance(newWProc) for SetWindowLong
MakeObjectInstance(newDefWProc) for Control->DefWndProc
Control->WindowProc = newWindowProc;
......;
}
Now, when I use TDCEdit and intercept Message.Msg == WM_NCHITTEST
inside newWProc Message.Result is 0 and stay 0 through all message process chain.
Note that subclassing TCustomEdit is one among other controls we need to subclass
in project and we try to use same subclass(TWinControl*) function for all.
Here is part of newWProc with few more lines to focus on problem
void __fastcall TControlWrapper::newWProc(Messages::TMessage &Message)
{
if(Message.Msg == WM_NCHITTEST ) // TEST
if(Message.Result == 0)
Message.Result=1;//<- WHY I NEED TO DO THIS
if( Message.Msg == WM_DESTROY) {
HandleWMDestroy(Message);
return;
}
CallWindowProcW( (int(__stdcall*)())oldWProc,
Handle, Message.Msg, Message.WParam,
Message.LParam);
if(Message.Msg == WM_NCHITTEST )
if(Message.Result == 0)Message.Result=1;//<- OR THIS
}
This is a confusing question - it doesn't help that your code samples are not C++.
set Control DefWndProc to SubClass.lpfnWndProc
is not a line in a C++ function, for example. Can you show your actual code please?
I can make a guess at what you're trying to do: are you trying to subclass a window (perhaps a form?) so that it moves when the mouse is clicked on it? If so, you don't need to do any raw Windows API-style subclassing, the way you appear to be doing with GetWindowLong. In C++ Builder, the VCL is an object-oriented wrapper around the Windows API, and you can do this in one of two much cleaner ways:
Create a new WindowProc and set it; this is a property pointing to a new window procedure, and you simply call the old one too;
Create a descendant class of your TWinControl (if you're using a form, you already have one) and implement the virtual method WndProc.
An example of #1, in Delphi (but you should be easily able to convert it to C++) is in the Embarcadero documentation on subclassing WndProc.
An example of #2, the cleanest OO version, is here, and this actually shows how to do what you're trying to do, too: C++Builder: Create a TForm with BorderStyle bsNone that is nevertheless movable and resizable
Given what you appear to want to do, I would suggest going with #2.

mfc access to formview item from dialog box

In my SDI application i need to get this behawiour. After I click on a button on the FormView, a CDialog opens. When I press the OK button on the CDialog, I call a function of the FormView. I don't want to close the CDialog. I try to do it with modeless dialog, but when i call formview function from dialog, i can't access to formview's control, like it's lost hwnd; the error is can't read memory of m_hwnd, the hwnd is ???.
This is my code:
Open modeless dialog:
CCampiDlg *m_pDialog = NULL;
HWND hCampi = NULL;
// Invoking the Dialog
m_pDialog = new CCampiDlg;
if (m_pDialog != NULL)
{
BOOL ret = m_pDialog->Create(m_pDialog->IDD, this);
if (!ret) //Create failed.
{
AfxMessageBox(_T("Error creating Dialog"));
}
m_pDialog->ShowWindow(SW_SHOW);
}
when i press the ok button in the dialog i do:
CEditorTxView pView;
box2 = (CEdit*)(GetDlgItem(IDC_CAMPI_BOX2));
box2->GetWindowTextW(campo);
pView.inserisciCampo(1, campo);
In inserisciCampo function in CEditorTxView (CFormView) i have to do operation with my control txtCtrl, but it's lost hwnd. The declaration of txtCtrl is in the CEditorTxView.h
CTx1 txtCtrl;
And initialize it in DoDataExchange function:
void CEditorTxView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TX1, txtCtrl);
}
Someone can help me plz?
I can give you two answers here:
How to do what you are asking (get access to a control of the CFormView from a modeless dialog)
How to solve your underlying problem (communicate changes in a modeless dialog to the owner view)
For the first one, you have to declare a pointer to the view in the dialog class and initialize it in the constructor of the view:
class CCampiDlg : public CDialog
{
public:
CCampiDlg(CEditorTxView* pView, CWnd*pParent = NULL) // Change declaration to add pointer to view
: m_pView(pView)
{
}
// ... Whatever
private:
CEditorTxView* m_pView;
}
Now in your button handler:
CEdit* box2 = (CEdit*)(GetDlgItem(IDC_CAMPI_BOX2)); // Why not use a control variable?
box2->GetWindowTextW(campo);
m_pView->inserisciCampo(1, campo);
This should do what you are asking for. However, it is the wrong way to do it.
The problem with this approach is that the dialog knows way too much about its parent. It knows it is of type CEditorTxView and that it has a member called inserisciCampo, that takes a number and some text.
It shouldn't know that much. In fact, knowing anything about it, other than it is of type CView or even CWnd, is too much.
If the dialog knows about the view, you can't reuse the dialog with other views, and anytime the view changes its representation (what now is a textbox may be a combobox in the future, for example) the dialog must change accordingly.
The solution would be to send a message to the parent, explaining what's happened. Then the parent (the view) should know haw to handle that event. For example:
class CCampiDlg : public CDialog
{
public:
CCampiDlg(CWnd*pParent = NULL) {}
protected:
OnOk()
{
CString campo;
c_CampiBox2.GetWindowText(campo);
GetParent()->SendMessage(UWM_CAMPO2_SET, 0, (LPARAM)&campo);
}
}
In the view:
// It can be ON_REGISTERED_MESSAGE:
ON_MESSAGE(UWM_CAMPO2_SET, OnCampo2Set)
//...
LRESULT CEditorTxView::OnCampo2Set(WPARAM, LPARAM lParam)
{
CString* s = (CString*) lParam;
inserisciCampo(1, *campo);
return 0;
}
Now, you have decoupled the view and the dialog. The dialog knows nothing about the view. You can change its type, change the representation, even make it a dialog, and you don't have to change anything in the dialog. And if you need that same modeless dialog somewhere else, you just drop it there, create a message handler in the parent, and voilĂ !
For further explanations and better examples, check these articles:
Dialog and control design (Your case is explained in the section "Notifications to the environment")
Message management
On Ok button click the below code is running:
CEditorTxView pView;
box2 = (CEdit*)(GetDlgItem(IDC_CAMPI_BOX2));
box2->GetWindowTextW(campo);
pView.inserisciCampo(1, campo);
Note that, you are creating the new pView in stack and it does't attach with any window. You are not actually referring the view that already created and launched your dialog acting a parent. Revisit the above code and try the get the view:
Try the below code, if it is not working (Google it)
CFrameWnd * pFrame = (CFrameWnd *)(AfxGetApp()->m_pMainWnd);
CView * pView = pFrame->GetActiveView();

MFC: Creating modeless dialog box without displaying

I'm trying to create a simple modeless dialog box which I'm creating from my CWinApp derived InitInstance() function.
BOOL CMyApp::InitInstance()
{
...
m_pMyDialog = new CMyDialog();
m_pMyDialog->Create(CMyDialog::IDD);
...
retrun TRUE;
}
I've created the dialog template in the resource editor and the WS_VISIBLE bit is unset. My intention is to avoid showing the dialog until I explicitly call ShowWindow(SW_SHOW) but for some reason the call to Create displays the dialog.
I've tried to change the return value of OnInitDialog() to FALSE but that doesn't work.
I've even tried to call ModifyStyle() in case something else is setting the WS_VISIBLE bit.
int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
ModifyStyle(WS_VISIBLE, 0);
return 0;
}
That doesn't work either. In all cases, after I call Create the dialog is displayed which isn't how I've read it should work.
The problem was with AnimateWindow() which was causing the dialog to display prematurely.

Cwnd returnd Undefined Value

I want to use Setwindowpos() in global function to change the postiion of one dialog.
So i coded like below
CWnd *pWnd = (CWnd*)pMain->GetDlgItem(IDD_TOOLBAR_DIALOG);//GetActiveFrame ();
pWnd->SetWindowPos(&CWnd::wndBottom,0,80,45,900,SWP_SHOWWINDOW);
pWnd returns as undefined value.
So i follow this method
CToolTab * tab;
tab = new CToolTab();
if(tab->GetSafeHwnd() == 0)
{
tab = new CToolTab();
if( tab->m_hWnd != NULL )
{
tab->SetWindowPos(&CWnd::wndBottom,0,80,45,900,SWP_SHOWWINDOW); }
}
But m_hWnd returns 0x0000.So in both cases SetWindowPos shows assertion error.
How can i get the handle of dialog in Global function?
Ok so i was thinking this through - and then it occurred to me that IDD_TOOLBAR_DIALOG is almost certainly the resource id for the dialog itself not a control on the dialog. You can't call GetDlgItem referencing the Dialog resource ID and expect to find the window that contains it (It simply won't work and you'll get back a null CWnd* pointer).
What is it that pMain points to? The main application window? Is that the parent to the Dialog?
Where in the code do you create the Dialog that want to move? At that point you must have a valid CWnd derived object for it? One solution would be to hold on to that as member variable to allow you call SetWindowPos on it later when necessary.