سؤال

أحتاج إلى تنفيذ وظائف em_setcuebanner, ، حيث يظهر تلميح نص داخل عنصر تحكم التحرير:

Example of cue banner in edit control

الصيد هو أنه لا يمكنني استخدام الإصدار 6 من عناصر التحكم المشتركة ، وهو ما هو مطلوب للحصول على تنفيذ Microsoft المرفق لافتة جديلة.

لقد بحثت ببساطة في تغيير نص تحكم التحرير ، وتنسيق الخط إلى

Dark Gray Italic Text

لكنه سوف يرمي يتغيرون الأحداث (غلاف المكون الذي توفره مكتبة مكون أعلى) أنني لا أستطيع إيجاد طريقة لتجنب.

لذلك كنت بدلاً من ذلك ، كنت أذهب إلى رسم النص المخصص ، ورسم نص راية جديلة عندما يكون التحكم غير مركّز وفارغًا ، والاعتماد على اللوحة الافتراضية على خلاف ذلك.

لا يعرض عنصر تحرير التحرير بشكل جيد آلية رسم مخصصة ، مثل ListView و TreeView وغيرها توفر.

لقد نظر أشخاص آخرون في ذلك, ، ولكن يبدو أنها مهمة شبه مستحيلة:

من الطريقة التي تبحث بها الأمور ، سأضطر إلى التعامل مع الرسائل التالية:

  • WM_ERASEBKGND ، WM_PAINT (لاسباب واضحة)
  • wm_setfocus ، wm_killfocus (لمنع الشريط الأبيض من العرض - الموضح أعلاه)
  • WM_CHAR (لمعالجة النص وتحديثه في عنصر التحكم)

وأحتاج أيضًا إلى إيجاد طريقة لعرض الكاريت في عنصر التحكم ، لأنني لم أجد طريقة للسماح لـ Windows بالقيام بذلك من أجلي دون رسم الشريط الأبيض الذي ذكرته.

هذا سيكون ممتعا. :عيون لفة:

بالنظر إلى أن التحكم في تحرير Windows لم يكن من المفترض أن يكون مخصصًا: هل يعرف أي شخص كيفية رسم عنصر تحكم في تحرير Windows؟


ملحوظة: سأقبل أيضًا الإجابات التي تحل مشكلتي ، بدلاً من الإجابة على سؤالي. لكن أي شخص آخر يرغب في رسم عنصر تحكم تحرير مخصص ، واجه هذا السؤال ، ربما يحب الإجابة.

هل كانت مفيدة؟

المحلول

الرسم المخصص للتحكم في التحرير مستحيل بشكل أساسي. هناك عدد قليل من الحالات المتخصصة التي كنت تفعلها القليل جدًا والتي يمكن أن تفلت من ذلك ، لكنك تخاطر بالخروج بشكل سيء في المراجعة التالية للنوافذ (أو عندما يقوم شخص ما بتشغيل تطبيقك على إصدار أقدم ، أو عبر الخدمات الطرفية ، إلخ).

مجرد الاستيلاء على WM_PAINT و WM_ERASEBKGROund ليست جيدة بما فيه الكفاية ، لأن التحكم سوف يرسم أحيانًا على رسائل أخرى أيضًا.

أنت أفضل حالًا فقط كتابة تحكم التحرير الخاص بك. أعلم أن هذا قدر كبير من العمل ، ولكن على المدى الطويل سيكون العمل أقل من محاولة اختراق طريقك إلى تولي جميع رمز رسم تحرير تحرير.

أتذكر مرة أخرى في الأيام الخوالي عندما يستخدم الجميع لنقام التحكم في الزر لإضافة اللون والرسومات ، إلخ. وكان رمزًا أقل مما كان لدينا في شجرة المصدر الخاصة بنا إلى الفئة الفرعية ورسم زر Windows المخصص.

نصائح أخرى

قم بإنشاء فئة نافذة خاصة بك تبدو مثل التحكم الفارغ في التحرير ، والتي ترسم نص جديلة ويظهر سيارة مياه ويركز. قم بإنشاء عنصر تحكم التحرير أيضًا ، ولكن ضعه خلف نافذتك. (أو اتركها مخفية)

ثم عندما تحصل على رسالة WM_CHAR الأولى (أو WM_KEYDOWN؟). يمكنك وضع نافذتك خلف Conrol Edit ، وتركيز على التحرير ، وتمرير رسالة WM_CHAR. ومنذ ذلك الحين ، سيتولى التحكم في التحرير.

يمكنك الاستماع إلى إخطارات EN_CHANGE من عنصر تحكم التحرير إذا كنت بحاجة إلى العودة إلى عرض نص الإشارات الخاص بك عندما يصبح التعديل فارغًا. لكنني أعتقد أنه سيكون من الجيد العودة إلى نص الإشارات فقط عندما يفقد التحرير التركيز وهو فارغ.

تم تصنيف التحكم في تحرير التحكم بشكل جيد بالنسبة لي - اللازم لعرض بعض معلومات التنسيق للمستخدم عند تحرير سمات الكائن (ويمكن أن تكون بعض السمات خطوطًا متعددة). الشيء المهم ، كما قال أدريان في إجابته أيضًا ، هو استدعاء إجراء تحكم التحرير قبل الرسم الخاص بك. تسبب وصفها بعد ذلك أو إصدارها الخاص في البداية/البهجة (مع إرجاع 0 أو defwindowproc) مشكلات بالنسبة لي من النص الذي لا يعرض على الإطلاق ، حتى يتم عرضه فقط عند تغيير الحجم ولكن ليس بعد التحرير ، إلى ترك القمامة الشاشة للسيارة بقايا. مع ذلك ، لم أواجه أي مشاكل بغض النظر عن أوقات إعادة التعديل الأخرى في تحرير.

بعض الإعداد:

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;

إن كتابة التحكم في التحرير الخاص بك (الذي قمت به بالفعل أكثر من مرة ، إلى درجات جزئية من الاكتمال مقارنةً بالذات المدمجة) ليس كثيرًا من العمل إذا قمت بعمل الحد الأدنى (ربما باللغة الإنجليزية فقط مع دعم الإقحام الأساسي) ، ولكن إنه الكثير من العمل للحصول على صحيح إذا كنت تريد التنقل في Caret عبر البرامج النصية المعقدة مع مجموعات متغيرة الحجم ، والاختيار على النطاقات ، ودعم IME ، وقوائم السياق مع النسخ واللصق ، وأنماط التباين العالية ، وميزات إمكانية الوصول مثل النص إلى الكلام. على عكس العديد من الإجابات الأخرى ، أوصي ليس تنفيذ تحكم تحريرك فقط لنص راية جديلة.

الفئة الفرعية تحكم تحرير. مقبض WM_PAINT من خلال الاتصال أولاً بإجراء النافذة الأصلية ، وبعد ذلك ، إذا كان فارغًا وليس في التركيز ، ارسم نص الإشارات. تمرير كل رسالة أخرى إلى إجراء النافذة الأصلي.

لقد فعلت هذا-إنه يعمل. لا يبدو أن المشكلة التي يواجهها شخص Codeguru تنطبق على وضعك. أعتقد أنه يحاول بذل المزيد من الجهد للمظهر. بالنسبة للأداء ، يبدو أن التحكم في التحرير يقوم ببعض التحديثات خارج WM_PAINT المعالجة (ربما للأداء). هذا سيجعل من المستحيل تقريبًا السيطرة الكاملة على المظهر. ولكن يمكنك رسم موجه جديلة.

وأحتاج أيضًا إلى إيجاد طريقة لعرض الكاريت في عنصر التحكم ، لأنني لم أجد طريقة للسماح لـ Windows بالقيام بذلك من أجلي دون رسم الشريط الأبيض الذي ذكرته.

إذا كنت ترغب في التعامل مع WM_Paint بنفسك دون إعادة توجيه الرسالة إلى WindowProc الأصلي من فئة الفئة الفائقة الخاصة بك ، يجب ألا تنسى استدعاء DefWindowProc. بحيث يتم رسم الكاريت. لتجنب الشريط الأبيض ، يجب إزالة فرشاة الفصل باستخدام setClassLongPtr. وبطريقة ما احتفظ بمنطقة القطع في DC لتصليط مخرجات ExtTextout الخاصة بـ Controt. قد يكون الشريط الأبيض نتيجة لخيار غير شفاف تم تمريره إلى exttextout عن طريق تحرير التحكم.

الخلاصة: اكتب سيطرتك الخاصة. لا ألم, لا ربح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top