MFC: Visual Studio Resource Editor Class Wizard doesn't have all control IDs under Member Variables - visual-studio-2017

I've run into this a few times, don't recall what I did to fix it last time (probably started all over). Here's what I did:
I copied an existing CMFCPropertySheet dialog box and pasted as new one then edited the dialog ID to IDD_MINE, deleted all the controls as a starting place. Next I added the various controls for the this dialog.
After setting up the dialog the way I wanted it, I went to "Add Class" and added a class for the dialog (choosing the base class CMFCPropertySheet). When it was done, it was incorrect (VS2017 has never done the property sheet correct for me). Referencing another property sheet that I have working, I added the missing IDD_MINE to the constructor and the AFX_DESIGN_TIME { enum IDD=IDD_MINE }.
Once the class was setup I was ready to start adding variables. However I noticed some of the controls that were a checkbox should have been a radio button so I deleted them, created radio buttons (push like) then choose the existing IDC_ names (old checkbox names) from the dropdown list for the control id. Next I try to add the first radio button as a value variable but that fails with the following error:
Object reference not set to an instance of an object.
So I go to the Class Wizard for the Dialog and look in "Member Variables" tab. It lists all the controls IDs except the radio buttons (and IDC_STATIC items that are -1) . I tried renaming the radio buttons by changing the IDC_ names but that didn't change anything (exit program, etc.., still same).
So does someone know how I get visual stdio resource editor / class wizard back in sync with the controls that really exist so I can add them using the wizard?
TIA!!
EDIT:
Even those variables which exist in the "Member Variables" tab can't be used with the wizard. Same Object Reference not set to instance of an object message.
So being desperate, I manually added the function:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
Everything works now!!
Which the wizard would take care of all this on its own.

Related

Changing button name MFC Visual Studio

I just started the GUI development, i had started on C++Builder but i switched to Visual Studio for differents reasons. But in Visual Studio, i've got a big problem :
In the GUI development interface (rc file) i can create buttons and place it, but i can't change there names. The name for all of MFC components i placed is initialize to a default name which i can't call and i can't change the property by the properties interface, i can change the Text, for change the Label of the Button, but not the name...
It's very incomfortable because by that i can't call my buttons for do anything, i have the same problem for Listboxs, so i can't modify my list because i can't call there
I just want to modify access my component by my c++ code for modifying this component
enter image description here
Thank for your help !
The MFC way of doing event handling is a bit more elaborate.
After the control is created on the form in the designer, an ID is generated ("IDC_BUTTON1" in the attached screenshot).
This is the ID that will be used for accessing this UI control from the code.
All this can be done via the designer also as shown in this article.
Basically, in the background this generated ID is put in a 'message map'
(more about message maps here).
In short 'message map' is used to specify what action needs to be performed when a certain type of action is done on the UI control by the user.
For, example if the button click is to be handled then in code:
the message map would look like:
BEGIN_MESSAGE_MAP(CSurface3DView, CView)
ON_BN_CLICKED(IDC_BUTTON1, CallMyFunction)
END_MESSAGE_MAP()
'ON_BN_CLICKED' is a predefined event macro.
The 'CallMyFunction()' function has to be declared with 'afx_msg' in the class. Besides please, have a look at data exchange mechanism as well. This know-how about data exchange will come in handy going forward.

Rewrite CListBox as a CCheckListBox

I am working on a Windows application using MFC and Visual Studio C++ 17.
I have multiple tabs in the application, one of which is currently implemented using CListBox and needs to be reimplemented using CCheckListBox.
CCheckListBox is a child class of CListBox.
I have a vector of unique CString's I want to display in the box.
To start simple, I tried making the tab with CListBox and by using CListBox::AddString(), this worked exactly as I wanted it to. It sorted the strings alphabetically, and automatically added a scroll bar on the side when the vector had too many CString's to display all at once in the list.
However, when swapping the CListBox variable to a CCheckListBox variable, I have come across the error when I press run along the lines of:
Debug Assertion Failed! ..... \mfc\winctrl3.cpp Line: 588
I found this GitHub link that has the winctrl3.cpp file and on line 588, there is a function called OnLButtonDblClk which is somewhat explained here.
The trouble is I am unsure of how to swap a variable from a parent class to a child class. Is it so different for Windows classes? In the courses and programs I have taken and written in the past, switching from a parent to child variable was straightforward but this is quite the opposite !
Any help is appreciated, thank you in advance ! :D
There is no assertion in line 588 of the source file in your link. That github upload dates back to 2014. Why not search the winctrl3.cpp source file in your own Visual Studio installation instead? In my own installation, it is in function PreSubclassWindow() and there is indeed an assertion there:
// CCheckListBoxes must be owner drawn
ASSERT(GetStyle() & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE));
That is the CCheckListBox must be owner-drawn. Find the CCheckListBox constructor code above, you will notice that it calls the CListBox (parent-class) constructor, applying either of the two owner-drawn styles. Instead, the CListBox constructor calls CWnd::Create() with the "LISTBOX" Windows Class-Name as a parameter. That is, it seems to be a MFC-implemented control, overriding the CListBox class, with an owner-drawn style. There is no mention of a native "Check-ListBox" class or style in the Win32 documentation either. Also the CCheckListBox documentation (in the link you posted) clearly states: CCheckListBox is only for owner-drawn controls because the list contains more than text strings.
Therefore:
If you are creating the control using a resource script, add an owner-drawn style (eg LBS_OWNERDRAWFIXED) to the control (or set the Owner-Drawn property in the property editor).
If you are creating the control programmatically make sure you are calling the CCheckListBox constructor, not the CListBox one.
Not sure what you mean about the scroll-bar (and why you mention it), doesn't the list-box display a scroll-bar automatically (WS_VSCROLL style - or property), do you have to do something on your own?
EDIT:
Forgot to mention, if you are creating the control using a resource script use the Class Wizard to add a member variable (of "Control" type, not "Value") to the dialog class. The new variable must be of type CCheckListBox (MFC class). This will subclass the control. If the old project already had a CListBox member variable change it to CCheckListBox.

MFC dialog-based app with tab control - Visual Studio bugs/restrictions make recommended path impossible?

Create a dialog-based application in Visual Studio 2019. Insert a new dialog in the resources. Place a control (or two) on that dialog that you will later (try to) hook up to a variable (e.g. an edit box to enter your name).
Prepare to add that control variable by creating a class for this second dialog. If you inherit from CDialogEx (or perhaps other classes too - not tested), you can go on to add a variable for the control you added - easy, normal.
But if you had the "tab control" context from the title above in your mind, and chose to inherit from CMFCPropertyPage instead, can you add a variable subsequently? No you cannot - the class added makes no reference to the ID of the dialog resource, and so the Add Variable process has no basis to find a class to add the variable to.
I think this is a bug in Visual Studio... but I'm not 100% sure because I have always found the documentation around property sheets and property pages somewhat confusing. Specifically:
Do the classes implementing the tabs contents on a tab control "contain" the controls "on" the tab... or is the tab control really just a way to provide visual cues to show/hide sets of controls, and all of those controls and associated variables reside in one class?
I believe it's intended to be the former, but I can imagine that one uses a tab control because there are strong similarities between tab contents, and therefore potential benefits in implementing all the control variables in one place so as to avoid duplication. I just wish it was stated explicitly somewhere what the intention was.
Wider context: I'm trying to implement a dialog-based app with a tab control dominating that dialog. MS documentation says to implement a tab control using CPropertySheet and CPropertyPage to implement the tabbed dialog and tab contents. However, there is no (direct) way to create a dialog-based application whose main dialog inherits from CPropertySheet. When you look for examples of tab controls at the application level, you readily find things that deviate from the documented path considerably - using neither CPropertySheet nor CPropertyPage and using the WM_LBUTTONDOWN event instead of TCN_SELCHANGE, both without obvious reasons.
Any tips on (a) how to repair the apparent Visual Studio bug and/or (b) how to inherit from CPropertySheet for my application dialog and/or (c) where to find a clearer and more conventional example of tab control use at the top level would be greatly appreciated.
Given that there appears to be no clear and consistent way of approaching this, if (like me) you think "how hard can it be?", you might naively set out to see if you can create a new dialog-based application based on CDialog and manually convert it to CPropertyPage. You might fare better; I quickly hit a weird problem with the app compiling but not running - it could not load the window caption from the resource ID, despite the caption literally being there in black and white. Due to the weirdness, this was a red flag, and so to my mind problem (b) seems to be not worth the effort.
Without a CPropertySheet at the top level, there is no point having any kind of CPropertyPage or CMFCPropertyPage involved, making problem (a) pointless. That said, if you manually convert from (default) CDialogEx to CPropertyPage for your tab classes, it seems to have no problem compiling and running - the tabs just don't have any functionality that integrates with the main dialog.
Instead, I can now recommend working through the details of the video example even though it does strange things at first glance. You can achieve the desired result in more or less the same way as follows:
Use plain CDialogEx throughout, and so provide all the tab switching/showing/hiding/control work yourself (which the example demonstrates).
Create your main dialog and all tabs in the resource editor, adding the CDialog-based classes from there.
If you create your tab dialog resources via Insert Dialog (generic) instead of Add Resource (uses specific templates) then you will have to manually set certain dialog properties for each tab:
Border: Thin (or I preferred None)
Style: Child
System Menu: false
Title Bar: false
You can simplify the repositioning of the tabs (see below; it barely justifies the separate SetRectangle() function)
You should (probably) drive the tab changing from the TCN_SELCHANGE event instead of WM_LBUTTONDOWN
As noted, repositioning the tabs can be simplified to something like:
CRect tabRect;
m_tabControl.GetWindowRect( &tabRect );
for ( int i = 0; i < m_totalTabs; i++ )
{
m_pTabPage[ i ]->SetWindowPos( &wndTop, tabRect.left, tabRect.top, 0, 0,
i == m_currentTab? SWP_NOSIZE|SWP_SHOWWINDOW : SWP_NOSIZE|SWP_HIDEWINDOW );
}
Additional calls to ShowWindow() for each tab shown in the example are redundant.
One time, I had made on application as such. I don't remember if I used the Visual Studio new project wizard. Most probably, I did. But I will assist you on how to do it if you can not reach how to do it via the assistant.
The essential things:
Define the main dialog in the resources and the respective class in its H and CPP files.
In the YourAppClass::InitInstance you will need to have something like:
YourMainDlgClass dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
else if (nResponse == -1)
{
TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
}
Insert a CMFCTabCtrl element in your dialog for tabs, instead of using a CPropertySheet.

Programmatically and completely delete button from MFC toolbar

I have a document within MFC C++ application. I need to delete one the buttons from the particular CMFCToolbar within a code (not resources) completely, even preventing a user to restore the button via toolbar customization dialog. At this moment I use RemoveButton method of CMFCToolbar but it only makes the button invisible and it can be restored via toolbar customization dialog that is not an option for me at this time. I will be very glad if you suggest something that can help me there.
There are two internal lists in CMFCToolBar that are used to reset the Buttons upon customization.
They are named m_OrigButtons and m_OrigResetButtons.
You may need to derive your own class and delete the buttons with the specific IDs from there.
But better: Never to include such a button on the first time when the toolbar is created!

How Do I Launch a Dialog in MFC?

I'm fairly new to VC++ and MFC, so bear with me. I have created a new dialog, and I want to figure out how to display it when the user clicks a button.
I have not create a class or header file for the dialog -- I tried using the class wizard, but it pretty much sucked and didn't work. That, or I was doing something wrong. Either one is equally as likely if you ask me.
So what steps do I need to take when creating the source/header files and getting the dialog to launch/display? It is a modal dialog.
CLARIFICATION: I understand that I need to create an instance of the dialog class, then just call DoModal() on it, but I'm not sure how to create the class file (with and/or without the wizard).
Right click the project and select
Add | Resource...
Select Dialog under Resource
type and click New.
Select Project | Add Class...
Enter CMyDialog for the Class
name, CDialog for the Base class
and Click Finish.
Read more: How to Make MFC Dialog Boxes
Seems to me you can make the button click just create a new instance of the dialog object and activate it. You'll probably have to keep a reference to the dialog so it doesn't get killed when the button action fxn returns it doesn't get garbage collected..