- ベストアンサー
コンボボックスの拡張
MFCのコンボボックス機能の拡張について質問です。 コンボボックスを「EnableWindow( FALSE )」で使用不可にした際に、 通常は、ボックス内に表示されている文字色がグレーになり、 カーソルでの範囲選択も不可になりますが、 文字色を黒のままにし、カーソルで範囲選択(コピー操作も可)が可能になるような プログラムを作成したいのです。 ヒントとして得た情報としては、 ・CEditクラスが関係 ・メッセージマップ横取り がありますが、情報が少なすぎて手が付けられない状態です。。 もし知識のある方おられましたら、具体的な解決策などご教授頂けないでしょうか。 開発環境は、VC++2005です。 どうか宜しくお願い致します。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
#3です。 ならば、WM_ENABLEを捕まえて、その中で子ウィンドウとしてエディットボックスを制御するのはどうでしょう。 Spy++で見るとわかりますが、コンボボックスは子ウィンドウとして、エディットボックスを持っています。それと同じ場所、大きさで、もう1個エディットボックスを作ります。 エディットボックスをWM_CREATEで作るか、WM_ENABLEで作るのがいいかは、ちょっとやってみないとわからないですが。
その他の回答 (5)
- machongola
- ベストアンサー率60% (434/720)
こんばんは。う~む。 ポップアップウィンドウを隠した状態で作成し、其のポップアップウィンドウに編集エディットボックスを搭載して、コンボボックスのエディットボックスに覆いかぶせて「表示・非表示」を切り替えてみては。 手法の良し悪しは別にして、一応出来る事は出来ました。 ダイアログのリサイズや最大化等も確りとへばり付いてくれたので、此の手法で大丈夫だとは思います・・・。 色々改良の余地やアラはあるかも知れませんが、其処はご勘弁です。参考程度に。 //ポップアップウィンドウのメンバ変数(アクティブフレームと命名) CWnd* m_pActiveFrame; //作成するエディットボックスのID(アクティブエディットと命名) const DWORD IDC_ACTIVEEDIT = 100; //ダイアログの初期化 BOOL CQandADlg::OnInitDialog() { //以前省略 // TODO: 特別な初期化を行う時はこの場所に追加してください。 RECT rc; CWnd* pwndComboBox = GetDlgItem(IDC_COMBO1); CWnd* pwndEdit = pwndComboBox->GetTopWindow(); pwndEdit->GetClientRect(&rc); //アクティブフレームを見えない状態で作成 m_pActiveFrame = new CWnd(); m_pActiveFrame->CreateEx(0, AfxRegisterWndClass(0), NULL, WS_POPUP, rc, pwndEdit, 0); //アクティブエディットを作成してアクティブフレームに乗せる LOGFONT lf; CEdit* pActiveEdit = new CEdit(); pActiveEdit->Create(pwndEdit->GetStyle(), rc, m_pActiveFrame, IDC_ACTIVEEDIT); //コンボボックスのエディットからフォントを複製する CFont* pFontFrom = pwndEdit->GetFont(); pFontFrom->GetLogFont(&lf); CFont* pFontClone = new CFont(); pFontClone->CreateFontIndirect(&lf); //複製したフォントをアクティブエディットに渡す pActiveEdit->SetFont(pFontClone); return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われません。 } //ダイアログが動いた時 void CQandADlg::OnMove(int x, int y) { CDialog::OnMove(x, y); // TODO: この位置にメッセージ ハンドラ用のコードを追加してください //アクティブフレームが作成されていないので引き返す if(!m_pActiveFrame)return; RECT rc; CWnd* pwndComboBox = GetDlgItem(IDC_COMBO1); CWnd* pwndEdit = pwndComboBox->GetTopWindow(); //コンボボックスのエディットのクライアント領域をスクリーン領域に変換 pwndEdit->GetClientRect(&rc); pwndEdit->ClientToScreen(&rc); //アクティブフレームを移動 m_pActiveFrame->MoveWindow(&rc, TRUE); } //見ての通り(何処かで此れを呼ぶ) void CQAndADlg::DisableComboBox() { CWnd* pwndComboBox = GetDlgItem(IDC_COMBO1); CWnd* pwndEdit = pwndComboBox->GetTopWindow(); pwndComboBox->EnableWindow(FALSE); m_pActiveFrame->ShowWindow(SW_SHOW); } //見ての通り(何処かで此れを呼ぶ) void CQAndADlg::EnableComboBox() { CWnd* pwndComboBox = GetDlgItem(IDC_COMBO1); pwndComboBox->EnableWindow(TRUE); m_pActiveFrame->ShowWindow(SW_HIDE); }
お礼
画像付きの詳しい解説ありがとうございます! 自分のイメージしていたコンボボックス自体の拡張とは少し異なりますが、 ダイアログのリサイズや最大化等に対応している辺りなど、 他のコントロールを作成した際にも利用できる点が多く、 非常に参考になりました!ありがとうございました。
- titokani
- ベストアンサー率19% (341/1726)
元のソースにどこまで手を入れることが許されるのか今ひとつ不明ですが、MFCということなので、CComboBoxの派生クラスを作るのが普通の方法です。 ダイアログで使用する場合にはSubClassDlgItemで結び付けます。 あと、訂正です。もう1つのエディットボックスを、コンボボックスの子ウィンドウとして作成してしまうと、コンボボックスがDisableになったときに操作不能になってしまいますね。もう1つのエディットボックスはコンボボックスの兄弟ウィンドウにする必要がありそうです。
お礼
派生クラスを作成し、WM_ENABLEメッセージのハンドラを作成することでとりあえず解決しました。 この方法が最良かどうかは分かりませんが、 皆様の参考意見を元に、より効率良いコードに改良していこうと思います。 ありがとうございました。
- titokani
- ベストアンサー率19% (341/1726)
あれ、ドロップダウンリストじゃだめなのかな?
補足
今回私が課されたプログラム作成の意図として、メッセージマップを横取り?して、 Enableなボックス内文字列の状態を変更する方法で作成するといったものとなっています。 よって効率悪い方法かもしれませんが、意図に沿って作成する必要があるのです。。。
- chie65536(@chie65535)
- ベストアンサー率44% (8742/19841)
追記。 >開発環境は、VC++2005です。 borland C++のGUI環境だと ・コンボボックスをフォームに置く ・置いたコンボボックスにピッタリ重ねてテキストボックスをフォームに置いて、プロパティページで「非表示」「書換不可」にする という感じでフォームを作って ・コンボボックスの使用可能、使用不可を切り替える際には、コンボボックスのテキストをテキストボックスに流し込んで、テキストボックスの「表示/非表示」を切り替える という処理を書くだけで済みます。 VC++2005でも、似たような処理が出来ると思います。
補足
具体的で分かりやすいご提案ありがとうございます。 確かに簡単で非常に効率的ですが。。今回の問題を作成するにあたって、 条件が既存のコンボボックスを拡張するというものであり、 上にテキストボックスを重ねて置くことができないのです。。 質問文に書いておけば良かったですね。せっかくのご提案なのに申し訳ありません。 >つまり「リストの選択は出来ず、テキストも書き替え不可だが、 >文字の色は通常の色で、範囲指定とコピーだけは出来る」と言うようにしたい、と? はい。その通りです。 イメージとしては、コンボボックスをEnableにした際に、 メッセージを受け取り、メッセージマップで定義したクラスのメンバ関数内で、 文字色を黒にし、カーソル範囲選択可能にするという処理を考えているのですが。。 もし上記認識で間違いないのなら、お手数ですが具体的な解決策など、 ご提示頂けたら幸いです。
- chie65536(@chie65535)
- ベストアンサー率44% (8742/19841)
つまり「リストの選択は出来ず、テキストも書き替え不可だが、文字の色は通常の色で、範囲指定とコピーだけは出来る」と言うようにしたい、と? 一番簡単なのは ・コンボボックスのテキストエリアの真上に、別のテキストボックスを重ねて乗せる ・コンボボックスが使用可能の状態の時は、別のテキストボックスは非表示にしておく ・コンボボックスを使用不可にする際は、コンボボックスのテキストを別のテキストボックスのテキストにコピーし、重ねてある別のテキストボックスを表示して使用可能にしてから、コンボボックスを使用不可にする ・重ねてある別のテキストボックスのテキストが変更されたのを検知したら、コンボボックスのテキストを別のテキストボックスのテキストにコピーし直して、元の文字列に戻す ・コンボボックスを使用可能にする際は、重ねてある別のテキストボックスを非表示にしてから、コンボボックスを使用可能にする と言う処理でしょう。 もし「テキストボックスを、使用可能だが、テキストの書き替えは不可」に出来るなら、以下のようにもっと簡単になります。 ・コンボボックスのテキストエリアの真上に、別のテキストボックスを重ねて乗せる。テキストボックスは「使用可能」「書換不可」にしておく。 ・コンボボックスが使用可能の状態の時は、別のテキストボックスは非表示にしておく ・コンボボックスを使用不可にする際は、コンボボックスのテキストを別のテキストボックスのテキストにコピーし、重ねてある別のテキストボックスを表示してから、コンボボックスを使用不可にする ・コンボボックスを使用可能にする際は、重ねてある別のテキストボックスを非表示にしてから、コンボボックスを使用可能にする このようにすれば「メッセージの横取りをどうのこうの」とか「コンボボックスのテキストエリアをどうのこうの」とか、面倒な事は一切不要です。
補足
早急なご回答ありがとうございます。 WM_ENABLEは許可状態から変更される際に送られるメッセージですね。 これを用いて作成しようと思います。 エディットボックスの制御方法として、 CWnd* pwndComboBox = GetDlgItem( IDC_COMBOOX ); CWnd* pwndEdit = pwndComboBox->GetTopWindow(); のようにポインタを取得し、制御することは分かりましたが、 メッセージを捕まえる方法がよく分かりません。 もし具体的な作成例など載っているサイトなどご存知でしたら、 お手数ですがご教授お願いできませんでしょうか? 聞いてばかりで申し訳ありません。。。