孙鑫VC学习笔记 7(1)

时间:2022-05-14 21:12:44

1,动态创建按钮

enum{IDD=IDD_DLG1}; 将对话框与类关联起来...

1)增加全局变量 CButton m_btn;

//定义成局部变量不行 1)是一种解决方案;

//方案二是定义指针,在堆上分配内存,与整个应用程序的生命周期是一样的.

pDlg->Create

pDlg->ShowWindow

2)在需要创建的地方

//ID号123可以随意改变 //确实

模态:DoModal

非模态:

多次创建出现非法访问的问题:

方法2:

static BOOL bIsCreate=FALSE; //设置成static,则第一次初始化,以后就不会再改动它了

方法1:

if(m_bIsCreate==FALSE) {} else ... //下面是升级版

方法3:

if(!m_btn.m_hWnd) //如果没有这个条件判断,则会多次创建.

        m_btn.Create("维新",BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,CRect(0,0,100,100),this,123);

else

        m_btn.DestroyWindow(); //m_bIsCreate=FALSE;

2,复制控件

在dlg上添加控件时,按住ctrl键,拖动就可以复制一模一样的控件

3,控件对齐

在对话框上多个控件对齐,可以用layout菜单或者左下角toolbar

4,动态编辑static静态文本框

CString str;

if(GetDlgItem(IDC_NUMBER1)->GetWindowText(str),str=="Number1:")

GetDlgItem(IDC_NUMBER1)->SetWindowText("数值1:");

else

GetDlgItem(IDC_NUMBER1)->SetWindowText("Number1:");

要让static静态文本框响应消息,需要复选上notify选项

在属性页里面进行修改

5,Edit文本框

获取/设置文本内容

1)方法1

        char ch[10];

        GetDlgItem(IDC_EDIT1)->GetWindowText(ch1,10);

        GetDlgItem(IDC_EDIT3)->SetWindowText(itoa(atoi(ch1),ch1,10));

2)方法2

        GetDlgItemText(IDC_EDIT1,ch1,10);

        SetDlgItemText(IDC_EDIT3,itoa(atoi(ch1),ch1,10)); //此处10为进制

3)方法3

        SetDlgItemInt(IDC_EDIT3,GetDlgItemInt(IDC_EDIT1));//对整型数字的字符串有用

4)关联变量法

对每个Edit控件关联一个变量,设置后记得用UpdateData()

对于显示数字类的文本框,可以定义value和control两种类型变量

DoDataExchange() called by the framework to exchange and validate dialog data

The framework automatically calls UpdateData with bSaveAndValidate set to FALSE when a modal dialog box is created in the default implementation of CDialog::OnInitDialog.

value选择为int类型

void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CTestDlg)
    DDX_Control(pDX, IDC_EDIT3, m_edit3);
    DDX_Control(pDX, IDC_EDIT2, m_edit2);
    DDX_Control(pDX, IDC_EDIT1, m_edit1);
    DDX_Text(pDX, IDC_EDIT1, m_num1);
    DDV_MinMaxInt(pDX, m_num1, 0, 100);
    DDX_Text(pDX, IDC_EDIT2, m_num2);
    DDV_MinMaxInt(pDX, m_num2, 0, 100);
    DDX_Text(pDX, IDC_EDIT3, m_num3);
    //}}AFX_DATA_MAP
}

以上为变量与控件进行关联...

DDX_Text:将控件与成员变量进行关联 Dialog Data eXchange

DDV_MinMaxInt: Dialog Data Verification

MSDN 搜索DDV_大把

DoDataExchange主要被框架调用,用来交换数据

//问题: 若直接写m_num3=m_num1+m_num2;m_num1,num2 在对话框中显示正确,但调试运行显示num1和num2均为0,得不到其值.查MSDN如下:

Never call this function directly. It is called by the UpdateData member function. Call UpdateData to initialize a dialog box's controls or retrieve data from a dialog box.

BOOL UpdateData( BOOL bSaveAndValidate = TRUE ); 
bSaveAndValidate

Flag that indicates whether dialog box is being initialized (FALSE) or data is being retrieved (TRUE).
UpdateData() 获取值很直观

控件变量: 代表控件自己本身...

5)利用WM_GETTEXT消息处理获取文本

char ch1[10];

可以用以下四种方法(m_edit1为关联的控制型变量)

在OnBtnAdd函数里面加:

        ::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);

        ::SendMessage(m_edit1.m_hWnd,WM_GETTEXT,10,(LPARAM)ch1); //已经关联了一个控件变量,所以可以直接调用其m_hWnd得到句柄

        GetDlgItem(IDC_EDIT1)->SendMessage(WM_GETTEXT,10,(LPARAM)ch1);

        m_edit1.SendMessage(WM_GETTEXT,10,(LPARAM)ch1); //个人以为此为最简单

//以下代码都是一样的:

num1=atoi(ch1);
num2=atoi(ch2);
num3=num1+num2;
itoa(num3,ch3,10);

再: 利用WM_SETTEXT消息处理设置文本

        m_edit3.SendMessage(WM_SETTEXT,0,(LPARAM)ch3);

6)直接对对话框控件进行消息发送

        SendDlgItemMessage(IDC_EDIT1,WM_GETTEXT,10,(LPARAM)ch1);//获取文本

//组合了:获取对话框句柄+调用SendMessage函数

Using SendDlgItemMessage is identical to retrieving a handle to the specified control and calling the SendMessage function.

        SendDlgItemMessage(IDC_EDIT3,WM_SETTEXT,0,(LPARAM)ch3);//设置文本

        SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,-1);

7)利用EM_GETSEL,EM_SETSEL的消息处理

SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,3);

//问题: 并没有显示覆选的部分,因点击Add按钮以后,focus到了Add按钮上

m_edit3.SetFocus();

SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,-1);//将所有文本都选择上

//总结:

nGetDlgItem()->Get(Set)WindowText()

nGetDlgItemText()/SetDlgItemText()

nGetDlgItemInt()/SetDlgItemInt()

n将控件和整型变量相关联

n将控件和控件变量相关联

nSendMessage()

nSendDlgItemMessage()

6,对话框收缩

点击"收缩<<"对话框收缩,点击"扩展>>"则扩展, 请看例子代码

第一步: 增加Button, Caption改为"收缩<<"

当点击时,要将窗口切除一部分,再改成"扩张>>"

CTestDlg::OnButton2函数

void CTestDlg::OnButton2()
{

//第二步:
    // TODO: Add your control notification handler code here
    CString str;
    if(GetDlgItemText(IDC_BUTTON2,str),str=="收缩<<")
    {
        SetDlgItemText(IDC_BUTTON2,"扩展>>");
    }
    else
    {
        SetDlgItemText(IDC_BUTTON2,"收缩<<");
    }

//分隔符:利用图形控件来表示,将其拉成一条线,改ID为IDC_SEPARATOR, 属性页里面点击sucken,显示出下陷的样子

//要点: 收缩后x坐标不变,只是y方向长度发生变化

    static CRect rectLarge;
    static CRect rectSmall;

//对话框的尺寸要是保留下来的,故不能重复定义,要声明成static型的.
    if(rectLarge.IsRectNull())
    {

//注意区别:

IsRectEmpty

Determines whether CRect is empty. CRect is empty if the width and/or height are 0 or negative。

IsRectNull

Determines whether the top, bottom, left, and right member variables are all equal to 0.


        CRect rectSeparator;
        GetWindowRect(&rectLarge);
        GetDlgItem(IDC_SEPARATOR)->GetWindowRect(&rectSeparator);

        rectSmall.left=rectLarge.left;
        rectSmall.top=rectLarge.top;
        rectSmall.right=rectLarge.right;
        rectSmall.bottom=rectSeparator.bottom;//只有右下角的纵坐标发生了变化
    }
    if(str=="收缩<<")
    {
        SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),
            SWP_NOMOVE | SWP_NOZORDER);

Windows系统管理三个独立的Z次序——一个用于顶层窗口、一个用于兄弟窗口,还有一个是用于最顶层窗口。最顶层窗口覆盖所有其它非最顶层窗口,而不管它是不是活动窗口或是前台窗口。应用程序通过设置WS_EX_TOPMOST风格创建最顶层窗口。

一般情况下,Windows系统把刚刚创建的窗口放在Z次序的顶部,用户可通过激活另外一个窗口来改变Z次序;Windows系统总是把活动的窗口放在Z次序的顶部,应用程序可用函数BringWindowToTop把一个窗口放置到Z次序的顶部。函数SetWindowPos和DeferWindowPos用来重排Z次序。

任何时候系统中只能有一个顶层窗口是活动的。用户通过单击窗口(或其中的一个子窗口)、使用ALT+TAB或ALT+ESC组合键来激活一个顶层窗口,应用程序则调用函数SetActiveWindow来激活一个顶层窗口。

用户通过单击一个窗口、使用ALT+TAB或ALT+ESC组合键来设置前台窗口,应用程序则用函数SetForegroundWindow设置前台窗口。如果新的前台窗口是一个顶层窗口,那么Windows系统就激活它,换句话说,Windows系统激活相应的顶层窗口。

//详见PPT!!


    }
    else
    {
        SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),
            SWP_NOMOVE | SWP_NOZORDER);
    }
}

//最后,将IDC_SEPARATOR的Visible设为否

7,多个edit框用Enter键切换的方法,三种方法

OK按钮: 属性-->Styles-->Default botton勾选上,则设为Default

//勾选去掉

//看如下强大的函数

LONG SetWindowLong( 

HWND hWnd, int nIndex, LONG dwNewLong );

If the function succeeds, the return value is the previous value of the specified 32-bit integer.

//

1)捕获键盘消息,在消息函数中处理(未提供)

第一步:

2)修改Edit的窗口过程:自己写窗口过程替代原来的窗口过程(比较麻烦的方法)

  (1)定义窗口过程类型变量

   WNDPROC prevProc; //就在CTestDlg::OnInitDialog()函数之前定义

第三步:如何写窗口过程? 查WNDCLASS!!

  (2)定义窗口过程函数

  LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam )

  {

   if(uMsg==WM_CHAR && wParam==0x0d)//如果WM_CHAR消息并且是回车

   {

    //::SetFocus(::GetNextWindow(hwnd,GW_HWNDNEXT));//获取下一窗口句柄方法一

注意: Edit1: //Styles--MultiLine勾选以后,才能响应回车消息!!

GW_HWNDNEXT
Returns a handle to the window below the given window.
GW_HWNDPREV
Returns a handle to the window above the given window.

    //SetFocus(::GetWindow(hwnd,GW_HWNDNEXT));//方法二

    SetFocus(::GetNextDlgTabItem(::GetParent(hwnd),hwnd,FALSE));//方法三

//属性而中General-->Tab Stop (静态文本就没有)

//FALSE搜索下一个控件,TRUE搜索先前控件

    return 1;

   }

   else

       return prevProc(hwnd,uMsg,wParam,lParam);

  }

//第二步:

  (3)添加WM_INITDIALOG对应的函数

  (4)在OnInitDialog中添加 //响应WM_INITDIALOG!!

说明在下面:Sent to a dialog box before the dialog box is displayed

   prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,(LONG)WinSunProc);

GWL_WNDPROC

Sets a new address for the window procedure.

  (5)注意 edit控件 MultiLine复选属性选/不选的不同

SetWindowLong changes an attribute of the specified window.

  3)在OnOK(default button对应的函数)

//利用OnOk(默认响应)函数实现按Enter键时自动Tab

void CTestDlg::OnOK()
{
    // TODO: Add extra validation here
    //GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus();//定死为EDIT1,注释之
    //GetFocus()->GetNextWindow()->SetFocus();//一直回车,出现非法访问;

//因一直回车,GetFocus()->GetNextWindow()->得到的是一个空指针...
    //GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();//GW_HWNDNEXT获取下一窗
    GetNextDlgTabItem(GetFocus())->SetFocus();//真正正确,第二个参数缺省为FALSE,搜寻下一个控件
//    CDialog::OnOK();
}

  GetFocus()->GetNextWindow()->SetFocus();//注意最后一个窗口时要判断,不然获取出错

  GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();//注意同上

  GetNextDlgTabItem(GetFocus())->SetFocus();

Layout-->Tab order (shortcut: Ctrl+D)

将收缩按钮设为Default的,则不由IDOK响应函数来响应

注意: 对话框初始的OK的ID号为IDOK,即使删除按钮(OnOk函数存在),依然会响应OnOk函数

注意缺少的虽IDOK 而不是 IDC_OK,切记切记!!

第7课  对话框用户界面程序的编写

动态添加Button
访问对话框上的子窗口:
获取对话框上的项目指针:GetDlgItem()
获取窗口信息:GetWindowText()
更改窗口信息:SetWindowText()
直接取得指定对话框上项目的信息:GetDlgItemText() 想当于GetDlgItem()和GetWindowText()合用。
当然,也有SetDlgItemText() 相当于GetDlgItem()和SetItemText() 合用。
GetDlgItemInt(),SetDlgItemInt()等等,S/GetDlgItemInt()可以处理有符号的整数。
字符到数组的转换:atoi()  转换一个类型到指定类型时,用 类型的第一个字母 to 指定类型的一个字母。
在DoExchange函数里,放置以DDX_为前缀的函数,来关联一个控件和变量,DDV_为前缀的函数,用来校验一个控件内容。
DDX_(对话框数据交换)   DDV_(对话框数据校验)
注意,在用数据变量关联控件的方式时,千万注意要使用UpdateData()!
也可以用一个控件变量关联一个控件,用它的成员函数,来对控件进行操作,例如:CEDIT.GetWindowText()
SendMessage()的用法,比较好用,注意,发送消息,是控件向系统发送,由系统处理。
SendDlgItemMessage()。

总结以上:
1, GetDlgItem()->G/SetWindowText()。
2, G/SetDlgItemText()。
3, G/SetDlgItemInt。
4, 将一个控件和一个整型变量相关联。
5, 将一个控件和一个控件变量相关联,用成员函数GetWindowText()和SetWindowText()去访问控件。
6, SendMessage(),可以用平台SDK,也可以用CWND成员函数。
7, SendDlgItemMessage()。
两个好用的消息:EM_GETSEL,EM_SETSEL: 取得与设置选择内容的位置。
改变窗口的大小Wnd::SetWindowPos()对话框从父类继承来的函数。
看一下用控件变量关联控件时,那些成员,例如Button的default。
消息:WM_INITDIALOG,在一个对话框和其上的控件建立完成之后,由对话框发送,当时,对话框还没显示。
Sent to a dialog box before the dialog box is displayed。


伸缩对话框:
判断一个矩形是否为空:IsRectEmpty(), IsRectNull()。前者是判断矩形面积是否为空,后者是判断矩形的四个坐标值是否为0,不关心是否能成为一个矩形。
·····SetWindowPos()改变窗口的大小和Z次序的排列。 ·····
焦点的问题:
SetWindowLong~~~~~~~~  超强的函数。
::GetNextWindow()
::GetWindow()
::GetNextDlgTabItem()
CWnd::GetWindow()
CWnd::GetNextWindow
CWnd::GetNextDlgTabItem()
缺省OK按钮的ID为IDOK