CDialog类三大重要虚函数
a)MFC平台希望接管三大重要消息:OnInitDialog() OnOK() OnCancel()
WM_INITDIALOG:
virtual BOOL OnInitDialog();
当对话框被创建后,OnInitDialog()函数会被自动调用。在这个函数中,可以进行对话框的初始化工作,如设置控件的属性、初始化变量等。如果在派生类中重写了OnInitDialog()函数,必须调用基类的同名函数,以保证基类的初始化工作得以完成。
b)点击确定和取消
ON_COMMAND(IDOK, &CDialog::OnOK)
ON_COMMAND(IDCANCEL, &CDialog::OnCancel)
virtual void OnOK();
virtual void OnCancel();
OnOK() /OnCancel() 在用户点击对话框的“确定”/"取消”按钮时被调用。默认情况下,OnOK()和OnCancel()函数会执行对话框的销毁操作,即关闭对话框。如果需要自定义“确定”按钮的行为,可以在派生类中重写OnOK()函数,并在函数中添加自定义的处理逻辑。
c)如果在派生类中重写以上函数,可以禁止回车和ESC关闭对话框。
MFC中反射型消息
控件的消息可以从父窗口方便的获取
a)类向导第二页是主窗口消息,包括WM_MOUSEMOVE等所有基础消息。
b)类向导第一页都是一些控件的ID,选择不同的ID就会列出对应控件的反射型消息。
c)原本很多消息,包括WM_MOUSEMOVE和WM_DROPFILES等消息一旦进入控件区域,都会被控件拐走。
d)消息被控件拐走之后,主窗口没有收到消息,此时要继续截获控件消息就不得不建立控件派生类并子类化(SubClass).
e)MFC为了更方便地从主窗口管理控件内部的消息,把控件内的基础消息合成高级消息反射给主窗口。
Notify这个英文就是通知,因此但凡见到BN_ EN_ LVN_ HDN_等等都是反射型消息。
LVN_ 代表ListCtrl的操作,比如新选中一行,HDN_
在MFC中,反射型消息是一种机制,它将窗口消息与类的成员函数关联起来,使得消息处理过程更加简化和灵活。
反射型消息机制通过使用宏和宏函数来实现。MFC提供了一系列的宏函数,比如DECLARE_MESSAGE_MAP()和BEGIN_MESSAGE_MAP(),这些宏函数用于声明和定义消息映射表。
首先,在类的声明中使用DECLARE_MESSAGE_MAP()宏,该宏将在类的定义中生成一个静态的消息映射表。
然后,在类的实现文件中使用BEGIN_MESSAGE_MAP()宏来定义消息映射表。在这个宏之后,可以使用类似于ON_MESSAGE()、ON_COMMAND()、ON_NOTIFY()等宏来将窗口消息与类的成员函数关联起来。这些宏的参数包括消息ID、消息处理函数和类的名称。
例如,下面的代码片段展示了如何使用反射型消息机制将窗口消息WM_COMMAND与类的成员函数关联起来:
BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
ON_COMMAND(ID_FILE_SAVE, OnFileSave)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
END_MESSAGE_MAP()
在上面的代码中,CMyWnd类继承自CWnd类,使用BEGIN_MESSAGE_MAP()来定义消息映射表。ON_COMMAND()宏将窗口消息ID和类的成员函数关联起来,例如ID_FILE_OPEN和OnFileOpen()函数。
窗口接收到WM_COMMAND消息时,MFC会根据消息映射表查找对应的成员函数,并自动调用该函数进行消息处理。
通过使用反射型消息机制,我们可以将窗口消息的处理逻辑集中在类中,使代码更加清晰和易于维护。
CS模式员工管理系统插入列表数据的功能开发
客户端代码
CInputDlg .h
#pragma once
#include "afxdialogex.h"
class CWorkerDlg; //include 害怕双方会双向包含
class CInputDlg : public CDialogEx// CInputDlg 对话框
{
DECLARE_DYNAMIC(CInputDlg)
CWorkerDlg* m_pDlg;
void InsertData();
bool FindNumb(SInfo& d);
CSocket& m_sock{ theApp.m_sock };
public:
CInputDlg(CWorkerDlg* pParent = nullptr); // 标准构造函数
virtual ~CInputDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_INPUT_DLG };// 对话框数据
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedOk();
};
CInputDlg.cpp: 实现文件
#include "pch.h"
#include "CLientXq.h"
#include "afxdialogex.h"
#include "CInputDlg.h"
#include "CWorkerDlg.h"
IMPLEMENT_DYNAMIC(CInputDlg, CDialogEx)// CInputDlg 对话框
CInputDlg::CInputDlg(CWorkerDlg* pParent)
: CDialogEx(IDD_INPUT_DLG, (CWnd*)pParent),m_pDlg(pParent)//this 传过来给m_pDlg调用刷新
{
}
CInputDlg::~CInputDlg()
{
}
void CInputDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CInputDlg, CDialogEx)
ON_BN_CLICKED(IDOK, &CInputDlg::OnBnClickedOk)
END_MESSAGE_MAP()
bool CInputDlg::FindNumb(SInfo& d)// CInputDlg 消息处理程序
{
int nCmd = WK_FIND_NUMB;
m_sock.Send(&nCmd, sizeof(nCmd));
m_sock.Send(&d.nNumb, sizeof(d.nNumb));
int nCount = 0;
if (m_sock.Receive(&nCount, sizeof(nCount)) != sizeof(nCount))
return false;
if (nCount < 1)
return false;
return m_sock.Receive(&d, sizeof(d)) == sizeof(d);
}
void CInputDlg::InsertData()
{
SInfo d;
CString str;
GetDlgItemText(IDC_NUMB, str);
d.nNumb = _tstoi(str);
if (FindNumb(d))
{
MessageBox(_T("工号已存在请重新输入!"), _T("提示"), MB_ICONSTOP);
SetFocus();
return;
}
if (MessageBox(_T("确定插入这条数据吗?"), _T("提示"), MB_YESNO | MB_ICONQUESTION) == IDNO)
return;
GetDlgItemText(IDC_SALARY, str);
d.fSala = (float)_tstoi(str);
GetDlgItemText(IDC_NAME, str);
strcpy_s(d.sName, _countof(d.sName), _bstr_t(str));
GetDlgItemText(IDC_DATETIME, str);
CApp::CorrentDate(str);
strcpy_s(d.sDate, _countof(d.sDate), _bstr_t(str));
int nCmd = WK_INPUT;
theApp.m_sock.Send(&nCmd, sizeof(nCmd));
theApp.m_sock.Send(&d, sizeof(d));
SetDlgItemText(IDC_NUMB, CString());
SetDlgItemText(IDC_NAME, CString());
SetDlgItemText(IDC_SALARY, CString());
SetFocus();
m_pDlg->Refresh();
}
void CInputDlg::OnBnClickedOk()
{
auto pWnd = GetFocus();
int nID = pWnd->GetDlgCtrlID();
if (nID == IDC_DATETIME || nID == IDOK)
InsertData();
else
NextDlgCtrl();
}
服务器端代码
CManager CManager::m_man;//实际就是全局变量
MYSQL m_sql;
CSockLx m_sock;
CWorker m_worker{ m_sql };
static void PrintError(const char* sSQL)
{
printf("SQL语句错误:%s\n %u: %s\n", sSQL, mysql_errno(&m_man.m_sql),
mysql_error(&m_man.m_sql));
}
多线程处理消息中当插入数据进来时做出反应
case WK_INPUT:
return m_worker.Input(pSocka);
bool CWorker::Input(CSockLx* pSocka)
{
SInfo d;
if (pSocka->Receive(&d, sizeof(d)) < sizeof(d))
return false;
char sSQL[256];
sprintf(sSQL, "INSERT INTO t_worker VALUES(%d,'%s',%0.2f,'%s')",
d.nNumb, d.sName, d.fSala, d.sDate);
int n = mysql_query(&m_sql, sSQL);
if (n)
{
CManager::PrintError(sSQL);//WriteLog
return false;
}
return true;
}