Creating CWnd derived control at runtime - c++

I am trying to create CWnd derived class at runtime but CWnd::Create fails. I have no idea why. Here is minimal code that show the problem:
MFCTestApplicationDlg.h
#pragma once
class c_CustomButton : public CButton
{
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
public:
c_CustomButton();
virtual ~c_CustomButton();
};
class TestWindow : public CWnd
{
public:
TestWindow();
virtual ~TestWindow();
protected:
DECLARE_MESSAGE_MAP()
DECLARE_DYNCREATE(TestWindow)
};
// CMFCTestApplicationDlg dialog
class CMFCTestApplicationDlg : public CDialogEx
{
...
}
MFCTestApplicationDlg.cpp
//
#include "stdafx.h"
#include "MFCTestApplication.h"
#include "MFCTestApplicationDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/*==========================================================================*/
c_CustomButton::c_CustomButton()
{
}
/*==========================================================================*/
c_CustomButton::~c_CustomButton()
{
}
BEGIN_MESSAGE_MAP(c_CustomButton, CButton)
END_MESSAGE_MAP()
/*==========================================================================*/
void c_CustomButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);
}
IMPLEMENT_DYNAMIC(TestWindow, CWnd)
TestWindow::TestWindow()
{
}
TestWindow::~TestWindow()
{
}
BEGIN_MESSAGE_MAP(TestWindow, CWnd)
END_MESSAGE_MAP()
void CMFCTestApplicationDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
c_CustomButton* pColoredButton = new c_CustomButton;
pColoredButton->Create((LPCTSTR)"", 0, CRect(), this, 0);// successeded
pColoredButton->SetWindowTextW((LPCTSTR)"test");
TestWindow* pTestWindow = new TestWindow;
pTestWindow->Create((LPCTSTR)"TestWindow", (LPCTSTR)"TestWindowName", 0, CRect(), this, 0);// failed
pTestWindow->SetWindowText((LPCTSTR)"test");
}
In void CMFCTestApplicationDlg::DoDataExchange(CDataExchange* pDX) I tried to create a CButton derived class object and CWnd derived class object. The first one created successfully but CWnd derived class object fails to create. Whats wrong with this code?

Related

Visual Studio Class Wizard - failed to retrieve controls of dialog

If I try in Visual Studio 2019 run class wizard for some dialog, the error "Failed retrieve controls of dialog 'IDD.....' is shown. But after it is class wizard opened and work properly.
But I am interesting, why it throw this error.
Dialog is inherited from my own class, not from CDialogEx. But My own class is inherited from CDialogEx.
My dialog class code:
#pragma once
#include "resource.h"
#include "CMjAcDialog.h"
// CMjcDlgVyberTrasu dialog
class CMjcDlgVyberTrasu : public CMjAcDialog
{
DECLARE_DYNAMIC(CMjcDlgVyberTrasu)
public:
CMjcDlgVyberTrasu(CWnd* pParent = nullptr); // standard constructor
virtual ~CMjcDlgVyberTrasu();
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_VYBER_TRASU };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
vector<CMajTrasa *> *m_pVecOfTrasy;
CListCtrl m_cList;
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBtUkaz();
virtual BOOL OnInitDialog();
};
And part of my my Dialog Class CMjAcDialog code:
class CMjAcDialog : public CDialogEx
{
DECLARE_DYNAMIC(CMjAcDialog)
protected:
UINT m_IDD;
CMajCtrlMap m_majCtrlMap;
CFont m_Font_mid, m_Font_big;
CString m_csDlgTitle;
HICON m_hIcon;
private:
int m_idMainIcon;
float m_dCurDpiScale;
// konstruktor
public:
CMjAcDialog(UINT idd, CWnd* pParent = NULL, CString acsWinCaption = L"", int idMainIcon = 0);
~CMjAcDialog();
protected:
virtual BOOL OnInitDialog();
.....
....

Creating a new base CDialogEx derived class

I have a lot of CDialogEx derived classes that do something like this in OnInitDialog:
CMeetingScheduleAssistantApp::InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
CMeetingScheduleAssistantApp::RestoreWindowPosition(_T("PublisherDB"), this, true);
Then, I have the following added to each derived dialog class:
int CPublishersDatabaseDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
return 0;
}
void CPublishersDatabaseDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CPublishersDatabaseDlg::OnClose()
{
CMeetingScheduleAssistantApp::SaveWindowPosition(_T("PublisherDB"), this);
CDialogEx::OnClose();
}
The only thing that is different for each dialog is the phrase that is used for saving the window position.
I want to have a based CDialogEx class that I can inherit from that will perform the above actions. I have looked on SO and seem some questions and creating a CDialog class and inheriting from another CDialog class. But this class I want to create is more generic. Effectively to be used as a base instead of CDialogEx.
Can this be done? Am I over-complicating this?
Problems
Why I try to create a new class, derived from CDialogEx:
I don't know if it is because it requires a dialog ID as stated here.
Classes such as CDialog, CFormView, or CPropertyPage, which require a dialog ID.
So I can't work out the correct way to create a base CDialogEx class for use in all my other dialog classes.
Update
I created this code and it tells me that CResizingDialog is not a class or a namespace:
#include "ResizingDialog.h"
#include "resource.h"
#include "stdafx.h"
IMPLEMENT_DYNAMIC(CResizingDialog, CDialogEx)
CResizingDialog::CResizingDialog(const CString& strWindowID, UINT nIDTemplate, CWnd* pParent = nullptr)
: m_strWindowID(strWindowID), CDialogEx(nIDTemplate, pParent)
{
}
CResizingDialog::~CResizingDialog()
{
}
void CResizingDialog::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CResizingDialog, CDialogEx)
ON_WM_CREATE()
ON_WM_GETMINMAXINFO()
ON_WM_CLOSE()
END_MESSAGE_MAP()
int CResizingDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
return 0;
}
void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CResizingDialog::OnClose()
{
SaveWindowPosition(m_strWindowID, this);
CDialogEx::OnClose();
}
Based on the comments encouraging me to try to create the class manually, I have it working:
#include "stdafx.h"
#include "resource.h"
#include "ResizingDialog.h"
IMPLEMENT_DYNAMIC(CResizingDialog, CDialogEx)
CResizingDialog::CResizingDialog(const CString& strWindowID, UINT nIDTemplate, CWnd* pParent /* nullptr */, bool bOnlyStorePosition /* false */)
: m_strWindowID(strWindowID),
m_bOnlyStorePosition(bOnlyStorePosition), CDialogEx(nIDTemplate, pParent)
{
}
CResizingDialog::~CResizingDialog()
{
}
void CResizingDialog::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CResizingDialog, CDialogEx)
ON_WM_CREATE()
ON_WM_GETMINMAXINFO()
ON_WM_CLOSE()
END_MESSAGE_MAP()
int CResizingDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
return 0;
}
void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CResizingDialog::OnClose()
{
SaveWindowPosition(m_strWindowID, this);
CDialogEx::OnClose();
}
void CResizingDialog::OnOK()
{
SaveWindowPosition();
CDialogEx::OnOK();
}
BOOL CResizingDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
if(!m_bOnlyStorePosition)
InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
RestoreWindowPosition(m_strWindowID, this, true);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
I decided to duplicate the methods that were in the app class into this new dialog class instead. Eventually they can be removed from the app class. The only thing I also had to do was #include my resource file because the image needs to know the value of the resource ID.
This is the ResizingDialog.h header:
#pragma once
#include <afxwin.h>
class CResizingDialog : public CDialogEx
{
DECLARE_DYNAMIC(CResizingDialog)
public:
CResizingDialog(const CString& phrase, UINT nIDTemplate, CWnd* pParent = nullptr, bool bOnlyStorePosition = false); // Constructor
virtual ~CResizingDialog(); // Destructor
protected:
void OnOK() override;
virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support
void SaveWindowPosition(void) { SaveWindowPosition(m_strWindowID, this); }
public:
BOOL OnInitDialog() override;
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
afx_msg void OnClose();
DECLARE_MESSAGE_MAP()
private:
CBitmap m_bmpResize;
CStatic m_lblResize;
CRect m_rcInit;
CString m_strWindowID;
bool m_bOnlyStorePosition;
void RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState = false);
void SaveWindowPosition(CString strWindow, CWnd* pWindow);
void InitialiseResizeIcon(CBitmap& rBmpResize, CStatic& rLblResize, CWnd* pDialog);
};
The actual functions SaveWindowPosition, RestoreWindowPosition and InitialiseResizeIcon are not shown here as they don't directly relate to the issue.

Calling a method from another class in message handler

I have .H file and .Cpp file for a dialog Print that contains two buttons Printer 1 and Printer 2 and I want to call a method in another class function when Printer 1 is pressed.
.H File
#pragma once
#ifndef PRINTCHOOSEDLG_H
#define PRINTCHOOSEDLG_H
class CPrintChooseDlg : public CTungstenDlg
{
public:
CPrintChooseDlg(CWnd* pParent = NULL);
enum { IDD = IDD_PRINTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX);
protected:
afx_msg void OnPrinter1();
afx_msg void OnPrinter2();
//virtual void OnPrinter1();
//virtual void OnPrinter2();
DECLARE_MESSAGE_MAP()
};
#endif
.Cpp
#include "stdafx.h"
#include "Tungsten.h"
#include "PrintChooseDlg.h"
CPrintChooseDlg::CPrintChooseDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPrintChooseDlg::IDD, pParent)
{
}
void CPrintChooseDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CPrintChooseDlg, CDialog)
ON_BN_CLICKED(IDC_PRINTER1,OnPrinter1)
ON_BN_CLICKED(IDC_PRINTER2,OnPrinter2)
END_MESSAGE_MAP()
void CPrintChooseDlg::OnPrinter1()
{
CTungstenDlg aux;
aux.OnOK();
}
void CPrintChooseDlg::OnPrinter2()
{
CTungstenDlg aux;
aux.OnOK();
}
How can i call the method CTungsten::OnOK inside the function CPrintChooseDlg::OnPrinter1()
It gives me an error of course because it is not defined in the PrintChooseDlg.cpp
What i tried: is to include guards in header and use suggested solutions in comments
Thanks in Advance

Visual C++ How to override event handler of parant class?

I need to override event wm_lbuttonup of CMFCRibbonSlider class
class CMyRibbonSlider : public CMFCRibbonSlider
{
public:
virtual void OnLButtonUp(CPoint point); // need this event handler!
};
void CMyRibbonSlider::OnLButtonUp(CPoint point)
{
AfxMessageBox(_T("Works!"))
return;
}
Use CMyRibbonSlider object in MainFrame class
class CMainFrame : public CMDIFrameWndEx
{
....
CMyRibbonSlider* SliderLine;
}
When CMFCRibbonSlider control apears and I click left mousebutton, nothing happens. What do I do wrong?
EDIT:
initialization
CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> ar;
m_wndRibbonBar.GetElementsByID(ID_SLIDER2, RibbonElementsArray);
m_wndRibbonBar.GetElementsByID(ID_START_BTN, ar);
RibbonElementsArray.Append(ar);
m_wndRibbonBar.GetElementsByID(ID_STOP_BTN, ar);
RibbonElementsArray.Append(ar);
m_wndRibbonBar.GetElementsByID(ID_SLIDER_LINE, ar); //HERE!
RibbonElementsArray.Append(ar);
m_wndRibbonBar.GetElementsByID(IDC_STATIC_TT, ar);
RibbonElementsArray.Append(ar);
Slider = DYNAMIC_DOWNCAST(CMFCRibbonSlider, RibbonElementsArray[0]);
btnStart = DYNAMIC_DOWNCAST(CMFCRibbonButton, RibbonElementsArray[1]);
btnStop = DYNAMIC_DOWNCAST(CMFCRibbonButton, RibbonElementsArray[2]);
SliderLine = (CMyRibbonSlider*)DYNAMIC_DOWNCAST(CMFCRibbonSlider, RibbonElementsArray[3]); //and HERE!
TmpLable = DYNAMIC_DOWNCAST(CMFCRibbonLabel, RibbonElementsArray[4]);
also I have these event handlers in Mainframe class and they work:
ON_UPDATE_COMMAND_UI(ID_SLIDER_LINE, &CMainFrame::OnUpdateSliderLine)
ON_COMMAND(ID_SLIDER_LINE, &CMainFrame::OnSliderLine)
SliderLine->GetPos() also returns right slider position, so I think initialization is right...
It is seem like the CMFCRibbonSlider control isn't added correctly to CMFCRibbonPanel and therefore CMainFrame class does not expose slider’s messages through message map.
Try to use a method described in the following article:
Walkthrough: Creating a New Ribbon Application By Using MFC
The code will be look like below.
MyRibbonSlider.h
#include "afxribbonslider.h"
#pragma once
class CMyRibbonSlider : public CMFCRibbonSlider
{
DECLARE_DYNCREATE(CMyRibbonSlider)
public:
CMyRibbonSlider();
CMyRibbonSlider(UINT nID, int nWidth = 100);
// Implementation
public:
virtual ~CMyRibbonSlider();
virtual void OnLButtonUp(CPoint point);
};
MyRibbonSlider.cpp
#include "stdafx.h"
#include "MyRibbonSlider.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(CMyRibbonSlider, CMFCRibbonSlider)
CMyRibbonSlider::CMyRibbonSlider()
{
}
CMyRibbonSlider::CMyRibbonSlider(UINT nID, int nWidth)
: CMFCRibbonSlider(nID, nWidth)
{
}
CMyRibbonSlider::~CMyRibbonSlider()
{
}
void CMyRibbonSlider::OnLButtonUp(CPoint point)
{
TRACE("\nCMyRibbonSlider::OnLButtonUp()");
return;
}
Related declarations in the CMainFrame.h
afx_msg void OnSliderLine();
afx_msg void OnUpdateSliderLine(CCmdUI* pCmdUI);
CMainFrame.cpp
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
...
ON_COMMAND(ID_SLIDER, &CMainFrame::OnSliderLine)
ON_UPDATE_COMMAND_UI(ID_SLIDER, &CMainFrame::OnUpdateSliderLine)
END_MESSAGE_MAP()
void CMainFrame::InitializeRibbon()
{
...
bNameValid = strTemp.LoadString(*your title*);
ASSERT(bNameValid);
CMFCRibbonPanel* pPanelAdvanced = pCategoryHome->AddPanel(strTemp, m_PanelImages.ExtractIcon (*your icon*));
strTemp = _T("Slider");
CMyRibbonSlider* pRibbonSlider = new CMyRibbonSlider(ID_SLIDER);
pPanelAdvanced->Add(pRibbonSlider);
...
}
void CMainFrame::OnSliderLine()
{
// TODO
}
void CMainFrame::OnUpdateSliderLine(CCmdUI* pCmdUI)
{
// TODO
}

MFC CView into CDockablePane

I need to place a CView derived class into a CDockablePane. Is there any code example somewhere, or can someone provide such code?
What I tried:
Apparently should be simple, online I found advice like "just create the view and set its parent to be the dialog or the dockable pane or what kind of window you want". But for some reason it doesn't work, maybe is because it needs a CFrameWnd, I don't know.
Anyway, I need to be able to do this without creating another document template class. Just to work with preexisting document and view classes.
Here's an example:
a class derived from CDockablePane:
//CRichEditPane .h
class CRichEditPane : public CDockablePane
{
DECLARE_DYNAMIC(CRichEditPane)
public:
CRichEditPane();
virtual ~CRichEditPane();
protected:
void AdjustLayout();
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
};
//CRichEditPane .cpp
IMPLEMENT_DYNAMIC(CRichEditPane, CDockablePane)
CRichEditPane::CRichEditPane()
{
}
CRichEditPane::~CRichEditPane()
{
}
BEGIN_MESSAGE_MAP(CRichEditPane, CDockablePane)
ON_WM_CREATE()
ON_WM_SIZE()
END_MESSAGE_MAP()
// CRichEditPane message handlers
int CRichEditPane::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
CRuntimeClass *pClass = RUNTIME_CLASS(CRichEditViewInPane);
// calling constructor using IMPLEMENT_DYNCREATE macro
CRichEditViewInPane *pView = (CRichEditViewInPane*)pClass->CreateObject();
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, AFX_IDW_PANE_FIRST, NULL))
{
return -1;
}
CRichEditCtrl ctrl;
ctrl.Create(WS_CHILD, CRect(0, 0, 0, 0), this, 10991);
return 0;
}
void CRichEditPane::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
AdjustLayout();
}
a view class derived from CView:
//CRichEditViewInPane .h
class CRichEditViewInPane : public CRichEditView
{
DECLARE_DYNCREATE(CRichEditViewInPane)
protected:
CRichEditViewInPane(); // protected constructor used by dynamic creation
virtual ~CRichEditViewInPane();
public:
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif
protected:
DECLARE_MESSAGE_MAP()
};
//CRichEditViewInPane. cpp
IMPLEMENT_DYNCREATE(CRichEditViewInPane, CRichEditView)
CRichEditViewInPane::CRichEditViewInPane()
{
}
CRichEditViewInPane::~CRichEditViewInPane()
{
}
BEGIN_MESSAGE_MAP(CRichEditViewInPane, CRichEditView)
END_MESSAGE_MAP()