I just tried to setup a small win32 project, and was just about to create a window.
I created a dialog in the resource designer and set up this class for my window:
#pragma once
#include "stdafx.h"
class TTTMainDialog : public CWindowImpl<TTTMainDialog>
{
public:
DECLARE_WND_CLASS(_T("TTTDlg"))
enum { IDD = IDD_TTT_DIALOG };
BEGIN_MSG_MAP_EX(MusicPlayerDialog)
MSG_WM_INITDIALOG(OnInitDialog);
MSG_WM_CLOSE(OnClose);
MSG_WM_DESTROY(OnDestroy);
END_MSG_MAP()
TTTMainDialog();
~TTTMainDialog();
private:
const BOOL OnInitDialog(const CWindow wndFocus, const LPARAM lInitParam);
void OnClose();
void OnDestroy();
};
As you can see, I added the window class declaration, I inherited CWindowImpl, I registered the dialog. I don't think I forgot something here.
In the class which is supposed to create the dialog, I tried to create it like this:
TTTMainDialog myDialog;
HWND handle = myDialog.Create(NULL);
myDialog.ShowWindow(nCmdShow);
However, the Create method does return NULL all the time. I checked the error code with GetLastError(), and it turns out i am getting error code 1406, or "ERROR_TLW_WITH_WSCHILD".
The msdn documentation says the following about this error:
"Cannot create a top-level child window."
I tried to google up on this, but there is not much to find.
If I had to take a guess I would say the problem is caused by some window class name details, but i'm really not sure.
Any advice?
You are trying to build a window class from wrong pieces.
The error is pretty descriptive: you are trying to create a parentless window with a WS_CHILD style and this does not work out.
You get the child style from default template parameter: CWindowImpl -> CWindowImplBaseT -> TWinTraits -> CControlWinTraits. CControlWinTraits is supposed for use with child control windows.
If you are going to use a dialog template (IDD_TTT_DIALOG) then the proper base class is CDialogImpl, which is already prepared to use proper window styles. Also, it has what it takes to create both modal and modeless dialogs. The latter act more like windows and are non-blocking but in the same time take dialog template resource with predefined controls.
Small example for CDialogImpl use
Or, another one
Related
I've implemented a Property Sheet and several Property Pages that are called from the Main Menu from the MainFrame.cpp spawned from my issue here:
MFC MDI Designing user preferences dialog GUI layout functionality
The code I landed on was:
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
Other messages...
ON_COMMAND(ID_SETTINGS_DIALOG, OnSettingsTools)
Other messages...
END_MESSAGE_MAP()
void CMainFrame::OnSettingsTools()
{
SettingsSheet SettingsSheet(L"Application Settings");
CSettingsPowerUser m_PowerUser;
CSettingsReset m_Reset;
CSettingsToolbars m_Toolbars;
CSettingsUserWarnings m_UserWarnings;
SettingsSheet.AddPage(&m_PowerUser);
SettingsSheet.AddPage(&m_Reset);
SettingsSheet.AddPage(&m_Toolbars);
SettingsSheet.AddPage(&m_UserWarnings);
//SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs);
SettingsSheet.DoModal();
}
Yielding:
I have included in MainFrame.h
#include <afxpropertysheet.h>
The property sheet is using CMFCPropertySheet in both the .cpp & .h as shown here in its .h file:
class SettingsSheet : public CMFCPropertySheet
{
DECLARE_DYNAMIC(SettingsSheet)
public:
SettingsSheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0);
SettingsSheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0);
virtual ~SettingsSheet();
protected:
DECLARE_MESSAGE_MAP()
};
So what the issue here is, you can see that I had to comment out the SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs); because I get an error that says SetLook identifier not found C3861.
If I hover inside the MainForm.h and right click the #include <afxpropertysheet.h> the file opens right up in the IDE and if I search for SetLook it most certainly can find it in the public section of the function.
So I've seen multiple code examples that use that SetLook and one of the tutorials I looked at used it and it works fine as I'm using VS2017.
I realize what a "not found is", but I'm at a loss as to why it's a problem here. It is the only error I am having now and I would like to use that functionality.
Thoughts on what may be going on here?
Update:
Following Dxiv's advice I changed the code to:
SettingsSheet.SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs);
It now compiles and runs, but have some odd results, it only shows one property page, and all the rest are AWOL.
I have figured out what the issue was; when I created the dialogs I used the base class of:
CPropertyPage
instead of:
CMFCPropertyPage
I had set the sheet to:
CMFCPropertySheet
and assumed it carried down since it compiled and displayed the tab view correctly, but failed on the other SetLook property options.
Once I adjusted all the dialogs to CMFCPropertyPage, the SetLook started working immediately. So I consider this issue CLOSED.
This is my first question here, so I'm trying to not sound stupid!
EXPLANATION:
I have a main window in Qt that has a button to create (sub-?) windows within the main window. This can be done as many times as the user wants, and each sub-window displays the same set of properties/items. I figured writing a class to hold all these properties would be a smart way to go about it (this would inherit the main window class), as each instance of the child window would automatically get the properties. I am using a slot to create each instance.
QUESTION:
Besides the desired properties, what do I add to the child window class to let Qt know that if I create an object of that type it should open a window?
For example, say I have implemented all the child window properties in a header file that looks something like this:
#include <QObject>
#include <QDialog> //Not sure about this
class ChildWindow : public ParentWindow
{
Q_OBJECT
public:
ChildWindow(QObject* parent);
~ChildWindow();
//Remaining properties like QSpinBox, Radio buttons etc
}
how then would I implement my slot? Like this?
void Parent::Slot()
{
ChildWindow* window;
window = new ChildWindow(this);
window->show()
}
My problem is that I don't see any code that indicates that window is a separate window. I can see that it is of type ChildWindow, but does just including QDialog give it the show() functionality?
EDIT:
I realise the first suggestion would be try and see if this works, but in the unlikely scenario that it works I wouldn't have learnt anything and I still wouldn't know why it worked, and if it didn't I would be back here asking this same question. I hope you guys understand.
EDIT 2:
error C2039: 'show' : is not a member of 'ChildWindow'
So I am guessing including QDialog did not do the trick
EDIT 3:
If I add this to the ChildWindow constructor
QDialog* child;
child = new QDialog;
child->show()
Do I have to do the same in the slot definition as well?
I have following code which works in the main dialog, but cannot work in the second (or third) dialog. The thing is that I want each page of the tab control can show a embedded dialog, it's similar to property page.
First I create two dialog, IDD_DIALOG1 and IDD_DIALOG2.Then I change the style of them to child and border to None. After that I add CDialog class to each of them.
In my MainDialog.h, I have the following code:
#include "Dialog1.h"
#include "Dialog2.h"
...
public:
CDialog1 m_para1;
CDialog2 m_para2;
CTabCtrl m_TabCtrl;
In my MainDialog.cpp, I use the following code to embed the dialo in the OnInitDialog:
m_TabCtrl.InsertItem(0, _T("TAB1"));
m_TabCtrl.InsertItem(1, _T("TAB2"));
m_para1.Create(IDD_DIALOG1,GetDlgItem(IDD_MAINDIALOG));
m_para2.Create(IDD_DIALOG2,GetDlgItem(IDD_MAINDIALOG));
CRect rs;
m_TabCtrl.GetClientRect(&rs);
rs.top+=37;
rs.bottom+=8;
rs.left+=13;
rs.right+=7;
m_para1.MoveWindow(&rs);
m_para2.MoveWindow(&rs);
m_para1.ShowWindow(TRUE);
m_para2.ShowWindow(FALSE);
m_TabCtrl.SetCurSel(1);
By using this way, It can work in this case. But if I want to use this method in my SecondDialog, the non-main dialog, it cannot work. Can someone help me out? Thanks in advance.
When you create a modeless dialog box, try this:
m_para1.Create(IDD_DIALOG1,&m_TabCtrl);
m_para2.Create(IDD_DIALOG2,&m_TabCtrl);
The second parameter of the Create function is a point to the parent window object (of type CWnd) to which the dialog object belongs. The return type of the GetDlgItem function is HWND.
See following:
http://msdn.microsoft.com/en-us/library/tc46f3be.aspx
http://msdn.microsoft.com/en-us/library/kc6x1ya0.aspx
I have been tasked with migrating our product's UI to VS2010. It is an MFC app, originally written in VC6. I have performed the following steps:
Converted the VC6 .dsp using VS2010
fixed up compile errors due to stricter VS2010 compiler
Removed all project references to VC6 mfc libs and directories
My problem is that for a dialog object (actually it's a CPropertyPage object), OnInitDialog() is not being called before other methods are. This causes an exception as OnInitDialog() needs to setup member variables.
The dialog class (CPAGEViewDefRecordFields) is subclassed from our own CValidatedPropertyPage, which in turn is derived from the MFC CPropertyPage class. The virtual method OnInitDialog() is present in all subclasses.
In the VS2010 version, when DoModal() is called on the containing property sheet, the OnInitDialog() method of the CPAGEViewDefRecordFields class is not being called. In the VC6 version, it is being called and all works ok.
In VC6, I can see that the message WM_INITDIALOG is sent, and handled in AfxDlgProc(), which in turn then calls OnInitDialog() of the dialog object.
In the VS2010 version, the first message that is processed is WM_NOTIFY, not WM_INITDIALOG.
Unfortunately I have no prior experience in MFC. What I am assuming that something has changed in the behaviour of MFC between the VC6 version and the VS2010 version. However I've not been able to find anything on the net which is similar to this.
Is there another migration step I have missed? Should I have to do something to the resources in the project when doing the migration?
I have checked that the resource is tied to the correct cpp file, as I can double click on the property page, and the IDE takes me to the correct file for the CPAGEViewDefRecordFields class.
If any of you have any ideas, I'd be very grateful.
Thanks!
Chris.
class CPAGEViewDefRecordFields : public CValidatedPropertyPage
{
public:
// Construction
CPAGEViewDefRecordFields(CWnd* pParent,
CXpViewProp* pViewProp,
CFont* pFont = NULL,
UINT nIDCaption = 0,
BOOL bSumOpRequired = TRUE,
BOOL bMinMaxRequired = TRUE,
BOOL bAllRecords = TRUE,
BOOL bShowInitSel = TRUE,
XLong lLimits = 0,
BOOL bSortSelTree = TRUE,
CXpThreshBaseLogProp* pThreshLogProp = NULL);
~CPAGEViewDefRecordFields();
// Dialog Data
//{{AFX_DATA(CPAGEViewDefRecordFields)
enum { IDD = IDD_VIEW_DEF_RECORD_FIELDS };
//}}AFX_DATA
// Overrides
// ClassWizard generate virtual function overrides
//{{AFX_VIRTUAL(CPAGEViewDefRecordFields)
virtual BOOL OnInitDialog();
//}}AFX_VIRTUAL
virtual BOOL OnSetActive();
virtual BOOL OnKillActive();
virtual void OnOK();
protected:
...
// Generated message map functions
//{{AFX_MSG(CPAGEViewDefRecordFields)
afx_msg void OnPbRemove();
afx_msg void OnPbAdd();
afx_msg void OnDblclkAvailableFields(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDblclkSelectedFields(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
...
UPDATE:
After some debugging, I can see what I think is the problem. However, not being an MFC programmer, I don't understand it.
I can see that OnInitDialog() is being called for the property sheet, and that a WM_INITDIALOG is then sent from the property sheet to the property pages. however, at some point in the windows internals, a WM_NOTIFY message is being sent, so this is the first message that is received, not the expected WM_INITDIALOG
I've highlighted the points on the stack trace, attached - can anyone explain why this is occuring? Is this normal behaviour - should I be catering for this in the future?
I've actually found a workaround, and that's to have an initialised flag, so that no code is executed until OnInitDialog() has been called. This is not the best solution, and I fear is more of a hack, so i would still appreciated any understanding of these messages. (I'm not an MFC programmer by trade you see!)
thanks!
OnInitDialog is called after all the dialog controls are created and just before the dialog box is displayed.
Thought I'd better answer this.
The answer came from a SO user's comment:
Your workaround with an initialized flag is the same as I would do. It looks like a tree view sends a notification when the tree view is created but your dialog isn't ready yet. You might not know when other controls do the same thing, so you need an initialized flag
The "workaround" is the only way to guarantee that the dialog is ready.
I am creating an MFC application which will be launched on click on Explorer Context (Rightclick) menu.
But I need to launch only single instance of the application. For that I have to use FindWindow and AfxRegisterClass
I tried to register the class in my MFC app as below:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
//Class name for using FindWindow later
wndcls.lpszClassName = _T("NDSApp");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and called the method in the constructor of the MFC class. I verified that the class is being registered while I am starting the application.
Now in my shell Extension I am trying to find the Class registered in my MFC as below:
CWnd *pWndPrev = NULL;
pWndPrev = CWnd::FindWindow(_T("NDSApp"),NULL);
if(pWndPrev != NULL)
pWndPrev->BringWindowToTop();
But I am not able to get the CWnd to Window. Not able to figure it out. Please let me know if I am missing something or doing something wrong.
FindWindow finds window instances not window classes. In your app which registers the class you need to actually create a window so that the extension can find that window.
(Finding the window by class name is fine; the problem is you haven't actually created anything to find.)
Also, I suspect if you try to create a window based on the window-class you've registered it will fail because you've left most of the WNDCLASS structure null. See the example you linked to for better default values. (e.g. You must provide a wndproc and hinstance.)