Система рендеринга контролирует шрифты вне класса - PullRequest
0 голосов
/ 15 марта 2011

уже довольно давно я пытаюсь найти решение проблемы "per-apllication cleartype fonts".

Я хочу реализовать шрифты cleartype для TextBox, или Button, или ComboBox, или любого другого нестандартного / стандартного элемента управления.

Ну, есть один простой способ добиться этого, о котором я знаю, и это переопределение метода OnPaint:

protected override void OnPaint(PaintEventArgs pevent)
{
    pevent.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

    base.OnPaint(pevent);
}

и это прекрасно работает, но дело в том, что я хочу сделать это без наследования какого-либо из этих элементов управления и каким-то образом изменить свойства шрифта вне класса.

метод, который я использовал до сих пор без особого успеха, состоял в том, чтобы установить «процедуру подключения» и прослушать сообщения, отправленные элементам управления. код ниже является частью Form1 class:

// the delegate with the same signature as the callback function
private delegate int HookMessages(int nCode, IntPtr wParam, IntPtr lParam);

// when the Load event of the Form takes place the controls are created
// and the method that sets the hooks is called
private void Form1_Load(object sender, EventArgs e)
{
    Button btn = new Button();
    btn.Name = "btn";
    btn.Parent = this;
    btn.Size = new Size(this.ClientRectangle.Width - 10, 20);
    btn.Location = new Point(5, tbx.Top + tbx.Height + 10);
    btn.BackColor = Color.FromArgb(100, 1, 1, 1);
    btn.Text = "Click ME";

    HookControlMessages();
}

// the hook that monitors control's events is set for the current thread
private void HookControlMessages()
{
    if (hookWndHandle == 0)
    {
        HookWndProcedure = new HookMessages(HookWndProcMessages);

        hookWndHandle = SetWindowsHookEx(
            WindowHookTypes.WH_CALLWNDPROC,
            HookWndProcedure,
            IntPtr.Zero,
            (int)GetCurrentThreadId());

        if (hookWndHandle == 0)
        {
            MessageBox.Show("Window`s messages hooking failed.");

            return;
        }
    }
}

// the callback function
private static int HookWndProcMessages(int nCode, IntPtr wParam, IntPtr lParam)
{
    int nextHook = 0;

    try
    {
        if (nCode >= 0)
        {
            CWPSTRUCT m = (CWPSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPSTRUCT));

            _thisInstance.CheckWndProcMsgs(m);
        }

        nextHook = CallNextHookEx(hookWndHandle, nCode, wParam, lParam);
    }
    catch
    {
        nextHook = 0;
    }

    return nextHook;
}

private void CheckWndProcMsgs(CWPSTRUCT m)
{
    if (m.hwnd == ((this.Controls.Find("btn", true) as Control[])[0] as Button).Handle)
    {
        #region BUTTON

        switch (m.message)
        {
            case (int)WindowsMessages.WM_CREATE:
                {
                    // when the handle of the control is created also a new font is created
                    // and a WM_SETFONT message sent along with the specification that a redraw must be performed
                    Rect rc = new Rect(new Rectangle(0, 0, ((this.Controls.Find("btn", true) as Control[])[0] as UButton).Width, ((this.Controls.Find("btn", true) as Control[])[0] as UButton).Height));
                    hFontNew = CreateFont(
                        25, 5, 2, 0, 900, 0, 0, 0,
                        (byte)FontCharSet.OEM_CHARSET,
                        (byte)FontPrecision.OUT_DEFAULT_PRECIS,
                        (byte)FontClipPrecision.CLIP_DEFAULT_PRECIS,
                        (byte)FontQuality.DEFAULT_QUALITY,
                        (byte)(FontPitchAndFamily.DEFAULT_PITCH | FontPitchAndFamily.FF_DONTCARE),
                        "Verdana");

                    SendMessage(m.hwnd, (uint)WindowsMessages.WM_SETFONT, hFontNew, (IntPtr)1);
                }
                break;
            case (int)WindowsMessages.WM_SETFONT:
                {
                    // the purpose of this block is to verify if the new font is set correct
                    LOGFONT lf = new LOGFONT();
                    IntPtr lf0 = Marshal.AllocCoTaskMem(Marshal.SizeOf(lf));

                    GetObject((IntPtr)m.wparam, Marshal.SizeOf(lf), lf0);
                    lf = (LOGFONT)Marshal.PtrToStructure(lf0, lf.GetType());

                    Marshal.FreeCoTaskMem(lf0);
                }
                break;
            case (int)WindowsMessages.WM_DESTROY:
                {
                    // when the control is destroyed the new font is also deleted
                    if (hFontNew != IntPtr.Zero)
                    {
                        DeleteObject(hFontNew);
                    }
                }
                break;
        }

        #endregion
    }
}

эта часть будет отлично работать для окна, созданного с помощью функций CreateWindow / CreateWindowEx, или если Paint event будет обрабатываться пользователем для пользовательской краски, но я хочу оставить всю картину в системе и изменять только шрифт без каких-либо других вмешательств в элемент управления.

должен ли этот подход работать? если нет, может кто-нибудь объяснить мне, почему? Я знаю, что когда система рисует элементы управления, она использует шрифт, заданный свойством Control.Font класса, но не должен ли он также использовать рендеринг шрифта из оконных сообщений? когда класс обрабатывает системные сообщения в методе WndProc, разве он не ретранслирует данные, поступившие в Message.WParam & Message.LParam из WndProc во время рисования?

например. при рисовании текста не должна ли система использовать WM_GETFONT, чтобы использовать соответствующий шрифт? Я, например, не знаю ни одного свойства Control, которое устанавливает рендеринг шрифта вне класса.

есть ли другие способы решения этой проблемы?

1 Ответ

0 голосов
/ 19 марта 2011

Я вижу, что это становится привычкой отвечать на мои собственные вопросы: D

хорошо ... нет проблем, пока я нахожу ответ,

так или иначе, решение моего вопросадовольно просто: чтобы отобразить кнопку, или метку, или текст группового блока вне класса (без создания подкласса базового класса и переопределения метода OnPaint), нужно установить свойство FaltStyle элемента управления в system (например, myControl.FlatStyle = FlatStyle.System;),поэтому система будет обрабатывать чертеж.

, затем установите процедуру глобального окна и переопределите сообщение WM_PAINT.вот одно хорошее место, которое я нашел для создания нового логического шрифта и отправки сообщения WM_SETFONT в элемент управления.

работает хорошо, но есть более простой способ!

Я имеютакже немного поигрался с Font.FromLogFont(LOGFONT), но безуспешно;качество шрифта не установлено, и все же, я не знаю, почему нет.

если кто-то может объяснить почему, пожалуйста, сделайте это.

...