2010-07-26 97 views
10

我一直在使用Delphi 2010中的Aero試圖找到一個好看的設計。人們看到的一個明顯的用途就是將玻璃框架擴展爲包含OK/Cancel按鈕在屏幕的底部。我注意到,雖然這在Delphi 2010中看起來不太正確 - 每個按鈕周圍都有一個白色邊框。Delphi按鈕在Aero玻璃上顯示白色邊框

此圖顯示了問題:前3個按鈕來自我的應用程序,最下面兩個來自Paint.NET的圖層屬性對話框。

White borders around Delphi controls http://i30.tinypic.com/1zzqfm0.png

我試圖和DoubleBuffered的各種組合第一放置在其他控件的控件的幾個組合,但問題仍然存在。有任何想法嗎?

+2

您是否擁有顯示此行爲的最小應用程序的來源? (.dfm和.pas的簡單形式將會這樣做) – 2010-07-26 14:26:48

+0

@Jeroen:我可以用包含TButton並設置玻璃框的簡單表單重現該行爲,以便按鈕位於玻璃上。我目前無法連接到QC,因此我無法確定是否存在類似的錯誤。 – 2010-07-26 14:30:50

+0

有趣的行爲 - 當button.doublebuffered爲true,但形式doublebuffered是假的,我得到一個顏色(黑色)周圍的按鈕,當兩個是真實的,我得到不同的顏色(如上面,灰色或clBtnFace),當按鈕不是雙緩衝的,文本看起來變灰。所以如果沒有看起來像垃圾,在delphi 2010上使用玻璃上的按鈕是不可能的? – 2010-07-27 20:13:12

回答

5

如果沒有人有乾淨的解決方案,作爲解決方法使用TBitBtnDoubleBuffered = false

+3

+1用於開箱即用的思考。但當然,它從來沒有這麼簡單:-( BitBtn看起來沒有雙緩衝沒有雙緩衝,但沒有雙緩衝,但打開它的形式,並且BitBtn看起來是一樣的,關閉窗體,並且你的標籤消失了。Aaargh! – 2010-07-26 15:05:08

+0

TSpeedButton在我嘗試這裏時看起來很好,但它不接受鍵盤焦點 – 2010-07-27 20:14:16

+0

在Delphi XE中,TBitBtn完美工作 - 無論TBitBtn或表單上的DoubleBuffered設置如何,這都是我的首選解決方案 – 2011-07-12 08:52:43

2

似乎唯一的解決方法是所有者繪製或第三方按鈕控件Check out the Glass Button by Roy Klever或者如下面鏈接的質量控制條目中所述TBitBtn帶有DoubleBuffered = false,這是此問題上面已接受的答案。

這是Windows Aero DWM中的一個錯誤,或者是Windows常見控件中的錯誤,或者是VCL類層次處理常見控件窗口消息和繪製玻璃時繪畫的錯誤。總之,Windows常用控件不能在玻璃上正確地自行塗漆,或者DWM組合(Aero)破損。驚喜。

標準的VCL按鈕組件使用Windows Common Controls中的Window Class BUTTON。

請注意TSpeedButton不使用Windows公共控件,並沒有這個問題。但是,它也不接受重點。

看來Embarcadero知道這個問題,它是QC# 75246,它是關閉的,因爲它實際上是公共控制庫中的一個錯誤,就像Will not Fix一樣,建議使用TBitBtn。按鈕並不孤單,這是一組QC報告的一部分,包括面板和其他常用控件。

但是,我有一個商業TcxButton(開發人員快速組件的一部分)接受鍵盤焦點,並沒有畫出這個故障。任何使用Win32公共控件按鈕控件的代碼似乎都有此問題。低級別的Win32 API黑客可能會找到解決方法。我正在研究它。如果我知道這個答案將會被更新。

一個有趣的細節:TcxButton有三種繪畫風格,cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}。選擇lfOffice11會將此故障重新加入。它看起來像是Vista/Win7中的aero中的玻璃功能與普通的control/xptheme按鈕繪圖代碼之間的奇怪交互。

這可能是唯一的解決方法是使用完全應用繪製的按鈕控件,並且不使用Windows常用控件按鈕或任何依賴於XP主題引擎的按鈕控件在航空玻璃窗格上繪製按鈕。

編輯:7月28日,Embarcadero的某人已經關閉了上述質檢條目,這是一個錯誤。我敦促他們重新打開它,如果只是爲了澄清這是否確實是常見控件DLL中的Windows錯誤。

如果你想玩弄,從StdCtrls複製TButton和TCustomButton類的VCL源代碼,就像我在這裏所做的那樣,修改CNCtlColorBtn,以便強制執行三件事之一 - PerformEraseBackground, DrawParentBackground或繼承,並查看結果。有趣的東西。

procedure TCustomGlassButton.CNCtlColorBtn(var Message: TWMCtlColorBtn); 
begin 
    PerformEraseBackground(Self, Message.ChildDC); 
    Message.Result := GetStockObject(NULL_BRUSH); 
(* 
    with ThemeServices do 
    if ThemesEnabled then 
    begin 
     if (Parent <> nil) and Parent.DoubleBuffered then 
     PerformEraseBackground(Self, Message.ChildDC) 
     else 
     DrawParentBackground(Handle, Message.ChildDC, nil, False); 
     { Return an empty brush to prevent Windows from overpainting we just have created. } 
     Message.Result := GetStockObject(NULL_BRUSH); 
    end 
    else 

     inherited; 
    *) 
end; 

Some interesting reading on Vista era glass/DWM/aero APIs (C++ developers blog)

1

Here我提供了一些代碼,使TButton的期待權上的玻璃。不幸的是,它使形式「點擊投擲」,所以我不認爲這是一個好主意。但是,也許你可以找到一種方法來修復表單的「點擊」。

0

如果你能夠使用win32 api,試着利用NM_CUSTOMDRAW通知(不是ownerdraw),就像我一樣(是的,按鈕發送它,包括收音機和複選框,但最好使用WM_CTLCOLORSTATIC)。這是如何在C++中完成的,但這個想法是一樣的。雖然我的想法很好,但偶爾我的按鈕在程序執行過程中從窗口執行DISAPPEAR一次,當它們是customdrawn時,我需要將鼠標懸停在它們上方,以便它們再次可見。這就是爲什麼我仍然在爲此尋找意見。請注意,在單一形式的應用程序中重現消失的按鈕非常困難。我在每個項目中都經歷過這種行爲。

case WM_NOTIFY: 
    switch(((LPNMHDR)lParam)->code){ 
    case NM_CUSTOMDRAW: 
    { 
     NMHDR *nmh=(NMHDR*)lParam; 
     //these 6000 through 6004 are button identifiers assigned by me 
     if(nmh->idFrom >= 6000 && nmh->idFrom <= 6004){ 
     switch(((LPNMCUSTOMDRAW)nmh)->dwDrawStage){ 
      case CDDS_PREERASE: 
      //BackgroundBrush is a HBRUSH used also as window background 
      FillRect(((LPNMCUSTOMDRAW)nmh)->hdc, &((LPNMCUSTOMDRAW)nmh)->rc, BackgroundBrush); 
      break; 
     } 
    } 
    break; 
} 
break;