【问题标题】:Adding another VC++ Dialog causes the second one to have focus dotted rectangle around controls?添加另一个 VC++ 对话框会导致第二个对话框在控件周围有焦点虚线矩形?
【发布时间】:2013-02-20 12:25:42
【问题描述】:

我制作了一个行为异常的 Visual Studio 2012 (Professional) 项目。当我只有一个对话框时,当我使用它们时,控件上不会出现焦点矩形(虚线边框),除非我第一次按 TAB 或 ALT。当我尝试在主对话框之前加载另一个对话框(作为启动屏幕)时,焦点虚线边框 do 出现在主(第二个)对话框上,当窗口加载。为什么会这样?如何防止这种情况发生?

我唯一的猜测是按 ENTER 或 ESC 会导致与按 TAB 或 ALT 相同的行为,我总是看到效果,因为用户必须按 ENTER 或 ESC 才能关闭启动屏幕。有人会认为有一种方法可以从控件中移除焦点,但这似乎并不容易。我可以轻松地将焦点设置到控件上,而不是一般地删除它。

对于那些对示例代码感兴趣的人:


我可以展示我整个项目的代码,但诚实地自己测试会更容易。创建一个新的 VC++ 项目 > MFC 应用程序,设置为“基于对话框”,完成。在资源视图中,右键单击对话框和“插入对话框”。使其与主窗口明显不同,并添加至少一个可以获取焦点的控件。最后,在您的主 .cpp 文件的顶部附近,您会发现文本“// The one and only”...在其下方是声明主应用程序对象的行。在 that 行下方创建一个新的对话框类(对于“启动画面”,您可以在下面看到我的*),然后在主应用程序的 InitInstance() 中,插入代码以加载上方的启动画面看起来像这样的部分:

CDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();

我用来显示启动画面的代码是:

CSplashDlg dlgSplash;
dlgSplash.DoModal();

*我的启动对话框代码:

更新:我更改了我的代码以允许首先单击对话框而不是按 Enter(事实上,我将在某个时候覆盖 pretranslatemsg() 并捕获 ESC 和 ENTER。这是我最新的代码:

class CSplashDlg : public CDialogEx
{
public:
    CSplashDlg();
    enum { IDD = IDD_SPLASH };

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

protected:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
};

CSplashDlg::CSplashDlg() : CDialogEx(CSplashDlg::IDD) {}

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

BEGIN_MESSAGE_MAP(CSplashDlg, CDialogEx)
    ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

void CSplashDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
    EndDialog(1);
    CDialogEx::OnLButtonUp(nFlags, point);
}

【问题讨论】:

  • 通过单击鼠标就可以关闭初始屏幕来测试它。这样你就会知道是不是因为用户必须按 Esc 或 Enter。

标签: c++ visual-studio visual-c++ mfc dialog


【解决方案1】:

似乎按 ESC 或 ENTER 在编程上与按 TAB 或 ALT 类似,因此按下这些键中的任何一个都会触发控件上的焦点边框。我的解决方案是手动关闭对话框,而不是使用默认的“OK”和“CANCEL”选项,因为某些原因触发了未来对话框中甚至尚未创建的焦点边框。

我在上面粘贴的最新代码是解决方案,最后我应该指出,防止用户在对话框中按 ENTER 或 ESC 也很重要(即使允许他们点击它,他们也可能这样做now) ,所以我使用PreTranslateMessage 捕捉这些按键。您可能完全可以防止发生原始问题,同时仍然允许在使用此方法时使用 ESCAPE 和 ENTER,但这并不像在 PreTranslateMessage 调用中包含 CSplashDlg::EndDialog(1); 那样简单(我尝试过,但失败了)。

在我的 CSplashDlg 类定义中:

virtual BOOL PreTranslateMessage(MSG* pMsg);

我的函数如下所示:

BOOL CSplashDlg::PreTranslateMessage(MSG* pMsg) {
    if ( pMsg->message == WM_KEYDOWN ) {
        if ( pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN ) {
            pMsg->wParam = NULL;
            //return MAKELONG(0,DC_HASDEFID);
        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}

【讨论】:

  • 我发现通过简单地返回 1 与将 wParam 设置为 NULL 达到相同的效果,因为非零值表示不应发送消息。
【解决方案2】:

在 OnInitDialog() 的主对话框(不是飞溅)中,将 return FALSE; 作为最后一条语句

【讨论】:

  • 确实会产生细微的差别,但并不能完全解决。对我来说,这使得焦点边框仍然显示,但控件没有通常的蓝色内发光。当您实际与控件交互时,发光会返回,并且焦点边框始终保持不变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-26
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多