MFC touch screen virtual numeric keyboard idea

These days, I need to use a touch screen in MFC projects. At the beginning, I originally called an external keyboard, but my superiors were reluctant and had to write a simple numeric keyboard myself. I will post the ideas and code below. You still have to create the keyboard interface yourself. I am posting the code as a reference.

The following is cpp

// CKeyBoard.cpp: implementation file
//

#include "stdafx.h"
#include "Resource.h" //Just include this in other header files
#include "CKeyBoard.h"
#include "afxdialogex.h"


// CKeyBoard dialog box

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, & amp;CKeyBoard::OnBnClickedOk)
END_MESSAGE_MAP()


// CKeyBoard message handler
BOOL CKeyBoard::OnInitDialog()
{
CDialogEx::OnInitDialog();

// TODO: Add additional initialization here
CFont* f;
f = new CFont;
f->CreateFont(36, // font height
0, // font width
0, // font tilt angle
0, // font tilt angle
FW_BOLD, // font thickness
FALSE, // Whether the font is italic
FALSE, // Whether the font is underlined
0, // Whether the font has strikethrough
ANSI_CHARSET, //Character set used by the font
OUT_DEFAULT_PRECIS, // Specify how to select the appropriate font
CLIP_DEFAULT_PRECIS, // Determine the precision of cropping
DEFAULT_QUALITY, // How does it match the selected font?
DEFAULT_PITCH | FF_SWISS, // Spacing flag and attribute flag
_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
//Exception: OCX property page should return FALSE
}

void CKeyBoard::OnBnClickedBtnNum1()
{
// TODO: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
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: Add control notification handler code here
CString str;
GetDlgItemText(IDC_EDIT1, str);
if (str.IsEmpty())
{

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


void CKeyBoard::OnBnClickedOk()
{
// TODO: Add control notification handler code here
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(""));
}

In fact, the whole code is not complicated. It is simply string processing. Of course, the same is true for adding other keys on your keyboard.

Below is .h

#pragma once

// CKeyBoard dialog box

class CKeyBoard : public CDialogEx
{
DECLARE_DYNAMIC(CKeyBoard)

public:
CKeyBoard(CWnd* pParent = nullptr); // Standard constructor
virtual ~CKeyBoard();

//Dialog data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_KEYBOARD };
#endif

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

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();
};

Keyboard picture interface

Then the simple keyboard is completed. The next step is how to call the keyboard.

Here you need to call a virtual function of MFC. PreTranslateMessage is a virtual function used to intercept messages. We can handle keyboard and mouse messages by overloading it. PreTranslateMessage is called before the message is sent to the TranslateMessage function, and most of the messages in this window pass through here. When you need to handle some messages before MFC, you often add code here.

What I call here is the left mouse button click. As for how to add this virtual function, there are many searches on the Internet, so I won’t post it here.

BOOL Your dialog class name::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add specialized code here and/or call the base class
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;
        //The purpose of this section is to obtain the ID of the mouse click control. The class name of the control will be obtained through the ID, because the keyboard mainly acts on
        //Text edit box, so you only need to find the Edit class
CWnd* pWnd = GetFocus();
nID = pWnd->GetDlgCtrlID();
wchar_t CClassName[255] = { 0 };

GetClassNameW(pWnd->GetSafeHwnd(), CClassName, 255);//Get the class name of the control, mainly Edit, Button, Static, etc.
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( & amp;rect);
if (rect.PtInRect(pMsg->pt) & amp; & amp; m_NestSaveParm.IsOpenKeyboard)
{
//Get the rectangular area of the button
CRectrect;
GetDlgItem(nID)->GetWindowRect(rect);

//dialog form size
CRect rectDlg;
GetWindowRect(rectDlg);//Get the size of the form

//Keyboard window size
CRectrectKey;
KeyBoard->GetWindowRect(rectKey);
                
                //The following is where the keyboard is set.
if (rect.right + rectKey.Width() > rectDlg.Width())
{
//New keyboard
KeyBoard->SetWindowPos(NULL, rect.left - rectKey.Width(), rect.top, 0, 0, SWP_NOSIZE);
KeyBoard->ShowWindow(SW_NORMAL);
targetID = nID;
}
else
{
//New keyboard
KeyBoard->SetWindowPos(NULL, rect.right, rect.top, 0, 0, SWP_NOSIZE);
KeyBoard->ShowWindow(SW_NORMAL);
targetID = nID;
}

return TRUE;
}
}

}
return CDialogEx::PreTranslateMessage(pMsg);
}



void Your dialog class name::SetEditNum(int nID, CString text)
{
SetDlgItemText(nID, text);
}




Then the basic process is roughly completed. The only thing left is to add the keyboard header file to the dialog box you need and initialize the keyboard.

 //In the header file of the dialog box you call:
CKeyBoard* KeyBoard;
void SetEditNum(int nID, CString text);
int targetID;




    //Initialize in the dialog box you called
    KeyBoard = NULL;
KeyBoard = new CKeyBoard();
KeyBoard->Create(IDD_KEYBOARD, this);
targetID = 0;

This is the idea, I hope it will be helpful to you.