当我尝试禁用一个风格的VCL上的按钮使用下面的代码行
TButton(Sender).enabled:= False;
我得到这个结果(在运行时禁用了按钮)
而不是这个! (设计时按钮禁用)
让两个或更多个具有相同颜色的按钮彼此相互混淆确实令人困惑,一个被禁用,另一个被启用
解决方法
此问题的原因位于
TButtonStyleHook
(在Vcl.StdCtrls单元)样式hook类的Paint方法中.
if FPressed then Details := StyleServices.GetElementDetails(tbPushButtonPressed) else if MouseInControl then //this condition is triggered even if the button is disabled Details := StyleServices.GetElementDetails(tbPushButtonHot) else if Focused then //this condition is triggered even if the button is disabled Details := StyleServices.GetElementDetails(tbPushButtonDefaulted) else if Control.Enabled then Details := StyleServices.GetElementDetails(tbPushButtonNormal) else Details := StyleServices.GetElementDetails(tbPushButtonDisabled);
并替换此代码
if FPressed then Details := StyleServices.GetElementDetails(tbPushButtonPressed) else if MouseInControl and Control.Enabled then Details := StyleServices.GetElementDetails(tbPushButtonHot) else if Focused and Control.Enabled then Details := StyleServices.GetElementDetails(tbPushButtonDefaulted) else if Control.Enabled then Details := StyleServices.GetElementDetails(tbPushButtonNormal) else Details := StyleServices.GetElementDetails(tbPushButtonDisabled);
另一个选项是重写TButton的Style钩子:
检查这个代码在这篇文章Fixing a VCL Style bug in the TButton component.这个代码的优点是你正在修复两个问题103708和103962.
Uses Winapi.CommCtrl,Vcl.Themes,Vcl.Styles; type TCustomButtonH=class(TCustomButton); //we need this helper to access some strict private fields TButtonStyleHookHelper = class Helper for TButtonStyleHook protected function Pressed : Boolean; function DropDown: Boolean; end; //to avoid writting a lot of extra code we are to use TButtonStyleHook class and override the paint method TButtonStyleHookFix = class(TButtonStyleHook) protected procedure Paint(Canvas: TCanvas); override; end; { TButtonStyleHookFix } procedure TButtonStyleHookFix.Paint(Canvas: TCanvas); var LDetails : TThemedElementDetails; DrawRect : TRect; pbuttonImagelist : BUTTON_IMAGELIST; IW,IH,IY : Integer; LTextFormatFlags : TTextFormatFlags; ThemeTextColor : TColor; Buffer : string; BufferLength : Integer; SaveIndex : Integer; X,Y,I : Integer; BCaption : String; begin if StyleServices.Available then begin BCaption := Text; if Pressed then LDetails := StyleServices.GetElementDetails(tbPushButtonPressed) else if MouseInControl and Control.Enabled then LDetails := StyleServices.GetElementDetails(tbPushButtonHot) else if Focused and Control.Enabled then LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted) else if Control.Enabled then LDetails := StyleServices.GetElementDetails(tbPushButtonNormal) else LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); DrawRect := Control.ClientRect; StyleServices.DrawElement(Canvas.Handle,LDetails,DrawRect); if Button_GetImageList(handle,pbuttonImagelist) and (pbuttonImagelist.himl <> 0) and ImageList_GetIconSize(pbuttonImagelist.himl,IW,IH) then begin if (GetWindowLong(Handle,GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK then IY := DrawRect.Top + 15 else IY := DrawRect.Top + (DrawRect.Height - IH) div 2; //here the image is drawn properly according to the ImageAlignment value case TCustomButton(Control).ImageAlignment of iaLeft : begin ImageList_Draw(pbuttonImagelist.himl,Canvas.Handle,DrawRect.Left + 3,IY,ILD_NORMAL); Inc(DrawRect.Left,IW + 3); end; iaRight : begin ImageList_Draw(pbuttonImagelist.himl,DrawRect.Right - IW -3,ILD_NORMAL); Dec(DrawRect.Right,IW - 3); end; iaCenter: begin ImageList_Draw(pbuttonImagelist.himl,(DrawRect.Right - IW) div 2,ILD_NORMAL); end; iaTop : begin ImageList_Draw(pbuttonImagelist.himl,3,ILD_NORMAL); end; iaBottom: begin ImageList_Draw(pbuttonImagelist.himl,(DrawRect.Height - IH) - 3,ILD_NORMAL); end; end; end; if (GetWindowLong(Handle,GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK then begin if pbuttonImagelist.himl = 0 then Inc(DrawRect.Left,35); Inc(DrawRect.Top,15); Inc(DrawRect.Left,5); Canvas.Font := TCustomButtonH(Control).Font; Canvas.Font.Style := []; Canvas.Font.Size := 12; LTextFormatFlags := TTextFormatFlags(DT_LEFT); if StyleServices.GetElementColor(LDetails,ecTextColor,ThemeTextColor) then Canvas.Font.Color := ThemeTextColor; StyleServices.DrawText(Canvas.Handle,BCaption,DrawRect,LTextFormatFlags,Canvas.Font.Color); SetLength(Buffer,Button_GetNoteLength(Handle) + 1); if Length(Buffer) <> 0 then begin BufferLength := Length(Buffer); if Button_GetNote(Handle,PChar(Buffer),BufferLength) then begin LTextFormatFlags := TTextFormatFlags(DT_LEFT or DT_WORDBREAK); Inc(DrawRect.Top,Canvas.TextHeight('Wq') + 2); Canvas.Font.Size := 8; StyleServices.DrawText(Canvas.Handle,Buffer,Canvas.Font.Color); end; end; if pbuttonImagelist.himl = 0 then begin if Pressed then LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyPHPressed) else if MouseInControl then LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphHot) else if Control.Enabled then LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphNormal) else LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphDisabled); DrawRect.Right := 35; DrawRect.Left := 3; DrawRect.Top := 10; DrawRect.Bottom := DrawRect.Top + 32; StyleServices.DrawElement(Canvas.Handle,DrawRect); end; end else if (GetWindowLong(Handle,GWL_STYLE) and BS_SPLITBUTTON) = BS_SPLITBUTTON then begin Dec(DrawRect.Right,15); DrawControlText(Canvas,Text,DT_VCENTER or DT_CENTER); if DropDown then begin LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); SaveIndex := SaveDC(Canvas.Handle); try IntersectClipRect(Canvas.Handle,Control.Width - 15,Control.Width,Control.Height); DrawRect := Rect(Control.Width - 30,Control.Height); StyleServices.DrawElement(Canvas.Handle,DrawRect); finally RestoreDC(Canvas.Handle,SaveIndex); end; end; with Canvas do begin Pen.Color := StyleServices.GetSystemColor(clBtnShadow); MoveTo(Control.Width - 15,3); LineTo(Control.Width - 15,Control.Height - 3); if Control.Enabled then Pen.Color := StyleServices.GetSystemColor(clBtnHighLight) else Pen.Color := Font.Color; MoveTo(Control.Width - 14,3); LineTo(Control.Width - 14,Control.Height - 3); Pen.Color := Font.Color; X := Control.Width - 8; Y := Control.Height div 2 + 1; for i := 3 downto 0 do begin MoveTo(X - I,Y - I); LineTo(X + I + 1,Y - I); end; end; end else begin //finally the text is aligned and drawn depending of the value of the ImageAlignment property case TCustomButton(Control).ImageAlignment of iaLeft,iaRight,iaCenter : DrawControlText(Canvas,DT_VCENTER or DT_CENTER); iaBottom : DrawControlText(Canvas,DT_TOP or DT_CENTER); iaTop : DrawControlText(Canvas,DT_BOTTOM or DT_CENTER); end; end; end; end; { TButtonStyleHookHelper } function TButtonStyleHookHelper.DropDown: Boolean; begin Result:=Self.FDropDown; end; function TButtonStyleHookHelper.Pressed: Boolean; begin Result:=Self.FPressed; end; initialization TStyleManager.Engine.RegisterStyleHook(TButton,TButtonStyleHookFix);