11

エディット コントロール内にテキスト ヒントが表示されるEM_SETCUEBANNERの機能を実装する必要があります。

エディット コントロールのキュー バナーの例

問題は、マイクロソフトが提供するキュー バナーの実装を取得するために必要な Common Controls のバージョン 6 を使用できないことです。

編集コントロールのテキストとフォント形式を変更するだけで調べました

Dark Gray Italic Text

しかし、回避する方法が見つからないChangeイベント(より高いコンポーネントライブラリによって提供されるコンポーネントラッパー)をスローします。

そのため、代わりにテキストをカスタム描画し、コントロールがフォーカスされておらず空のときにキューバナーテキストを描画し、それ以外の場合はデフォルトの描画に依存していました。

Edit コントロールは、 ListView、TreeView などのカスタム描画メカニズムを適切に公開しません。

他の人が調べましたが、ほとんど不可能な作業のようです:

状況から見て、次のメッセージを処理する必要があります。

  • WM_ERASEBKGND、WM_PAINT (明らかな理由)
  • WM_SETFOCUS、WM_KILLFOCUS (白いバーが表示されないようにするため -- 上記)
  • WM_CHAR (コントロール内のテキストを処理および更新するため)

また、コントロールにキャレットを表示する方法も見つける必要があります。これは、前述の白いバーをペイントせずに Windows でキャレットを表示できるようにする方法が見つからないためです。

これは楽しいことになるだろう。:ロールアイズ:

Windows Edit コントロールがカスタム描画されることを意図していなかったことを考えると、Windows Edit コントロールをカスタム描画する方法を知っている人はいますか?


:質問に答えるのではなく、問題を解決する回答も受け入れます。しかし、この質問に出くわして編集コントロールをカスタム描画したい他の人は、おそらく答えが欲しいでしょう.

4

5 に答える 5

10

編集コントロールをカスタム描画することは基本的に不可能です。いくつかの特殊なケースがありますが、それを回避できるほどのことはほとんど行っていませんが、次のリビジョンのWindowsで(または誰かが古いバージョンでアプリを実行したり、ターミナルサービスを介して)ひどく壊れてしまうリスクがあります。

コントロールが他のメッセージにもペイントすることがあるため、WM_PAINTとWM_ERASEBKGROUNDを引き継ぐだけでは十分ではありません。

独自の編集コントロールを作成する方がよいでしょう。これは膨大な量の作業であることを私は知っていますが、長期的には、編集コントロールのすべての描画コードを引き継ぐ方法をハックしようとするよりも作業が少なくなります。

古き良き時代に、誰もがボタンコントロールをサブクラス化して色やグラフィックスなどを追加していたことを思い出します。ある日、座って自分のボタンウィンドウクラスを作成しました。そして、Windowsボタンをサブクラス化してカスタム描画するのは、ソースツリーにあるものよりも少ないコードでした。

于 2009-12-24T04:50:24.747 に答える
5

キュー テキストを描画し、キャレットを表示し、フォーカスを持つ空の編集コントロールのような独自のウィンドウ クラスを作成します。エディット コントロールも作成しますが、ウィンドウの後ろに配置します。(または非表示のままにする)

次に、最初の WM_CHAR メッセージ (または WM_KEYDOWN?) を受け取ったとき。ウィンドウを編集コントロールの背後に置き、編集にフォーカスを与え、WM_CHAR メッセージを渡します。それ以降は、編集コントロールが引き継ぎます。

エディットが空になったときにキュー テキストの表示に戻る必要がある場合は、エディット コントロールから EN_CHANGE 通知を聞くことができます。しかし、編集がフォーカスを失い、空の場合にのみ、キューテキストに戻るのは問題ないと思います。

于 2009-12-24T04:32:50.547 に答える
5

EDIT コントロールのサブクラス化は、私にとってはうまくいきました。オブジェクト属性を編集するときに、書式設定情報をユーザーに表示する必要がありました (一部の属性は複数行になる可能性があります)。エイドリアンも彼の答えで言ったように、重要なことは、独自の描画の前にEDIT コントロールのプロシージャを呼び出すことです。後で呼び出すか、独自の BeginPaint/EndPaint (return 0 または DefWindowProc を使用) を発行すると、テキストがまったく表示されない、サイズ変更時にのみ表示され、編集後は表示されない、残りのキャレットの画面のゴミが残るなどの問題が発生しました。これで、EDIT コントロールの他の再描画時間に関係なく、問題は発生しませんでした。

いくつかのセットアップ:

SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));

// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");

コールバック:

LRESULT CALLBACK AttributeValueEditProcedure(
    HWND hwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR subclassId,
    DWORD_PTR data
    )
{

...

case WM_PRINTCLIENT:
case WM_PAINT:
    {
        auto textLength = GetWindowTextLength(hwnd);
        if (textLength == 0 && GetFocus() != hwnd)
        {
            // Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
            // control's WM_PAINT handler calls BeginPaint/EndPaint, which
            // validates the update rect and would otherwise lead to drawing
            // nothing later because the region is empty. Also, grab it from
            // the cache so we don't mess with the EDIT's DC.
            HDC hdc = (message == WM_PRINTCLIENT)
                ? reinterpret_cast<HDC>(wParam)
                : GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);

            // Call the EDIT control so that the caret is properly handled,
            // no caret litter left on the screen after tabbing away.
            auto result = DefSubclassProc(hwnd, message, wParam, lParam);

            // Get the font and margin so the cue banner text has a
            // consistent appearance and placement with existing text.
            HFONT font = GetWindowFont(hwnd);
            RECT editRect;
            Edit_GetRect(hwnd, OUT &editRect);

            // Ideally we would call Edit_GetCueBannerText, but since that message
            // returns nothing when ES_MULTILINE, use a window property instead.
            auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));

            HFONT previousFont = SelectFont(hdc, font);
            SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
            SetBkMode(hdc, TRANSPARENT);
            DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
            SelectFont(hdc, previousFont);

            ReleaseDC(hwnd, hdc);

            // Return the EDIT's result (could probably safely just return zero here,
            // but seems safer to relay whatever value came from the edit).
            return result;
        }
    }
    break;

独自の EDIT コントロールを作成すること (組み込みのものと比較して部分的な完成度で実際に複数回行ったことがあります) は、最小限の作業を行う場合 (基本的なキャレット サポートのある英語のみ) はそれほど作業ではありませんが、可変サイズのクラスタを使用した複雑なスクリプトでのキャレット ナビゲーション、範囲での選択、IME サポート、コピー アンド ペーストによるコンテキスト メニュー、ハイ コントラスト モード、テキスト読み上げなどのアクセシビリティ機能が必要な場合は、修正するのに多くの作業が必要です。したがって、他の多くの回答とは異なり、キュー バナー テキストのためだけに独自の EDIT コントロールを実装しないことをお勧めします。

于 2015-07-17T23:35:34.800 に答える
3

エディット コントロールをサブクラス化します。最初に元のウィンドウ プロシージャを呼び出して処理WM_PAINTし、それが空でフォーカスされていない場合は、キュー テキストを描画します。他のすべてのメッセージを元のウィンドウ プロシージャに渡します。

私はこれをやった - それは動作します。CodeGuru の人が抱えていた問題は、あなたの状況には当てはまらないようです。彼は外見にもっと力を入れようとしていると思います。パフォーマンスのために、エディット コントロールが処理外でいくつかの更新を行っているように見えますWM_PAINT(おそらくパフォーマンスのため)。そのため、外観を完全に制御することはほぼ不可能になります。ただし、キュー プロンプトを描画することはできます。

于 2009-12-23T22:41:20.067 に答える
0

また、コントロールにキャレットを表示する方法も見つける必要があります。これは、前述の白いバーをペイントせずに Windows でキャレットを表示できるようにする方法が見つからないためです。

スーパークラスの元の windowproc にメッセージを転送せずに WM_PAINT を自分で処理したい場合は、DefWindowProc を呼び出すことを忘れないでください。キャレットが描画されるように。白いバーを避けるには、SetClassLongPtr でクラス ブラシを削除する必要があります。そして、どういうわけか、編集コントロールの ExtTextOut 出力をクリップするために、DC のクリッピング領域を保持します。白いバーは、編集コントロールによって ExtTextOut に渡された OPAQUE オプションの結果である可能性があります。

結論: 独自のコントロールを記述します。痛みなくして得るものなし。

于 2012-10-06T11:27:19.717 に答える