MFC 之 IPControl 的使用

       最近在做一个音频传输的项目,现在已经到了界面的部分了,决定使用MFC来写一个界面,通信必然离不了IP,今天写的是MFC中IP控件的使用。这里模仿VS的界面做一个静态IP配置的界面,如下所示:

注意:对话框下面的按钮有两个,分别是确定和取消按钮,后面隐藏了确认按钮,并将按钮取消改成完成

该对话框的效果是:

1.点第一个Radio控件,后面Group控件内的所有IP框变灰,不接受输入;

2.点第二个Radio控件,后面三个IP控件接受输入;

3.当焦点移到子网掩码控件时,根据输入的IP自动生成;

4.在IP框输入时,按键盘Enter键,焦点依次下移;

5.点击完成按钮,弹出确认对话框。

查看MSDN上该类的成员函数,如下:  

void ClearAddress();
清除IP地址控件中的内容。

BOOL IsBlank();
如果IP地址控件的所有域均为空,返回非0值;否则返回0。

void SetAddress(BYTE nField0,BYTE nField1,BYTEnField2,BYTE nField3);
void SetAddress(DWORD dwAddress);
设置IP地址控件中的地址值。
第一种形式是用4个0~255的整数分别设置IP地址各个域的值。
第二种形式是用1个长整数设置IP地址值。

int GetAddress(BYTE& nField0,BYTE&nField1,BYTE& nField2,BYTE& nField3);
int GetAddress(DWORD& dwAddress);
获取IP地址控件中的地址值。
第一种形式是把IP地址的4个域填充到用4个引用中。
第二种形式是把IP地址填充到1个长整数的引用中。
返回值:IP地址控件中非空域的数量。

void SetFieldFocus(WORD nField);
把焦点设置在指定的域中。nField取值为0~3,如果大于3,则焦点设置到第一个空域中,若所有域均非空,则 焦点设置在第一个域中。

void SetFieldRange(int nField,BYTE nLower,BYTE nUpper);
设置指定域中数值的取值范围。
nField:域索引,取值0~3;
nLower:域的下限;
nUpper:域的上限。


1, 首先创建基于对话框的MFC应用程序,名为:IPControl,然后按上图,排好控件后,分别为三个IP框添加三个控制变量,m_Addr1,m_Addr2,m_Addr3,分别依次对应IP,Netmask,Dns。

2,现在来完成效果1和效果2;

在对话框上右击鼠标,添加BOOL变量IP_From,这里IP_From = FALSE表示IP地址是自动获取的,IP_From = TRUE,则表示手动配置;

然后添加函数EnableIp(),用来控制三个IP框是否变灰,代码如下:

void CIPControlDlg::EnableIp()
{     
	 m_Addr1.EnableWindow( IP_From ); 
	 m_Addr2.EnableWindow( IP_From );  
	 m_Addr3.EnableWindow( IP_From ); 
}

在资源页面,分别双击两个Radio控件,添加控件处理函数,其中点击第一个Radio控件时,让三个IP控件中的内容清空,用成员函数ClearAddress();当点击第二个Radio控件时,让焦点默认停在第一个IP控件上。具体代码如下:

void CIPControlDlg::OnBnClickedRadio1()
{
	// TODO: 在此添加控件通知处理程序代码
	IP_From = FALSE;
	m_Addr1.ClearAddress();
	m_Addr2.ClearAddress();
	m_Addr3.ClearAddress();
	EnableIp();
}

void CIPControlDlg::OnBnClickedRadio2()
{
	// TODO: 在此添加控件通知处理程序代码
	IP_From = TRUE;
	EnableIp();
	m_Addr1.SetFieldFocus(0);
}

OnInitialDialog()中添加如下代码来设置默认效果:

<span style="font-size:14px;">CheckDlgButton(IDC_RADIO1,TRUE);
CheckDlgButton(IDC_RADIO2,FALSE);
EnableIp();//这里因为IP_From 初始化为False了,所以默认三个IP控件为灰色</span>

点击运行,效果如下:

 

3,实现第三个效果:对于子网掩码,我们都知道,只需要知道IP第一个域的值就能得以确定

这里采用消息传递的形式,根据函数OnSetfocus()来设置这样的效果,由于在VS2010中没有看到EN_SETFOCUS这个消息,因此这里选择手动添加。

1)点击对话框资源,右击添加类CSubNetMask;并在头文件中添加IP控件指针CIPAddressCtrl *m_IPAddrCtrl用来获取输入的IP地址,同时在构造函数中初始化该指针为NULL;并在OnInitialDialog()中添加如下代码,让该指针指向IP地址的输入框:

m_Addr2.m_IPAddrCtrl = &m_Addr1;

2)在SubNetMask.h中添加消息处理函数afx_msg void OnSetfocus(),并在在SubNetMask.cpp中添加消息处理函数如下:

<span style="font-size:14px;">BEGIN_MESSAGE_MAP(CSubNetMask, CIPAddressCtrl)
	ON_CONTROL_REFLECT(EN_SETFOCUS,&CSubNetMask::OnSetfocus)//  手动添加消息处理函数
END_MESSAGE_MAP();

void CSubNetMask::OnSetfocus()//  手动添加消息处理函数
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_IPAddrCtrl && IsBlank())
	{
		BYTE field1,field2,field3,field4;
		m_IPAddrCtrl->GetAddress(field1,field2,field3,field4);
		if (field1 >= 0 && field1<= 127)
		{
			SetAddress(255,0,0,0);
		}
		else if (field1 >= 128 && field1 <=191)
		{
			SetAddress(255,255,0,0);
		}
		else if (field1 >= 192 && field1 <=223)
		{
			SetAddress(255,255,255,0);
		}
	}
}</span>
这里根据 m_IPAddrCtrl指针和GetAddress()获取输入的IP地址,并根据输入IP的第一个域的值来设置子网掩码。

3)将IPControl.h中m_Addr2的类型改成CSubNetMask;

4,实现第四个效果,这就涉及到修改MFC控件的窗口过程了,这在孙鑫老师的视频教程第7课也讲到了。主要是根据缺省的控件来响应键盘按下的消息。步骤如下:

1)首先资源界面双击确定按钮进入OnBnClickedOk()函数代码区,并注释掉CDialogEx::OnOK();语句;

2)添加窗口过程的步骤如下代码所示:IPControlDlg.cpp中添加如下代码,注意不是在任何函数中添加,这里面添加的是全局的,所以要使用WINAPI函数来编程;

<pre name="code" class="cpp">WNDPROC prevProc; //回调函数

static LRESULT CALLBACK WinMyProc(
	HWND hWnd,
	UINT uMsg,
	WPARAM wParam,
	LPARAM lParam 
	)
{
	if (uMsg == WM_CHAR && wParam == 0x0d)
	{
		//::SetFocus(::GetNextWindow(hWnd,GW_HWNDNEXT));
		::SetFocus(GetNextDlgTabItem(::GetParent(hWnd),hWnd,FALSE));//当键盘按下Enter键时,将焦点转移到下个tab按钮处
									//这里的tab按钮可以在对话框资源界面按Ctrl+D来设置顺序
		return 1;
	}
	else
	{
		return prevProc(hWnd,uMsg,wParam,lParam);
	}
}

 
本来这里面是要响应WM_INITIALDLG消息的,由于VS2010取消了这个消息,而以函数OnInitialDialog()直接来实现,所以这边就不需要再添加消息处理函数了,只需要在OnInitialDialog()中添加如下代码即可: 

<span style="font-size:14px;">prevProc = (WNDPROC)SetWindowLong(GetDlgItem(IDC_IPADDRESS1)->m_hWnd, GWL_WNDPROC, (LONG)WinMyProc);</span>

3)资源界面双击确定按钮进入OnBnClickedOk()函数代码区,添加如下代码:

<span style="font-size:14px;">GetNextDlgTabItem(GetFocus())->SetFocus();</span><span style="font-size:18px; color: rgb(204, 51, 204); ">	</span>

5,实现效果5:这个效果就比较简单了,首先资源界面双击取消按钮,进入代码区,设置效果5,如下代码所示:

<span style="font-size:14px;">void CIPControlDlg::OnBnClickedCancel()
{
<pre name="code" class="cpp">	if (IDYES== MessageBox("是否确认修改?","确认",MB_YESNO))
	{
		CDialogEx::OnCancel();
	}
}</span>
 
然后将资源界面右击属性按钮,在属性中隐藏此按钮。 

至此,该对话框的效果已经全部实现了,下面附上主要代码段

<span style="font-size:14px;">// IPControlDlg.h : 头文件
//

#pragma once
#include "afxcmn.h"
#include "SubNetMask.h"


// CIPControlDlg 对话框
class CIPControlDlg : public CDialogEx
{
// 构造
public:
	CIPControlDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_IPCONTROL_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void EnableIp();

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedRadio1();
	afx_msg void OnBnClickedRadio2();
	afx_msg void OnIpnFieldchangedIpaddress2(NMHDR *pNMHDR, LRESULT *pResult);
public:
	CIPAddressCtrl m_Addr1;
	CSubNetMask m_Addr2;
	CIPAddressCtrl m_Addr3;
	BOOL IP_From;   //单选按钮的位置,为0表示自动获取
	DWORD m_IP;
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedCancel();
};</span><span style="color: rgb(204, 51, 204); font-size: 18px; ">
</span>
// IPControlDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "IPControl.h"
#include "IPControlDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CIPControlDlg 对话框

CIPControlDlg::CIPControlDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CIPControlDlg::IDD, pParent)
	, IP_From(FALSE)
	, m_IP(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CIPControlDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_IPADDRESS1, m_Addr1);
	DDX_Control(pDX, IDC_IPADDRESS2, m_Addr2);
	DDX_Control(pDX, IDC_IPADDRESS3, m_Addr3);
}

BEGIN_MESSAGE_MAP(CIPControlDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_RADIO1, &CIPControlDlg::OnBnClickedRadio1)
	ON_BN_CLICKED(IDC_RADIO2, &CIPControlDlg::OnBnClickedRadio2)
	ON_BN_CLICKED(IDOK, &CIPControlDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CIPControlDlg::OnBnClickedCancel)
END_MESSAGE_MAP()


// CIPControlDlg 消息处理程序

WNDPROC prevProc; //回调函数

static LRESULT CALLBACK WinMyProc(
	HWND hWnd,
	UINT uMsg,
	WPARAM wParam,
	LPARAM lParam 
	)
{
	if (uMsg == WM_CHAR && wParam == 0x0d)
	{
		//::SetFocus(::GetNextWindow(hWnd,GW_HWNDNEXT));
		::SetFocus(GetNextDlgTabItem(::GetParent(hWnd),hWnd,FALSE));//当键盘按下Enter键时,将焦点转移到下个tab按钮处
																	//这里的tab按钮可以在对话框资源界面按Ctrl+D来设置顺序
		return 1;
	}
	else
	{
		return prevProc(hWnd,uMsg,wParam,lParam);
	}
}

BOOL CIPControlDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	CheckDlgButton(IDC_RADIO1,TRUE);
	CheckDlgButton(IDC_RADIO2,FALSE);
	EnableIp();

	m_Addr2.m_IPAddrCtrl = &m_Addr1;

	prevProc = (WNDPROC)SetWindowLong(GetDlgItem(IDC_IPADDRESS1)->m_hWnd, GWL_WNDPROC, (LONG)WinMyProc);
	

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CIPControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CIPControlDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CIPControlDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CIPControlDlg::EnableIp()
{     
	 m_Addr1.EnableWindow( IP_From ); 
	 m_Addr2.EnableWindow( IP_From );  
	 m_Addr3.EnableWindow( IP_From ); 
}

void CIPControlDlg::OnBnClickedRadio1()
{
	// TODO: 在此添加控件通知处理程序代码
	IP_From = FALSE;
	m_Addr1.ClearAddress();
	m_Addr2.ClearAddress();
	m_Addr3.ClearAddress();
	EnableIp();
}

void CIPControlDlg::OnBnClickedRadio2()
{
	// TODO: 在此添加控件通知处理程序代码
	IP_From = TRUE;
	EnableIp();
	m_Addr1.SetFieldFocus(0);
}




void CIPControlDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	GetNextDlgTabItem(GetFocus())->SetFocus();
	//CDialogEx::OnOK();
}


void CIPControlDlg::OnBnClickedCancel()
{
<pre name="code" class="cpp">	if (IDYES== MessageBox("是否确认修改?","确认",MB_YESNO))
	{
		CDialogEx::OnCancel();
	}
}
 
#pragma once
#include "afxcmn.h"
class CSubNetMask :
	public CIPAddressCtrl
{
public:
	CSubNetMask(void);
	~CSubNetMask(void);


public:



public:
	CIPAddressCtrl *m_IPAddrCtrl;

protected:

	afx_msg void OnSetfocus();
	DECLARE_MESSAGE_MAP();
};

#include "StdAfx.h"
#include "SubNetMask.h"


CSubNetMask::CSubNetMask(void)
{
	m_IPAddrCtrl =NULL;
}


CSubNetMask::~CSubNetMask(void)
{
}

BEGIN_MESSAGE_MAP(CSubNetMask, CIPAddressCtrl)
	ON_CONTROL_REFLECT(EN_SETFOCUS,&CSubNetMask::OnSetfocus)//  手动添加消息处理函数
END_MESSAGE_MAP();

void CSubNetMask::OnSetfocus()//  手动添加消息处理函数
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_IPAddrCtrl && IsBlank())
	{
		BYTE field1,field2,field3,field4;
		m_IPAddrCtrl->GetAddress(field1,field2,field3,field4);
		if (field1 >= 0 && field1<= 127)
		{
			SetAddress(255,0,0,0);
		}
		else if (field1 >= 128 && field1 <=191)
		{
			SetAddress(255,255,0,0);
		}
		else if (field1 >= 192 && field1 <=223)
		{
			SetAddress(255,255,255,0);
		}
	}
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值