I'm working on a project that currently exists as a user-interactive application w/ MFC dialog boxes. I have to extend it so that it can be used as an application that accepts command-line parameters. To do that, i have to call the method that is mapped to the button click of one of the MFC-based dialog boxes from another class. How can I do that?
Crate a public method in the class containing your button-click-method, and let it call the private button-click-method. You got me? ;-)
Create and expose a public method in your Form class that will call the button click handler.
Header declaration:
public:
void DoClick();
Definition:
void YourDlg::DoClick()
{
OnBnClickedOk(); // for example
}
Also remember that the dialog class needs to be instantiated when you call it.
Related
I'm new to MFC. I chose to create an office style MFC app through the wizard in VS2017. I now want to extend CMFCShellTreeCtrl so I created another class with that as the base class. The basics are fine. My issue is that I want to do something like:
whatever MyClass::FuncitonCalledAfterControlCreated(...)
{
SetFlags(GetFlags() | SHCONTF_NONFOLDERS);
ModifyStyle(0x0, TVS_CHECKBOXES);
}
But I'm having trouble figuring out what virtual function to override or am I supposed to do one of those message mapping things? I would guess that whatever it is, it would be common to all controls? Anyway, what would be the appropriate function?
TIA!!
If control is derived from CWnd a WM_CREATE is issued which can be directed to the control via a message map of:
ON_WM_CREATE()
And member function:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
If on a dialog resource the WM_CREATE won't occur. Some say you can use PreSubClassWindow but on a case of testing Create(), that call comes BEFORE the CreateWindowEx call so won't work for setting the TVS_CHECKBOX style. I didn't try a CDialog with a tree control and check the call stack.
Using Visual Studio 2013, I created a dialog resource using the resource editor. It is a child control with no border and is just a collection of radio buttons, push buttons, and static text. I want to turn this into a custom control in order to place this in several different locations. Let's call this a "Panel".
I then created a regular dialog and using the Toolbox "Custom Control", defined an area for the Panel. The Panel registers itself and has a valid window handle.
I used the following example:
https://www.codeproject.com/Articles/521/Creating-Custom-Controls
The parent's DDX gets hit and the _panel is properly instantiated:
MyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX)
DDX_Control(pDX, IDC_CUSTOM_PANEL, _panel)
}
I read that I need to override the OnPaint() and OnEraseBkgnd(CDC* pDC) methods so the Panel class has these but they are empty. I do not have any custom painting to do as the Panel contains nothing but regular buttons.
What do I have to include in OnPaint()?
I also noticed that none of the member buttons are instantiated in the Panel like would normally happen in a dialog's DoDataExchange method. Instead, I've had to resort to dynamically creating each of the control's inside the Panel's PreSubclassWindow() method:
void MyPanel:PreSubclassWindow()
{
_groupBox.Create(_T("Options"), WS_CHILD|WS_VISIBLE|BS_GROUPBOX, CRect(11, 11, 112, 231), this, IDC_STATIC_GROUPBOX);
//... do this for every dialog element??? seems like overkill...
CWnd::PreSubclassWindow()
}
Why do I need to do this when I've already defined/designed the Panel and each of its controls in the resource editor?
If I do not do this in the PreSubclassWindow method, nothing will appear on the dialog.
Any help is appreciated. Thanks.
The article says override OnPaint and OnEraseBkgnd if you want to change the functionality. It doesn't say you have to override always.
Just remove ON_WM_PAINT and ON_WM_ERASEBKGND, remove OnPaint and OnEraseBkgnd if you don't need them. Or call the base class implementations if you are not making any changes:
void MyPanel::OnPaint() { CWnd::OnPaint(); }
BOOL MyPanel::OnEraseBkgnd(CDC* pDC) { return CWnd::OnEraseBkgnd(pDC); }
This will show a blank control with nothing in it, unless you add a child window to _panel as you have done in MyPanel:PreSubclassWindow
You are adding _groupBox to _panel. And you are adding _panel to the MyDialog.
MyDialog::DoDataExchange(...){DDX_Control(pDX, IDC_CUSTOM_PANEL, _panel)} is needed to invoke SubclassWindow for _panel. That in turn calls _groupBox.Create.
If MyPanel::OnPaint and MyPanel::PreSubclassWindow are not doing anything MyPanel appears as a blank control.
... do this for every dialog element??? seems like overkill...
You can directly add _groupBox to the main dialog. But if you want to add specific controls within MyPanel then you have to do it manually.
You can also create a child dialog within a main dialog. For example that's how a tab control works.
I've derived a custom control from ATL::CWindowImpl<CMyCustomControl> and declared DECLARE_WND_CLASS(_T("CMyCustomControl")).
I've also made a dialog resource with a custom control with the class name CMyCustomControl.
How do I go about registering the control properly so I can display it on the dialog?
There are thre typical way to create custom controls in WTL.
DECLARE_WND_CLASS/DECLARE_WND_SUPERCLASS + RegisterClassEx API to register class by name + custom control reference in dialog template to instantiate control through class name
Implement window class, esp. inheriting from CWindowImpl, and create control manually, esp. from OnCreate/OnInitDialog
Implement window class, instantiate standard control through dialog template, and subclass the control instance to alter its behavior (e.g. static with hyperlinks, custom list view, edit control with color highlighting etc)
With all three you need to do more than just a macro in class definition. You will find great examples here: http://www.viksoe.dk/code/all_wtl.htm under "Controls" section.
Certainly the fourth method is implementing an ActiveX control.
I added a activex control to my MFC project, I don't use the dialog editor to add the control, I just used MFC to generate a wrapper class for the control, and call the "create" member in the wrapper class to create the control programmatically, the code is more or less like:
class CMyView
{
CCalendar m_ctl;
//other members.....
}
int CMyView::OnCreate
{
m_ctl.create("",WS_CHILD|WS_VISIBLE,this,CRect(50,50,100,100));
//.....
}
But I found that the wrapper class provide no way for me to change the control's property, so if I want to change the control's property programmatically, what should I do? Can I achieve this through a wrapper class? Or can it be done programmatically at all? Or is it only can be done via a dialog editor? Thank you.
Yes, wrapper only includes functions, if you create it via class wizard.
To change properties, i.e. variables, you could instantiate ActiveX in a form or a dialog and you would have the ability to modify values of properties in properties window.
If you want to do it on-the-run, you can right click to activeX object and then click on add variable. You will see that it will also create wrapper class for the object. This class will automatically include getters and setters for the activex, visible in the newly generated header file.
If you have already created a wrapper class for your activex, it may not work, try this in a fresh project. You can then copy generated .cpp and .h files to your own project afterwards.
I play with Eclipse + wxWidgets + wxFormBuilder
I use wxFormBuilder for GUI-design. It generates 2 classes: first is base class; second inherits first to implement functionality like button clicks. But both of this files are regenerated every time I have changes in wxFormBuilder.
I wonder how to add some code to inherited class. For example, I have listbox, button and menu item. I want to do same action (add some string to listbox) when user presses button or selects menu item. For this reason I want to implement common function 'action'. I'll call this functuion in button and menu item handlers. Where I should declare this function and its implementation to avoid erasing manual code?
Thanks.
wxFormbuilder has the ability to generate a derived class for you. Located under Tools->Generate Inherited Class.
This code is only generated when you invoke this tool, so most probably only once. It is derived from the automatically generated class. You use this class and can implement your stuff inside of it.
So, the usual workflow is like this:
build your frame/panel in formbuilder
generate inherited class
implement your handling code in inherited class
make changes to form/panel in wxFormbuilder -> will only affect generated class, not inherited class
There is my own code generator for wxFormBuilder inherited classes which preserves manual code wxFUp455