無効のエディットボックスの文字色の変更

[戻る]
花乃 2008/10/16(木) 14:40:54
早速質問させていただきます。

OS:Windows2000 XP
VC6でダイアログベースです。

HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor) 
{
// TODO: この位置で DC のアトリビュートを変更してください
    pDC->SetTextColor( m_colText );
    pDC->SetBkColor( m_colBack );
    return m_brush;

}

//-----------------------------------------------------------------------------
// 文字色の変更
// ret    : なし
// arg1    : (IN)        colBack        文字色
//-----------------------------------------------------------------------------
void CColorEdit::SetTextColor( COLORREF colText )
{
    m_colText = colText;
}

//-----------------------------------------------------------------------------
// 背景色の変更
// ret    : なし
// arg1    : (IN)        colBack        背景色
//-----------------------------------------------------------------------------
void CColorEdit::SetBackColor( COLORREF colBack )
{
    m_colBack = colBack;
    m_brush.DeleteObject();
    m_brush.CreateSolidBrush( m_colBack );
    if( NULL != m_hWnd )
    {
        RedrawWindow( NULL, NULL, RDW_FRAME | RDW_INVALIDATE | 
RDW_UPDATENOW );
    }
}

花乃 2008/10/16(木) 14:45:59
すみません。途中で送信してしまいました。
上記のように、CEditの派生クラスを作って、
色を変えているのですが、
リソースの設定で「無効」にした場合に、
文字色が変わりません。

ReadOnly(TRUE)にして、TabStopを設定しないというのも
試したのですが、エディットボックス内にカーソルが出てしまいます。
カーソルは出したくないのです。
スタティックテキストにするしか無いのでしょうか?
この場合、入力したくなると困るので、
何か良い方法があればと思い書き込みさせていただきました。
よろしくお願い致します。

どとう 2008/10/16(木) 15:32:13
私はよく、エディットコントロールのEN_SETFOCUSのイベントハンドラで
別のコントロールにフォーカスを移すようにしています。

void CXXXXDlg::OnEnSetfocusEdit1()
{
  //最初のコントロールにフォーカスを移動
    CWnd *pWnd=GetWindow( GW_CHILD );
    if( pWnd ) pWnd->SetFocus();
}

花乃 2008/10/16(木) 15:39:41
どとう様、ありがとうございます。

この場合、一つ一つのコントロールのフォーカスを、
移動させなくてはならないのですよね?
今回、この色設定をするエディットボックスが50個くらいあるので、
この対応はかなり厳しそうですが、今後の参考になりました。

subaru 2008/10/16(木) 16:41:48
カーソル移動させたくないだけなら、
CEditの派生クラスの方にOnLButtonDownとOnContextMenuの
ハンドラを追加してその実装を空にするだけでも
できそうですがどうでしょうか。

Hazard52 2008/10/16(木) 16:56:22
かなり前の記憶ですが、EDITを無効化した場合は、
STATICと同じく、WM_CTLCOLORSTATICが送られてきて、
こちらで処理しないといけなかった様な気がします。

どとう 2008/10/16(木) 17:09:55
よく考えたら、CEditの派生クラスのOnSetFocus()で
前のフォーカスに戻せば良いのではないでしょうか?

void CXXXEdit::OnSetFocus(CWnd* pOldWnd)
{
  //CEdit::OnSetFocus(pOldWnd);
  //前のフォーカスに戻す
    if( pOldWnd ) pOldWnd->SetFocus();
}

カーソルは出なくなりますが、入力もできなくなり
ただのスタティックテキストのようになります。
それで良いのですよね?

Tabで移動できなくなるので、TabStop=FALSEが必要。

花乃 2008/10/16(木) 17:35:36
subaru様 Hazard52様
ありがとうございます。

subaru様
> カーソル移動させたくないだけなら、
> CEditの派生クラスの方にOnLButtonDownとOnContextMenuの
> ハンドラを追加してその実装を空にするだけでも
> できそうですがどうでしょうか。

この場合、無効にしているエディットボックスは、
理想的な動きをしてくれたのですが、
色を変更したいだけの、有効なエディットボックスも
入力が出来なくなってしまったので、

void CColorEdit::OnLButtonDown(UINT nFlags, CPoint point) 
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
    if( !( GetStyle() & ES_READONLY ))
    {
        CEdit::OnLButtonDown(nFlags, point);
    }
}

こんな感じで、回避してみたのですが、
OnContextMenuの方の対応策が思いつきません。
何か良い方法ありますでしょうか?

--------------------------------------------------------------------

Hazard52様
> かなり前の記憶ですが、EDITを無効化した場合は、
> STATICと同じく、WM_CTLCOLORSTATICが送られてきて、
> こちらで処理しないといけなかった様な気がします。

クラスウィザードを使っているのですが、
WM_CTLCOLORSTATICが見当たりません。
自分で、書かないとダメですか?

よろしくお願い致します。

gak 2008/10/16(木) 18:01:33
> ReadOnly(TRUE)にして、TabStopを設定しないというのも
> 試したのですが、エディットボックス内にカーソルが出てしまいます。
> この場合、入力したくなると困るので
文字を範囲選択して Ctrl+C とかされても問題は無いのだけど、カーソルに点滅されると
入力可と誤解されるかもしれないので嫌だ!って可能性もあるのかな。

void CColorEdit::OnSetfocus() {
    ::DestroyCaret();
}

仮にそうならば上記コードでカーソルを消す事は可能なハズ。
だが、内部的にはカーソルは生きているので Shift + 十字キーとかマウスとかで文字の
範囲選択はできちゃうけどね。

> WM_CTLCOLORSTATICが見当たりません。
MFC では WM_CTLCOLORxxxx 系メッセージは WM_CTLCOLOR に纏めて送られてくる。
で、実際にどの WM_CTLCOLORxxxx が送られてきたか判断するには OnCtlColor() の
nCtlColor を見て判断する仕様になってる。
ぶっちゃけると、花乃さんのコードで WM_CTLCOLORSTATIC で送られてきた時の処理はで
きている。(EDIT にくる WM_CTLCOLORxxxx 系メッセージ全てで同じ処理をしているので
結果的に、と言った方が正しいだろうけど)

subaru 2008/10/16(木) 18:11:50
>こんな感じで、回避してみたのですが、
>OnContextMenuの方の対応策が思いつきません。
OnLButtonDownと同様
CEdit::OnContextMenu(...);
で既定の処理が行われます。

>クラスウィザードを使っているのですが、
>WM_CTLCOLORSTATICが見当たりません。
>自分で、書かないとダメですか?
MFCの場合はOnCtlColorの引数で判断すること
になるのですがこれは通常ダイアログ側の実装のはず。
#CEditの派生クラスの方に書いてるみたいだけどメッセージくるのかな?

Hazard52 2008/10/17(金) 09:42:01
gak様、subaru様、ありがとうございます。
MFCの場合は、OnCtlColor()に纏められて送られて来るですね。
確かに以前作った時は、APIで作ってました。

で終わってしまうのも中途半端なので、CEditの派生クラスで作ってみました。
CEditの派生クラスにOnPaint()を追加して、その中で色付けをすると
無効にしても同じく設定できましたが、いかがでしょうか?

花乃 2008/10/17(金) 11:02:21
どとう様 gak様 subaru様 Hazard52様
何度も書き込みしてくださってありがとうございます。

どとう様
> よく考えたら、CEditの派生クラスのOnSetFocus()で
> 前のフォーカスに戻せば良いのではないでしょうか?

void CColorEdit::OnSetFocus(CWnd* pOldWnd) 
{
    if(( GetStyle() & ES_READONLY ))
    {
        // 前のフォーカスに戻す
        if( pOldWnd )
        {
            pOldWnd->SetFocus();
        }
    }
    else
    {
        CEdit::OnSetFocus( pOldWnd );
    }
}

これで、うまくいきました。
SetReadOnly( TRUE );
設定をした、エディットボックスはカーソルが付かず、
それ以外は普通に入力も出来ました。
勿論、色も変わりました。
ありがとうございます。

--------------------------------------------------------------------

gak様
色々と解説ありがとうございます。
まだまだ、勉強不足でカーソルを消すなんて
思いついても無かったです。
参考になりました。

--------------------------------------------------------------------

subaru様
> OnLButtonDownと同様
> CEdit::OnContextMenu(...);
> で既定の処理が行われます。

void CColorEdit::OnContextMenu(CWnd* pWnd, CPoint point) 
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加してください
    if( !( GetStyle() & ES_READONLY ))
    {
        CEdit::OnContextMenu( pWnd,  point );
    }
}

こちらもうまくいきました。
クラスウィザードで関数を作成したとき、
OnLButtonDownは
CEdit::OnLButtonDown(nFlags, point);
↑この、規定クラスを呼ぶコードが勝手に付いてきたのですが、
OnContextMenuには無かったので、
どうしたものかと、考えてしまいました。
無事に解決しました。
ありがとうございます。

--------------------------------------------------------------------

Hazard52様
> で終わってしまうのも中途半端なので、CEditの派生クラスで作ってみました。
> CEditの派生クラスにOnPaint()を追加して、その中で色付けをすると
> 無効にしても同じく設定できましたが、いかがでしょうか?

ありがとうございます。
こちらの案も試してみたくて、
OnPaint()の追加をして、CtlColorのように色をセットしてみたのですが、
文字が出なくなってしまいました。
この場合、CtlColorは標準に戻すのでしょうか?
それと、OnPaint()関数では、色設定のほかに何をすればよいのでしょうか?
何度もすみませんが教えていただければと思います。
よろしくお願い致します。

Hazard52 2008/10/17(金) 11:51:16
OnPaint()は、下記の様に記述しました。
OnChildNotify()が無いと、入力した時に一部しか再描画されません。
ヘッダファイルには、publicで、下の一文を追加して下さい。
virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, 
LRESULT* pLResult);

void CColorEdit::OnPaint() 
{
    UINT        nFormat        = DT_SINGLELINE;
    COLORREF    OldColText;
    COLORREF    OldColBack;
    CString        sTitle;
    CRect        cr1, cr2;
    CPen        cPen;
    CPen*        cPenOld;

    CPaintDC    dc(this);            // 描画用のデバイス コンテキスト

    //    描画ペン生成
    LOGBRUSH    logBrush;
    logBrush.lbStyle = BS_SOLID;
    logBrush.lbColor = RGB(0, 0, 0);
    cPen.CreatePen(PS_SOLID | PS_GEOMETRIC, 1, &logBrush);
    cPenOld = dc.SelectObject(&cPen);
    //    描画文字列取得
    GetWindowText(sTitle);
    //    クライアント矩形描画領域取得
    GetClientRect(&cr1);

    cr2.left = cr1.left + 1;
    cr2.top = cr1.top + 1;
    cr2.right = cr1.right - 1;
    cr2.bottom = cr1.bottom - 1;
    dc.FillSolidRect(cr2, m_ColBack);

    OldColText = dc.SetTextColor(m_ColText);
    OldColBack = dc.SetBkColor(m_ColBack);
    dc.DrawText(sTitle, &cr2, nFormat);

    //    変更した属性を戻す
    dc.SetTextColor(OldColText);
    dc.SetBkColor(OldColBack);
    dc.SelectObject(cPenOld);
}

BOOL CColorEdit::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, 
LRESULT* pLResult) 
{
    Invalidate();
    return CEdit::OnChildNotify(message, wParam, lParam, pLResult);
}

Hazard52 2008/10/17(金) 11:53:30
あっ。すいません。
CtlColor()は、使用してませんでした。

花乃 2008/10/17(金) 16:00:54
[[解決]]
Hazard52様
親切にしてくださって、ありがとうございます。

教えてくださった方法でも、
希望通りの動作が出来ました。
OnPaint関数では、自分で描画しないといけなかったのですね。
OnChildNotifyの存在も知らなかったので、
本当に勉強になりました。感動です。
ありがとうございました。

一つの事を実現するのに、色々な方法があるのですね。
今回は、OnSetFocusで、前のフォーカスに戻すことに
致しました。
教えてくださった皆さん、ありがとうございました。

古いスレッドには追加発言できません。