3

メニューと CTabCtrl を含むダイアログがありました。CTabCtrl には、CDialog を含む 1 つのタブがありました。次に、いくつかの静的テキストと CRichEditCtrl が含まれていました。ウィンドウがフォーカスを取得したり失ったりすることに特に問題はありませんでした。

2 番目の同一のタブを追加して以来、タブが変更されるたびに、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

エディット コントロールとリッチ エディット コントロールの既定の動作では、コントロールに入力フォーカスがない場合は選択範囲が表示になり、コントロールにフォーカスがある場合にのみ表示されます。ただし、選択は変更されません。スタイルはES_NOHIDESELこの既定の動作をオーバーライドし、フォーカスがあるかどうかに関係なく、選択範囲が常にコントロールに表示されるようにします。これは、Microsoft Word と Visual Studio の両方が行うことです。

そのため、SDK ドキュメントに関するあなたの理解は完全に正しいものです。残念ながら、リッチ エディット コントロールの動作には別の側面があり、それが邪魔になっています。ダイアログ ボックスでホストされているエディット コントロールまたはリッチ エディット コントロールがフォーカスを受け取ると、すべてのテキストが自動的に選択され、プロセスの現在のキャレット位置が消去されます。はこのES_NOHIDESEL動作には影響しません。コントロールがフォーカスされていないときに選択が表示されるかどうかが変わるだけです。IInspectable が提案したように実行し、メッセージの処理をカスタマイズするためにコントロールをサブクラス化するWM_GETDLGCODEことで、このフォーカス オンのすべての選択動作を確実にオーバーライドできます。

しかし、もっと簡単な解決策があります。と同じようES_NOHIDESELに、作成時にコントロールのスタイルを設定します。ES_SAVESELリソース エディタで設定できますがES_NOHIDESEL(「非表示選択なし」)、 に相当するプロパティはありませんES_SAVESEL。手動で RC ファイルに追加できますが、Visual Studio がそのファイルを再生成するときに消去されないという保証はありません。

または、リッチ エディット コントロールにオプション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 に答える