3

我有一个带有菜单和 CTabCtrl 的对话框。CTabCtrl 有一个选项卡,其中包含一个 CDialog。反过来,它包含一些静态文本和一个 CRichEditCtrl。窗口获得和失去焦点没有特别的问题。

我此后添加了第二个相同的选项卡,现在每次更改选项卡时,CRichEditCtrl 中的所有文本都显然被选中。它以反转的配色方案显示,如果您按下一个键,所有文本都会被替换。

ECO_NOHIDESEL 标志的描述说(强调我的):

否定编辑控件的默认行为。默认行为在控件失去输入焦点时隐藏选择,并在控件接收到输入焦点时显示选择。如果指定 ECO_NOHIDESEL,则所选文本会反转,即使控件没有焦点也是如此。

“显示选择”对我来说听起来像是“显示该控件最后一次获得焦点时的选择”,这不是正在发生的事情。通常在失去焦点之前没有选择任何内容,但如果我确实尝试留下选择,返回另一个选项卡并返回,则像往常一样选择整个文本。

可以防止这种选择吗?

void EditorDialog::OnTabSelChange(NMHDR * phdr, LRESULT* pResult) {

  CTabCtrl* ptab = (CTabCtrl*) GetDlgItem( IDC_TAB );

  int iPageActive = ptab->GetCurSel();

  if ( iPageActive >= appage.N() ) {
      AKS( AKSWarn, "got tab change to tab %d when I only have %d ppages", iPageActive, appage.N() );
      return;
  }

  ppageActive = appage[ iPageActive ];

  SetActivePagePos();

  SCWinUtilSetWindowTextVA( this, "Editor: %s", ppageActive->pszFileName );
}



void EditorDialog::SetActivePagePos() {

  // STEP 1: Make the proper tab page visible.

  for ( int i = 0; i < appage.N(); i++ )
      appage[i]->ShowWindow( SW_HIDE );
  ppageActive->ShowWindow( SW_SHOW );

  // STEP 2: Make the new tab page the right size and position.

  CTabCtrl* ptab = (CTabCtrl*) GetDlgItem( IDC_TAB );

  CRect rectTab, rectItem;

  ptab->GetClientRect( &rectTab );
  ptab->GetItemRect( 0, &rectItem );

  int iPageX = rectItem.left   + 2;
  int iPageY = rectItem.bottom + 4;
  int iPageW = rectTab.right   - 2 - iPageX;
  int iPageH = rectTab.bottom  - 2 - iPageY;

  ppageActive->SetWindowPos( &wndTop, iPageX, iPageY, iPageW, iPageH, SWP_SHOWWINDOW | SWP_NOZORDER );

  // STEP 3: Give the window focus and let it know to redraw.

  ppageActive->SetFocus();

  // When the tab changes the entire content of the RichEdit is selected for some reason.
  // As a workaround I manually clear the selection.
  CRichEditCtrl* prich = (CRichEditCtrl*) ppageActive->GetDlgItem( IDC_PATCH );
  prich->SetSel(-1,-1);

  // Redrawing just the prich, or the ppageActive, or the ptab, doesn't
  // cause the RichEdit to redraw correctly, but Redrawing the entire dialog does.
  RedrawWindow();
}
4

2 回答 2

7

Edit 和 Rich Edit 控件的默认行为是在控件没有输入焦点时使选择不可见,并且仅在控件具有焦点时才使其可见。但是,选择没有改变。该ES_NOHIDESEL样式会覆盖此默认行为并导致选择始终出现在控件中,无论它是否具有焦点。您之前肯定见过这种行为:这是 Microsoft Word 和 Visual Studio 所做的。

因此,您对 SDK 文档的理解是完全正确的。不幸的是,Rich Edit 控件行为的另一个方面正在阻碍。每当对话框中承载的 Edit 或 Rich Edit 控件获得焦点时,它会自动选择其所有文本,从而消除进程中的当前插入符号位置。对这种ES_NOHIDESEL行为没有任何影响;它只是改变控件未聚焦时选择是否可见。您当然可以通过按照IInspectable 建议的操作并子类化控件来自定义其对WM_GETDLGCODE消息的处理来覆盖这种全选焦点行为。

但是有一个简单的解决方案。与 相同ES_NOHIDESEL您希望在创建时设置控件的ES_SAVESEL样式。尽管您可以ES_NOHIDESEL在资源编辑器中设置(“无隐藏选择”),但ES_SAVESEL. 您可以手动将其添加到 RC 文件中,但不能保证在 Visual Studio 重新生成该文件时它不会被删除。

或者,您可以向 Rich Edit 控件EM_SETOPTIONS发送指定ECO_SAVESEL选项的消息。在 MFC 中,SetOptions成员函数封装了此消息的发送。例如,在您的OnInitDialog函数中,您可能具有以下内容:

m_myRichEditCtrl.SetOptions(ECOOP_OR, ECO_SAVESEL);  // maintain selection across focus events
于 2016-05-10T11:35:46.470 回答
4

Edit 和 RichEdit 控件的默认行为是在获得焦点时选择整个内容。ES_NOHIDESEL不会修改此行为,而只是指示控件始终显示其选择,即使它没有输入焦点。

要更改 RichEdit 控件的默认行为以保留其选择,您必须从它派生并提供您的自定义OnGetDlgCode实现:

UINT RichEditSelectionPreserving::OnGetDlgCode() {
    // Call the base class implementation
    UINT code = CRichEditCtrl::OnGetDlgCode();
    // And mask out the undesired feature
    code = code & ~DLGC_HASSETSEL;
    return code;
}
于 2014-01-02T14:12:09.677 回答