MFC 触摸屏虚拟数字键盘思路

文章描述了在MFC项目中如何创建一个简单的数字键盘,包括使用CDialogEx类、处理键盘输入和调用PreTranslateMessage函数来控制键盘显示。作者分享了关键代码段和整体实现思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天在MFC项目上需要用到触摸屏,在一开始本来是调用外部键盘的,但是上级不太愿意只好自己写一个简单的数字键盘使用。下面我会把写的思路和代码贴出来,键盘界面还是得自己创建,我贴代码是给个参考。

下面是cpp

// CKeyBoard.cpp: 实现文件
//

#include "stdafx.h"
#include "Resource.h" //其它头文件里包括这个即可
#include "CKeyBoard.h"
#include "afxdialogex.h"


// CKeyBoard 对话框

IMPLEMENT_DYNAMIC(CKeyBoard, CDialogEx)

CKeyBoard::CKeyBoard(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_KEYBOARD, pParent)
{

}

CKeyBoard::~CKeyBoard()
{
}

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


BEGIN_MESSAGE_MAP(CKeyBoard, CDialogEx)
	ON_BN_CLICKED(IDC_BTN_Num1, &CKeyBoard::OnBnClickedBtnNum1)
	ON_BN_CLICKED(IDC_BTN_Num2, &CKeyBoard::OnBnClickedBtnNum2)
	ON_BN_CLICKED(IDC_BTN_Num3, &CKeyBoard::OnBnClickedBtnNum3)
	ON_BN_CLICKED(IDC_BTN_Num4, &CKeyBoard::OnBnClickedBtnNum4)
	ON_BN_CLICKED(IDC_BTN_Num5, &CKeyBoard::OnBnClickedBtnNum5)
	ON_BN_CLICKED(IDC_BTN_Num6, &CKeyBoard::OnBnClickedBtnNum6)
	ON_BN_CLICKED(IDC_BTN_Num7, &CKeyBoard::OnBnClickedBtnNum7)
	ON_BN_CLICKED(IDC_BTN_Num8, &CKeyBoard::OnBnClickedBtnNum8)
	ON_BN_CLICKED(IDC_BTN_Num9, &CKeyBoard::OnBnClickedBtnNum9)
	ON_BN_CLICKED(IDC_BTN_Num0, &CKeyBoard::OnBnClickedBtnNum0)
	ON_BN_CLICKED(IDC_BTN_Del, &CKeyBoard::OnBnClickedBtnDel)
	ON_BN_CLICKED(IDC_BTN_Point, &CKeyBoard::OnBnClickedBtnPoint)
	ON_BN_CLICKED(IDOK, &CKeyBoard::OnBnClickedOk)
END_MESSAGE_MAP()


// CKeyBoard 消息处理程序
BOOL CKeyBoard::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  在此添加额外的初始化
	CFont* f;
	f = new CFont;
	f->CreateFont(36, // 字体高度
		0, // 字体宽度
		0, // 字体倾斜角
		0, // 字体倾斜角
		FW_BOLD, // 字体的粗细
		FALSE, // 字体是否为斜体
		FALSE, // 字体是否有下划线
		0, // 字体是否有删除线
		ANSI_CHARSET, // 字体使用的字符集
		OUT_DEFAULT_PRECIS, // 指定如何选择合适的字体
		CLIP_DEFAULT_PRECIS, // 确定裁剪的精度
		DEFAULT_QUALITY, // 怎么样跟选择的字体相符合
		DEFAULT_PITCH | FF_SWISS, // 间距标志和属性标志
		_T("楷体"));

	GetDlgItem(IDC_EDIT1)->SetFont(f);
	GetDlgItem(IDC_BTN_Num1)->SetFont(f);
	GetDlgItem(IDC_BTN_Num2)->SetFont(f);
	GetDlgItem(IDC_BTN_Num3)->SetFont(f);
	GetDlgItem(IDC_BTN_Num4)->SetFont(f);
	GetDlgItem(IDC_BTN_Num5)->SetFont(f);
	GetDlgItem(IDC_BTN_Num6)->SetFont(f);
	GetDlgItem(IDC_BTN_Num7)->SetFont(f);
	GetDlgItem(IDC_BTN_Num8)->SetFont(f);
	GetDlgItem(IDC_BTN_Num9)->SetFont(f);
	GetDlgItem(IDC_BTN_Num0)->SetFont(f);
	GetDlgItem(IDC_BTN_Del)->SetFont(f);
	GetDlgItem(IDC_BTN_Point)->SetFont(f);

	SetWindowText(_T("KeyBoard"));

	return TRUE;  // return TRUE unless you set the focus to a control
				  // 异常: OCX 属性页应返回 FALSE
}

void CKeyBoard::OnBnClickedBtnNum1()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("1"));
	}
	else
	{
		str.Append(_T("1"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum2()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("2"));
	}
	else
	{
		str.Append(_T("2"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum3()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("3"));
	}
	else
	{
		str.Append(_T("3"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum4()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("4"));
	}
	else
	{
		str.Append(_T("4"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum5()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("5"));
	}
	else
	{
		str.Append(_T("5"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum6()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("6"));
	}
	else
	{
		str.Append(_T("6"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum7()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("7"));
	}
	else
	{
		str.Append(_T("7"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum8()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("8"));
	}
	else
	{
		str.Append(_T("8"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum9()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("9"));
	}
	else
	{
		str.Append(_T("9"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnNum0()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{
		SetDlgItemText(IDC_EDIT1, _T("0"));
	}
	else
	{
		str.Append(_T("0"));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedBtnDel()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{

	}
	else
	{
		string res = str.GetBuffer();
		res.erase(res.end() - 1);

		SetDlgItemText(IDC_EDIT1, res.c_str());
	}
}


void CKeyBoard::OnBnClickedBtnPoint()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (str.IsEmpty())
	{

	}
	else
	{
		str.Append(_T("."));
		SetDlgItemText(IDC_EDIT1, str);
	}
}


void CKeyBoard::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	isConfirm = TRUE;
	CDialogEx::OnOK();
}

CString CKeyBoard::GetEdit1Str()
{
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	return str;
}

BOOL CKeyBoard::GetIsConfirm()
{
	return isConfirm;
}

void CKeyBoard::SetIsConfirm(BOOL isconfirm)
{
	isConfirm = isconfirm;
}

void CKeyBoard::RefrashEdit()
{
	SetDlgItemText(IDC_EDIT1, _T(""));
}

其实整个代码并不复杂,简单点就是字符串处理,当然你键盘再加其它键同样道理。

下面是.h

#pragma once

// CKeyBoard 对话框

class CKeyBoard : public CDialogEx
{
	DECLARE_DYNAMIC(CKeyBoard)

public:
	CKeyBoard(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CKeyBoard();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_KEYBOARD };
#endif

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

	DECLARE_MESSAGE_MAP()

public:
	afx_msg void OnBnClickedBtnNum1();
	afx_msg void OnBnClickedBtnNum2();
	afx_msg void OnBnClickedBtnNum3();
	afx_msg void OnBnClickedBtnNum4();
	afx_msg void OnBnClickedBtnNum5();
	afx_msg void OnBnClickedBtnNum6();
	afx_msg void OnBnClickedBtnNum7();
	afx_msg void OnBnClickedBtnNum8();
	afx_msg void OnBnClickedBtnNum9();
	afx_msg void OnBnClickedBtnNum0();
	afx_msg void OnBnClickedBtnDel();
	afx_msg void OnBnClickedBtnPoint();
	afx_msg void OnBnClickedOk();
	virtual BOOL OnInitDialog();

	CString NumResult;
	CString GetEdit1Str();
	BOOL isConfirm;
	BOOL GetIsConfirm();
	void SetIsConfirm(BOOL isconfirm);
	void RefrashEdit();
};

键盘的图片界面

 那么简单的键盘就完成了。接下来就是如何调用键盘的问题。

这里需要调用MFC的一个虚函数。PreTranslateMessage是一个虚函数,用于截获消息。我们可以通过重载它来处理键盘和鼠标消息。PreTranslateMessage在消息送给TranslateMessage函数之前被调用,绝大多数本窗口的消息都要通过这里。当你需要在MFC之前处理某些消息时,常常要在这里添加代码。

这里我调用的是鼠标左键单击,至于这个虚函数如何添加,网上一搜大把,这里不再贴出来。

BOOL 你的对话框类名::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (targetID != 0 || KeyBoard->GetEdit1Str() != "")
	{
		if (KeyBoard->GetIsConfirm())
		{
			SetEditNum(targetID, KeyBoard->GetEdit1Str());
			KeyBoard->SetIsConfirm(FALSE);
			KeyBoard->RefrashEdit();
		}
	}
	if (pMsg->message == WM_LBUTTONDOWN)
	{
		int nID = 0;
        //这一段的作用是为了获取鼠标点击控件的ID,将通过ID获取控件的类名,因为键盘主要作用于
        //文本编辑框上,所以只需要找到Edit类就行
		CWnd* pWnd = GetFocus();
		nID = pWnd->GetDlgCtrlID();
		wchar_t CClassName[255] = { 0 };

		GetClassNameW(pWnd->GetSafeHwnd(), CClassName, 255);//得到控件的类名,主要有Edit,Button,Static等等
		int bufferSize = WideCharToMultiByte(CP_UTF8, 0, CClassName, -1, nullptr, 0, nullptr, nullptr);
		std::string cClassName(bufferSize, 0);
		WideCharToMultiByte(CP_UTF8, 0, CClassName, -1, &cClassName[0], bufferSize, nullptr, nullptr);
		string comp(cClassName);

		if (strcmp(cClassName.c_str(), "Edit") == 0)
		{
			CEdit* ptr = (CEdit*)GetDlgItem(nID);
			CRect rect; ptr->GetWindowRect(&rect);
			if (rect.PtInRect(pMsg->pt) && m_NestSaveParm.IsOpenKeyboard)
			{
				//获取按钮的矩形区域
				CRect rect;
				GetDlgItem(nID)->GetWindowRect(rect);

				//对话框窗体大小
				CRect rectDlg;
				GetWindowRect(rectDlg);//获得窗体的大小

				//键盘窗体大小
				CRect rectKey;
				KeyBoard->GetWindowRect(rectKey);
                
                //下面这里就是设置键盘的位置了。
				if (rect.right + rectKey.Width() > rectDlg.Width())
				{
					//新建键盘
					KeyBoard->SetWindowPos(NULL, rect.left - rectKey.Width(), rect.top, 0, 0, SWP_NOSIZE);
					KeyBoard->ShowWindow(SW_NORMAL);
					targetID = nID;
				}
				else
				{
					//新建键盘
					KeyBoard->SetWindowPos(NULL, rect.right, rect.top, 0, 0, SWP_NOSIZE);
					KeyBoard->ShowWindow(SW_NORMAL);
					targetID = nID;
				}

				return TRUE;
			}
		}

	}
	return CDialogEx::PreTranslateMessage(pMsg);
}



void 你的对话框类名::SetEditNum(int nID, CString text)
{
	SetDlgItemText(nID, text);
}




那么大概的基本过程就这样完成了,剩下的就是在你所需要的对话框添加键盘头文件还有把键盘初始化,

    //在你调用的对话框的头文件中:
	CKeyBoard* KeyBoard;
	void SetEditNum(int nID, CString text);
	int targetID;	




    //在你调用的对话框进行初始化
    KeyBoard = NULL;
	KeyBoard = new CKeyBoard();
	KeyBoard->Create(IDD_KEYBOARD, this);
	targetID = 0;

思路是这么个思路,希望对你有所帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值