I am learning MFC programming. In the part of dialog design, I entered a problem.
The resource is IDD_PEN_WIDTH, which is the ID of the dialog. And there is a piece of automatically generated code related to this:
class PenWidthDlg : public CDialogEx
{
DECLARE_DYNAMIC(PenWidthDlg)
public:
PenWidthDlg(CWnd* pParent = NULL); // standard constructor
virtual ~PenWidthDlg();
// Dialog Data
enum { IDD = IDD_PEN_WIDTH };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
int m_nPenWidth;
};
Before I run my program, the IDD_PEN_WIDTH shows "#define IDD_PEN_WIDTH 301" while hovering mouse on IDD_PEN_WIDTH in the code. But when I run it, there is one error says IDD_PEN_WIDTH is an undefined identifier. Then I hover mouse on "IDD_PEN_WIDTH", it also says it's undefined.
I am usually confused in MFC studying, and I will appreciate very much for your detailed explanations. Thanks.
It has to be defined in every cpp file that uses it. Add #include "Resource.h" in those cpp files. Do that #include before the #include of the dialog .h file.
Related
I am building a 3d painter in C++ with OpenGL and MFC.
I created dialogs for creating every shape that i have: like cube, cylinder and etc...
My cube class inherits the cylinder class with the difference of amount of stack and slices only.
Hence the CreateCylinder dialog should look the same as the CreateCube dialog.
I was able to inherit it fine, but i have an error that says:
Error 6 error C2065: 'IDD_BASEWIN_DIALOG' : undeclared identifier c:\users\l122\desktop\opengl\opengl\basewindlg.h 19 1 OpenGL
This happens every new compilation after some minor code changes.
To fix it, i comment this line:
enum { IDD = IDD_BASEWIN_DIALOG };
then compile and uncomment the same line, which helps in the next compilation to work fine.
That how i inherited the CreateCylinder dialog class in my CreateCube dialog class:
IMPLEMENT_DYNAMIC(CreateCube, CreateCylinder)
CreateCube::CreateCube()
: CreateCylinder(this->GetSafeOwner())
{
}
CreateCube::~CreateCube()
{
}
void CreateCube::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
CreateCylinder::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CreateCube, CreateCylinder)
END_MESSAGE_MAP()
and i also edited this line in the CreateCylinder constructor:
CreateCylinder::CreateCylinder(CWnd* pParent /*=NULL*/)
: CDialogEx(CreateCylinder::IDD, this->GetSafeOwner())
The header file:
#pragma once
#include "CreateCylinder.h"
// CreateCube dialog
class CreateCube : public CreateCylinder
{
DECLARE_DYNAMIC(CreateCube)
public:
CreateCube(); // standard constructor
virtual ~CreateCube();
// Dialog Data
enum { IDD = IDD_CREATE_CUBE_DLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
};
I want to know what have i done wrong with the inheritance. is it necessary to send parent's pointer to the base dialog as i did?
And is the error above has to do anything with it?
The problem here is the scope of the enum symbol IDD_CREATE_CUBE_DLG. When you inherit a class, you don't inherit it's "symbol scope", you merely inherit its "members namespace". I'm sure some language lawyer can give a more precise (technically correct) explanation. But, a simple explanation is that you don't inherit symbol - thus enum - definitions. You should be able to access them even if they are in protected scope, though.
So, assuming that IDD_CREATE_CUBE_DLG is used in CreateCylinder class to set "its" IDD, then, instead of:
enum { IDD = IDD_CREATE_CUBE_DLG };
you should write:
enum { IDD = CreateCylinder::IDD };
I think that the correct wording would be to say that you need the "fully qualified" name here.
This is actually a good thing, and some class libraries use it to play tricks, like enumerating messages supported by a class, and such - see, for example, the FOX (widget) toolkit library.
UPDATE:
If you change your declaration as is updated here, thus avoiding the use of IDD_CREATE_CUBE_DLG, it's probable that you won't have problems with IDD_CREATE_CUBE_DLG any more. But, if you still do, the problem would be that IDD_CREATE_CUBE_DLG, since it's declared in Resource.h, then, at the time it was used (which is the line for which the error is reported), the Resource.h wasn't (properly) included. So, check what is the .cpp file that is compiled when your error is reported. Then check the includes in that file. You should clean them up, but, for starters, you may "just" #include "Resource.h" at the top (of the .h file).
As for the constructor of CDialogEx, just pass the parameter along, like this:
CreateCylinder::CreateCylinder(CWnd* pParent)
: CDialogEx(CreateCylinder::IDD, pParent)
Actually adding resource.h to my base dialog header solved the problem. I just can't understand how it worked flawlessly, before i have added the inherited classes. In both cases this header file wasn't included, so how did it work in a first place?
I am having a hard time subclassing Widgets in the QDesigner. I am using QDesigner to create my UI, but using cmake to compile rather than .pro files. So I am basically using QT Creator for nothing other than generating ui files.
Now I want to subclass QLabel in order to override the mouse click event, so as far as I understand all I have to do is right click the QLabel and select "promote to". It then asks me what i want to promote to, so I say "clickable_qlabel.h". However, when I call "make", I get "ui_mainWindow.h:95:5: error: ‘Clickable_QLabel’ does not name a type". Unfortunately I have no idea where I need to put clickable_qlabel.h, or whether it already exists and I just need to fill it with my code.
Any help would be greatly appreciated!
Many thanks.
[UPDATE]
OK, so now I have created the following class:
QLabelClickable.h
#ifndef _QLABELCLICKABLE_H_
#define _QLABELCLICKABLE_H_
#include <QLabel>
#include <QMouseEvent>
class QLabelClickable : public QLabel
{
Q_OBJECT
public:
explicit QLabelClickable( const QString& text="", QWidget* parent=0 );
~QLabelClickable();
signals:
void clicked(int, int);
protected:
void mousePressEvent(QMouseEvent* event);
};
#endif
QLabelClickable.cpp
#include "QLabelClickable.h"
QLabelClickable::QLabelClickable(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
QLabelClickable::~QLabelClickable()
{
}
void QLabelClickable::mousePressEvent(QMouseEvent* event)
{
emit clicked(event->x(),event->y());
}
So this code compiles beautifully. So now I am in QtDesigner and I create a QLabel, called label4, and I right click and select "Promote to". Then under "Promoted class name:" I type "QLabelClickable" and under "Header file:" I type "QLabelClickable.h". Then I click "Promote". Wonderful. But I am still getting the error:
Vigil/build/ui_mainWindow.h:328:42: error: no matching function for call to ‘QLabelClickable::QLabelClickable(QWidget*&)’ label_4 = new QLabelClickable(tab);
So clearly QtDesigner needs to be instructed (somehow) where my implementation of QLabelClickable is. Quite frustrating.
Eh. My error, I should have read the error message properly. I hadn't included a constructor for the passing of only a QWidget. Adding
QLabelClickable::QLabelClickable( QWidget* parent ) : QLabel(parent) {
}
to my CPP has solved the problem! Hooray.
I'm currently writing an application using MFC and CLR in visual studio, and my program is crashing whenever I call the constructor of a class I've written (the class is to control a camera over USB).
I've got a base class CameraBase:
class CameraBase
{
public:
virtual bool getFrame(cv::Mat& outImage) { return true; };
};
and a derived class LumeneraCamera (for the specific camera):
class LumeneraCamera : public CameraBase
{
public:
DLL_API LumeneraCamera();
DLL_API bool connect(int cameraNum);
DLL_API bool disconnect();
DLL_API bool getFrame(cv::Mat& outImage);
private:
//Bunch of misc variables
};
These classes are compiled into a DLL and accessed from another program:
int main()
{
cout << "Initing camera" << endl;
camera = new LumeneraCamera();
//More operations
}
When I run the program, it prints Initing camera and then fails because of an assertion in dllinit.cpp (line 133: VERIFY(AfxInitExtensionModule(controlDLL, hInstance));). It crashes before executing anything in the constructor. I'm not really sure what the problem is but it seems tied to MFC, so I'm currently looking into untangling my project from MFC entirely. Any suggestions or fixes are appreciated!
According to MSDN, if your DLL is dynamically linked against the MFC DLLs, each function exported from this DLL which call into MFC must have the AFX_MANAGE_STATE macro added at the very beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
I eventually solved it by disabling MFC - a library I was using suggested MFC but as far as I can tell works fine without it.
Background: So I've created an application that is basically a large preference dialog where the user can configure a number of pages, each with a bunch of different settings. These settings are in the form of dropdowns and text boxes. I want to store all of the variables into one massive "Parameters.h" file so that I can access them from anywhere in my application. Each sub-page has it's own source and header file.
I'm having trouble with the pointers though. I'm not sure how to reference the Parameters class. Basically, my application has two main components: a main dialog and a bunch of sub, child pages. The main dialog is where the sub-pages are shown and hidden, based on what page the user chooses in a listbox on the left of the main dialog.
I'm just working with one sub-page right now, and have the following, but when I debug, I'm getting <BadPtr> all over the place. I have greatly simplified the code, but it should be enough to figure out what I'm doing wrong.
Question: So how do I point to this Parameters class in each sub-dialog so that I can store and use all of these variables?
SAPrefsDialog.cpp: Main dialog that houses the sub-pages
BOOL CSAPrefsDialog::OnInitDialog()
{
CDialog::OnInitDialog();
FSC_Main fscMain;
fscMain.SetParametersPointer(&m_pParams);
// [ ... ]
}
SAPrefsDialog.h: Main dialog header file
#include "Parameters.h"
public:
CSAPrefsDialog(CWnd* pParent = NULL); // standard constructor
~CSAPrefsDialog();
Parameters m_pParams;
FSC_Main.h: Sub-page header file
#include "Parameters.h"
class FSC_Main : public CSAPrefsSubDlg
{
// Construction
public:
FSC_Main(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(FSC_Main)
enum { IDD = IDD_FS_CONFIG_MAIN };
//}}AFX_DATA
public:
void SetParametersPointer(Parameters* pParameters)
{ m_Params = pParameters; }
private:
Parameters *m_Params;
};
Parameters.h
#include "stdafx.h"
#include "prefs.h"
#pragma once
class Parameters
{
public:
Parameters(); // standard constructor
public:
~Parameters(void);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
public:
//*****************************************************************************
//
// FSC_Main.cpp Variables
//
//*****************************************************************************
CString m_strVehiclesMainNumVehicles;
CString m_strVehiclesMainMaxSensorCount;
CString m_strVehiclesMainTaskProcessingInterval;
CString m_strVehiclesMain
// [ ... ]
Parameters.cpp
#include "stdafx.h"
#include "prefs.h"
#include "pages.h"
#include "Parameters.h"
//*****************************************************************************
//
// Parameters::Parameters
//
//*****************************************************************************
Parameters::Parameters():
m_strVehiclesMainNumVehicles("")
, m_strVehiclesMainMaxSensorCount("")
, m_strVehiclesMainTaskProcessingInterval("")
// [ ... ]
{
}
The problem is that you're making the pages as local variables in CSAPrefsDialog::OnInitDialog, and those variables are destroyed as soon as you leave the function. You should make them as member variables of your CSAPrefsDialog class. Everything else you're doing looks fine.
I have create a simple MFC appwizard dialog project. I used the Class Wizard to create a new class called CMyDlg based on CDialog. Then I went to the Message Map screen and doubleclicked on the WM_INITDIALOG entry to automatically create a CMyDlg::OnInitDialog() handler.
The problem I have is that CMyDlg::OnInitDialog() will not call. I have put a breakpoint in there and it simply will not call. The parent dialog's OnInitDialog() method gets called, but it will not call the CMyDlg::OnInitDialog() method.
Is there something special than needs to be done?
I have managed to implement a workaround which is to send a message of my own from the parent dialog's OnInitDialog() method and have it handled in CMyDlg but.. I'm sure this is not the way to do it..
// MyDlg.cpp : implementation file
//
#include "stdafx.h"
#include "DeriveDlgTest.h"
#include "MyDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMyDlg dialog
CMyDlg::CMyDlg( UINT nIDTemplate, CWnd* pParent /*=NULL*/)
: CDialog(nIDTemplate, pParent)
{
// PDS: THIS GETS CALLED
}
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyDlg message handlers
BOOL CMyDlg::OnInitDialog()
{
// PDS: THIS DOES NOT GET CALLED
CDialog::OnInitDialog();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
#if !defined(AFX_MYDLG_H__ECC7F6AC_FEB3_419D_AFE2_6B6DE8196D74__INCLUDED_)
#define AFX_MYDLG_H__ECC7F6AC_FEB3_419D_AFE2_6B6DE8196D74__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MyDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CMyDlg dialog
class CMyDlg : public CDialog
{
// Construction
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
CMyDlg( UINT nIDTemplate, CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_DERIVEDLGTEST_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CMyDlg)
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MYDLG_H__ECC7F6AC_FEB3_419D_AFE2_6B6DE8196D74__INCLUDED_)
Thanks Guys. I've uploaded the dummy project to the link below. Try building the project and you will find that CMyDlg::OnInitDialog() is never called.
I removed the IDD enum and constructor as advised above but it didn't make any difference at all. There is not CMyDlg dlg; dlg.DoModal() call as the main dialog itself it derived from CMyDlg as opposed to the usual CDialog class.
I still haven't solved this issue so any help would be appreciated.
Cheers
link text
You derive
CDeriveDlgTestDlg from CMyDlg but inside CDeriveDlgTestDlg::OnInitDialog() you explicitly direct compiler to jump over base class and execute CDialog::OnInitDialog(), so CMyDlg::OnInitDialog() is never called.
You must not handle the WM_INITDIALOG message if you're using an MFC dialog.
The MFC CDialog class has a virtual method named OnInitDialog() which you must simply override and that one will get called.
You can create that method automatically from the "overrides" tab instead of the "window messages" tab in VS.
If you're using a Release build rather than Debug, you might have trouble setting breakpoints - they might get set on the wrong line, or ignored entirely. Either double check to see that you're using a Debug build, or find another way to determine that the code is or isn't being reached. I don't see anything obviously wrong with your code.
If you want to use CMyDlg as a base for other dialog classes, you cannot have the IDD set in your CMyDlg class. The IDD should be set on the class derived from CMyDlg.
So you should delete this:
enum { IDD = IDD_DERIVEDLGTEST_DIALOG };
and replace the standard constructor:
// in the .h file:
//CMyDlg(CWnd* pParent = NULL);
CMyDlg(LPCSTR szIDTemplate, CWnd* pParent = NULL );
// in the .cpp file:
CMyDlg::CMyDlg(LPCSTR szIDTemplate,CWnd* pParent /*=NULL*/)
: CDialog(szIDTemplate, pParent)
{
}
Edit: I just saw your link code. Have you noticed this in your derived class?
BOOL CDeriveDlgTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
You are calling CDialog::OnInitDialog(), not CMyDlg::OnInitDialog()!
In fact, you should replace all mentions of CDialog thar appear in CDeriveDlgTestDlg with CMyDlg. Do this and you're good to go.