2011-03-15 76 views
0

現在我試圖找到解決方案「per-apllication cleartype fonts」問題。渲染系統控制字體以外的字體

我想實現TextBoxButtonComboBox或任何其他非自定義/庫存控件的明文字體。

好,有一個簡單的方法來實現這一目標,我知道的,那就是,重寫OnPaint方法:

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

    base.OnPaint(pevent); 
} 

,這工作得很好,但事情是,我想這樣做而不會繼承這些控件,並以某種方式從類外改變字體屬性。

我迄今爲止使用的方法並沒有取得太大的成功,而是安裝了'Hook Procedure'並偵聽發送到控件的消息。代碼波紋管是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方法中的系統消息時,是否在繪畫時繼續傳送WndProcMessage.WParam & Message.LParam中的數據?

例如。當繪製文本時,系統不應該使用WM_GETFONT來使用合適的字體嗎? 我對於一個不知道任何設置字體渲染類的控件屬性。

是否有解決此問題的其他解決方案?

回答

0

我看到它開始成爲一種習慣回答我的問題:d

以及..只要我找到答案沒問題,

無論如何,解決我的問題很簡單: 要在類外部呈現按鈕,標籤或組框文本(沒有繼承基類並覆蓋OnPaint方法),應該將控件的FaltStyle屬性設置爲系統(例如myControl.FlatStyle = FlatStyle.System;),以便系統將處理畫畫。

然後,安裝全局窗口過程並覆蓋WM_PAINT消息。這裏是我發現創建一個新的邏輯字體並將WM_SETFONT消息發送給控件的好地方。

很好地工作,但是,有一種更簡單的方法!

我也玩過Font.FromLogFont(LOGFONT),但沒有任何成功; 字體質量沒有設置,但我不知道爲什麼沒有。

如果有人能解釋爲什麼,請這樣做。