光标自动聚焦输入框,扫码后,点击Test按键
测试完成后, 清空输入框并重新聚焦输入框,等待下次扫码测试;
为什么初始化时光标可自动聚集输入框,而测试结束后聚焦输入框失败呢?
1.初版实现
1.1 添加控件
输入编辑框ID为:IDC_EDIT_BARCODE
添加变量:CEdit m_editBarcode;
Test按键ID为:IDC_BUTTON_START
1.2 头文件
private:
CEdit m_editBarcode;
CString CstrBarcode;
std::string SN;
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
virtual BOOL PreTranslateMessage(MSG* pMsg); // 处理扫码枪输入
1.3.cpp实现
BOOL CDtSampleDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
///
///初始化其他内容
///
m_editBarcode.SetFocus(); // 初始聚焦到条码框
return FALSE; // 必须返回FALSE,确保焦点设置生效
}
条码框处理
#pragma region"条码框处理"
BOOL CDtSampleDlg::PreTranslateMessage(MSG* pMsg) {
if (pMsg->message == WM_KEYDOWN) {
if (pMsg->wParam == VK_RETURN) { // 扫码枪以回车结束输入
GetDlgItemText(IDC_EDIT_BARCODE, CstrBarcode);
//--- 可选:校验条码格式(示例:长度至少6位) ---
if (CstrBarcode.GetLength() < 6) {
MessageBox(_T("无效条码!"), _T("错误"), MB_ICONERROR);
SetDlgItemText(IDC_EDIT_BARCODE, _T(""));
m_editBarcode.SetFocus();
return TRUE; // 拦截消息
}
//--- 校验结束 ---
//条码框字符转换为 string类型,赋值给SN
//SN = Cstr2str(CstrBarcode);
SN = CstrBarcode.GetString();
return TRUE; // 拦截回车消息
}
}
return CDialogEx::PreTranslateMessage(pMsg);
}
#pragma endregion
按键触发测试功能
void CDtSampleDlg::TestFlow()
{
///
///其他内容
///
if (!test1())
{
msg(this, "test1测试 失败!\r\n");
return;
}
msg(this, "关test1测试 成功!\r\n");
if (!test2())
{
msg(this, "test2测试 失败!\r\n");
return;
}
msg(this, "关test2测试 成功!\r\n");
// 清空输入框并重新聚焦
SetDlgItemText(IDC_EDIT_BARCODE, _T(""));
m_editBarcode.SetFocus();
}
void CDtSampleDlg::OnBnClickedButtonTest()
{
TestFlow();
}
1.4 测试效果
运行后
扫码,然后点击 Test 按钮测试
测试完毕后,清空条码框,但是聚焦输入框失败
2 问题分析
问题原因分析
在MFC中,焦点设置失败通常由以下原因导致:
1.模态窗口干扰
TestFlow()
中频繁调用 msg()
显示消息,若其内部使用 AfxMessageBox
或 MessageBox
,会创建模态对话框,导致主窗口失去焦点。关闭模态窗口后,焦点可能未正确返回到原控件。
2. UI线程阻塞
测试流程中的耗时操作(如 Sleep(1500)
、硬件控制)会阻塞UI线程,导致 SetFocus()
调用未及时处理。
3.控件状态变更
测试过程中可能禁用或隐藏了条码框(IDC_EDIT_BARCODE),导致 SetFocus() 失效。
4.默认按钮抢占焦点
如果对话框定义了默认按钮(如“Test”按钮),按下回车时会触发按钮点击,测试结束后焦点会停留在按钮上。
3 解决方案代码
3.1 步骤1:异步设置焦点 ( 完美解决)
通过 PostMessage 延迟焦点设置,确保在UI消息队列空闲时执行。
头文件
// 在对话框类头文件中添加自定义消息
#define WM_SETFOCUS_BARCODE (WM_USER + 102)
protected:
// 设置焦点到条码框
afx_msg LRESULT OnSetFocusBarcode(WPARAM, LPARAM);
// 消息映射声明
BEGIN_MESSAGE_MAP(CDtSampleDlg, CDialogEx)
ON_MESSAGE(WM_SETFOCUS_BARCODE, &CDtSampleDlg::OnSetFocusBarcode)
END_MESSAGE_MAP()
// 消息处理函数
LRESULT CDtSampleDlg::OnSetFocusBarcode(WPARAM, LPARAM) {
m_editBarcode.SetFocus(); // 设置焦点到条码框
return 0;
}
// 修改TestFlow末尾代码
void CDtSampleDlg::TestFlow() {
// ...原有代码...
// 清空条码框并异步设置焦点
SetDlgItemText(IDC_EDIT_BARCODE, _T(""));
PostMessage(WM_SETFOCUS_BARCODE);
}
问题解决,测试完成后,清空输入框并重新自动聚焦输入框。
3.2 如果还不行,追加一下方法
步骤2:禁用默认按钮行为
在对话框初始化时移除默认按钮的 BS_DEFPUSHBUTTON 样式,防止其抢占焦点。
BOOL CDtSampleDlg::OnInitDialog() {
CDialogEx::OnInitDialog();
// 移除"开始测试"按钮的默认按钮属性
CButton* pStartButton = (CButton*)GetDlgItem(IDC_BUTTON_START);
if (pStartButton) {
pStartButton->ModifyStyle(BS_DEFPUSHBUTTON, BS_PUSHBUTTON);
}
// 初始聚焦条码框
m_editBarcode.SetFocus();
return FALSE; // 必须返回FALSE以阻止MFC自动设置焦点
}
步骤3:验证控件状态
确保测试过程中未禁用或隐藏条码框。
void CDtSampleDlg::TestFlow() {
// 确保条码框处于可聚焦状态
GetDlgItem(IDC_EDIT_BARCODE)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_BARCODE)->ShowWindow(SW_SHOW);
// ...原有代码...
}