zl程序教程

您现在的位置是:首页 >  其它

当前栏目

MFC中的一般经验之谈4

mfc 一般 经验之谈
2023-09-27 14:21:09 时间

  MFC中的窗口控件,都是从CWnd类中继承的。MFC以及ResourceEditor支持的所有控件称为标准控件。

  在对话框资源文件夹下,然后邮件新建添加新对话框,新建对话框后要在资源视图中的对话框文件夹下修改对话框的ID .添加新对话框资源后保存,在添加类向导,MFC则自动弹出“类定义”向导,将新生成的类与新创建的对话框资源相关联的向导。在类向导中可以定义生成的类头文件与定义文件的物理位置,这样可以在物理存储层面对代码进行管理。注意在.cpp .h文件修改时,需要(1)添加引用目录的形式,或者(2)修改包含文件中添加相对目录,注意“当前文件”目录位置为参考进行填写,我的另一篇博客中的如何处理相对路径的原则(http://www.cnblogs.com/icmzn/articles/5720097.html)

  

  处理对话框两部(1)调整显示对话框UI,(2)编辑对话框用户交互逻辑。

  调整显示对话框,为对话框添加资源,在工具控件框中1,拖动控件到对话框,2选中控件,然后单击需要绘制位置的窗口地方。【分组框】把单选按钮放置在一个组内。对话框编辑好后,可以通过Ctrl + T 进行预览测试操作

  对话框资源与对话框类如何关联的???(WWW.icmzn.com)

  (1)对话框保存在.rc文件中,对话框ID是需要用户设定,然后MFC自动在Resource.H中添加此ID对应的值,(2)在DialogAAA.h对话框对应的类的头文件中,生命了此对话框类对应的对话框资源,通过IDD枚举定义与对话框资源的ID标尺一致。(3)这三个文件的内部关联关系如下图所示。

  Resource.h这个文件时MFC自动维护的,所以如果在对话框资源中进行变更对话框ID或者只控件的ID的时候,之前变更的ID将会永久保存在这个文件中,所以可以通过对Resource.h这个文件的人工检查,可以删除没有使用的ID的条目项,这样“净化”项目中的文件。

  

在类中初始化类的成员的方式:

(1)通过在类的内部赋值,则使用枚举的方式,将类的成员通过枚举形式进行赋值处理;

(2)在类的内部直接赋值,则需要把类的成员声明为静态常量类型:const static int IDO=IDD_DIALOG_NUMBER;因为对话框的ID在创建对话框资源的时候已被MFC自动添加其ID值得定义为一个值。

  编辑对话框,利用类向导新建一个此对话框对应的类。在对话框资源窗口上的所有控件,都会讲控件本身关联到此对话框窗口

  对话框有两种:模态对话框和非模态对话框。模态对话框通过Dlg.doModel()创建;费模态对话框则需要通过在其父类对话框的构造函数中调用NoDlg.create()创建非模态对话框对象。

  子类窗口可以通过重载父类窗口的某些方法,这样可以对消息处理流进行“拦截”。如对话框的OK,与Concle按钮,则需要重载父类的OnOK(), OnConcle(),这样在用户点击OK或者Cancle后,在对话框关闭之前进行“特殊时刻”进行处理,在函数中需要在最后调用基累的处理消息。其次在对话框结束后会返回IDOK,IDCONCLE。非模态对话框,在OnOKey()OnCancle()中调用默认是隐藏模态对话框,可以在函数内调用基累的CWNd::DestroyWindow()销毁对话框。

  通过VS2013的“格式”菜单--Order顺序,菜单项,调整Tab建的顺序。

  为对话框资源添加对应的类对象后,可以添加类的成员函数,这样对话框类实现重新实现了基累的如下函数, 实现对话框资源变量的数据传递。两种成员函数一种是CPP基本类型的成员,另一种是空间类型的成员,后者可以很好的实现对话框控制键与控件类成员自由的数据交换。该函数是由MFC框架自动调用的,用于交换对话框成员变量与控件之间的数据交换。DDX:DoDataExchange,执行数据交换。DDV:DoDataValidate:执行数据校验。

  下面代码中DDX执行控件ID为IDC_BUTTON2,以及与对话框成员变量m_btn2自动的数据交换。前者是对子话框显示之前自动调用,将对话框类的成员变量中的值传到对话框,当对话框点击OK按钮关闭后,DDX又再次被自动调用,数据放置到本对话框中的成员变量中保存。即显示对话框之前修改对话框对应类的成员变量值,在对话框正常OK关闭后,从成员变量中取回设定的值。CDataExchange类是一个标定数据传输方向的对象类。

头文件声明  XXX.h:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

----------------------
定义文件  XXX.pp
void CTExtJCDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON2, m_btn2);
}

  virtual BOOL OnInitDialog( );对话框控制类可以继承实现父类的此函数,用以响应WM_INITDIALOG消息。此函数在DoMOdel(),Create()之后,在对话框显示之前被调用。用以在对话框显示之前调整一些默认行为,如默认焦点的位置。在重写的版本,首先调用基类 OnInitDialog,但忽略其返回值。 通常将返回从重写的方法中 TRUE。重载形式如下图所示

BOOL CSimpleDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // TODO: Add extra initialization here
   m_cMyEdit.SetWindowText(_T("My Name")); // Initialize control values
   m_cMyList.ShowWindow(SW_HIDE);      // Show or hide a control, etc.

   return TRUE;  // return TRUE unless you set the focus to a control
   // EXCEPTION: OCX Property Pages should return FALSE
}

  CWnd* GetDlgItem(  int nID ) const;
  HWND* GetDlgItem(   int nID,  HWND* phWnd) const;//返回任意特定窗口上的特定控件

  nID 指定要检索的控件或子窗口的标识符ID。phWnd 指针指向的窗口,需要进行类型转化特定控件的类型。如果ID不存在,怎返回的CWnd指针为NULL

  窗口的缩放显示:WinOS有两种“逻辑坐标”“设备坐标”之间映射关系的映射模式:MM_ANISOTROPIC, MM_ISOTROPIC.前者允许对每个轴进行缩放,而后者智能将两轴等比例缩放。

  (1)逻辑坐标(页面坐标),由映射模式决定。MM_LONENGLISH,定义是以0.01英寸为最小的逻辑单位,坐标原点在左上角,向右X正,向下Y正。逻辑坐标由“设备上下文”的绘图函数使用

  (2)设备坐标(在设备窗口中称为客户单坐标),在客户端窗口中是以“像素”为最小单位进行量度,坐标原点在左上角,向右X正,向下Y正。设备坐标是在设备上下文的外部使用,如在鼠标消息响应函数中定义光标的位置,以像素为量度。  

  (3)屏幕坐标,以像素为量度单位。

  在两种映射模式中:“逻辑坐标”转化为“设备坐标”的方式,以下函数决定,

  

  视口ViewPort与窗口Window,定义了如何把“逻辑坐标”转化为“设备坐标”,即如何把实际英寸坐标通过窗口的逻辑坐标Window的定义转化为像素坐标。其中需要说明的是:逻辑窗口Window定义是为了调整设备中显示屏原点的位置设置划分的。设备视口ViewPort定义,是为了将实际坐标“映射缩放”的视口(设备窗口)的位置。

  WinOS中把实际逻辑坐标系中的点(Xlogical, Ylogical)默认英寸。 通过 [逻辑窗口定义][视口窗口定义]转化为设备坐标中的一点(Xdevice, Ydevice)像素。  通过设置“逻辑窗口尺寸”以及“视口尺寸”可以完成缩放的效果展示

  

  

   CWnd::onPrepareDC(),可以在窗口收到任何WM_PAINT,消息后先调用这个函数,然后在调用OnDraw()。所以可以在OnDraw之前设置设备上下文,完成缩放相关的设置。

  状态栏的使用

  MainFrame成员中有m_wndStateBar,控制状态栏的指针,切实protected的成员。类型CMFCStateBar。状态栏、工具栏、菜单栏都是框架类的组成部分,不是View类的控制区域。

protected:  // 控件条嵌入成员
    CStatusBar        m_wndStatusBar;

  在框架类的onCreate(),函数中设置状态栏的操作如下

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    if (!m_wndStatusBar.Create(this))
    {
        TRACE0("未能创建状态栏\n");
        return -1;      // 未能创建
    }
    m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
    return 0;
}

   状态栏在框架类的CPP文件中,需要使用一个UINT类型的指示器常量数组,数组中的内容已经由MFC设置初值仅仅作为一个标记。但是要在资源视图中的字符串资源中添加自定义的指示器标识ID,以及值,以及响应的显示内容。注意指示器ID_INDICATOR_这种约束格式,且如果右键插入String,则值是MFC自动设置的,需要自己为自己的指示器添加“显示内容”即可。

  

  数组有几个元素,代表指示器的状态有几个。

static UINT indicators[] =
{
    ID_SEPARATOR,           // 状态行指示器
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
    ID_INDICATOR_OVR,
    ID_INDICATOR_CAPS, 
    ID_INDICATOR_JOHNCHUANG,

};

  由于新添加了三个,则指示显示三个,默认第一个元素表示指示器分隔符的样式,其他可以不管。

  

  以上是工具栏的原理,如果需要对各个指示器进行实时更新处理,则需要做一下修改:

  (1)根据指示器关联的变量以及所在的位置,在乡音的Doc类,或者View类,或者Frame类中添加消息响应函数,

  用类向导进行添加ON_UPDATE_COMMAND_UI响应函数,关联指示器的ID(即指示器标识数组中的ID)及相关的处理函数。

BEGIN_MESSAGE_MAP(CTextEditorView, CView)
    ON_UPDATE_COMMAND_UI(ID_INDICATOR_JOHNCHUANG, &CTextEditorView::OnUpdateIndicatorJohnchuang)
END_MESSAGE_MAP()

  (2)在处理函数中,修改本响应函数对应的表示ID命令状态的修改。其中参数代表:当前状态栏的指针。

void CTextEditorView::OnUpdateIndicatorJohnchuang(CCmdUI *pCmdUI)
{
    pCmdUI->Enable();
    CString text;
    text.Format(_T("AAAA   %d"), 100);
    pCmdUI->SetText(text);
}