2012-03-06 10 views
13

जब मैं कोड की follwing लाइन का उपयोग करने से एक स्टाइल VCL पर एक बटन को निष्क्रिय करने की कोशिशअक्षम TButton मुद्दा

TButton(Sender).enabled:= False; 

मैं इस परिणाम (बटन कार्यावधि में अक्षम)

मिल

enter image description here

इसके बजाए !! (डिजाइन समय में बटन अक्षम)

enter image description here

यह वास्तव में एक दूसरे के बगल में एक ही रंग के साथ दो या अधिक बटन के लिए भ्रमित कर रहा है, एक अक्षम किया गया है और अन्य सक्षम किया गया है

+0

क्या यह है कि यह विशेष शैली कैसे प्रदर्शित होती है, या आपको लगता है कि एक बग है? अगर पहली छवि अक्षम बटन है, तो दूसरी छवि क्या है? –

+2

@DavidHeffernan पहली छवि कोड द्वारा अक्षम है, दूसरा ऑब्जेक्ट इंस्पेक्टर (डिज़ाइन समय) से अक्षम है, मुझे लगता है कि यह एक बग है! – Raul

+0

रन-टाइम पर बटन अक्षम करने के बाद 'repaint' के बारे में क्या? – teran

उत्तर

16

इस समस्या का कारण TButtonStyleHook (Vcl.StdCtrls इकाई में) स्टाइल हुक क्लास की पेंट विधि में स्थित है।

विधि

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 के लिए शैली हुक पुनर्लेखन है के लिए बदल देते हैं:

चेक इस कोड को इस में आधारित लेख Fixing a VCL Style bug in the TButton component। Ths कोड का लाभ यह है कि आप दो मुद्दों को ठीक कर रहे हैं 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, 0, Canvas.Handle, DrawRect.Left + 3, IY, ILD_NORMAL); 
        Inc(DrawRect.Left, IW + 3); 
        end; 
     iaRight : 
        begin 
        ImageList_Draw(pbuttonImagelist.himl, 0, Canvas.Handle, DrawRect.Right - IW -3, IY, ILD_NORMAL); 
        Dec(DrawRect.Right, IW - 3); 
        end; 

     iaCenter: 
        begin 
        ImageList_Draw(pbuttonImagelist.himl, 0, Canvas.Handle, (DrawRect.Right - IW) div 2, IY, ILD_NORMAL); 
        end; 


     iaTop : 
        begin 
        ImageList_Draw(pbuttonImagelist.himl, 0, Canvas.Handle, (DrawRect.Right - IW) div 2, 3, ILD_NORMAL); 
        end; 


     iaBottom: 
        begin 
        ImageList_Draw(pbuttonImagelist.himl, 0, Canvas.Handle, (DrawRect.Right - IW) div 2, (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, LDetails, 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, LDetails, Buffer, DrawRect, 
      LTextFormatFlags, 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, LDetails, DrawRect); 
     end; 

    end 
    else 
    if (GetWindowLong(Handle, GWL_STYLE) and BS_SPLITBUTTON) = BS_SPLITBUTTON then 
    begin 
     Dec(DrawRect.Right, 15); 
     DrawControlText(Canvas, LDetails, Text, DrawRect, DT_VCENTER or DT_CENTER); 
     if DropDown then 
     begin 
     LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); 
     SaveIndex := SaveDC(Canvas.Handle); 
     try 
      IntersectClipRect(Canvas.Handle, Control.Width - 15, 0, 
      Control.Width, Control.Height); 
      DrawRect := Rect(Control.Width - 30, 0, Control.Width, Control.Height); 
      StyleServices.DrawElement(Canvas.Handle, LDetails, 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, LDetails, BCaption, DrawRect, DT_VCENTER or DT_CENTER); 
     iaBottom : DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_TOP or DT_CENTER); 
     iaTop : DrawControlText(Canvas, LDetails, BCaption, DrawRect, 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); 
+1

+1 अच्छी तरह से किया गया। मुझे पता था कि हमारे निवासी वीसीएल शैलियों गुरु इस में फंस जाएंगे। मैं विश्वास नहीं कर सकता कि वीसीएल कोड कितना खराब है। –

+0

एक फिक्स लिखते समय यह नियंत्रण को संभालने के लिए बस इतना क्लीनर है। पहले सक्षम स्थिति। इसका मतलब है कि आपको केवल उस संपत्ति का परीक्षण करना होगा। –

+2

"+1" से अधिक की आवश्यकता है Embarcadero आपको अतिरिक्त प्रयासों के लिए दोनों का भुगतान करना चाहिए :) – Raul

11

यह स्पष्ट रूप से में एक बग है वीसीएल समस्या यह प्रतीत होती है कि Enabled उस बटन से जुड़े ईवेंट हैंडलर से बटन की प्रॉपर्टी को संशोधित करने से बटन की दृश्य उपस्थिति नहीं बदली जाती है। बटन का व्यवहार बदल दिया गया है (यदि आप EnabledFalse इस तरह से सेट करते हैं तो आप इसे क्लिक नहीं कर सकते हैं), लेकिन दृश्य इसे इंगित नहीं करते हैं।

मैंने QC#103962 सबमिट किया और इसमें कोई संदेह नहीं है कि भविष्य का अद्यतन समस्या को ठीक करेगा। इस बीच में मैं निम्नलिखित तरीके को प्रदान करते हैं:

procedure TMyForm.Button1Click(Sender: TObject); 
begin 
    Button1.Enabled := False; 
    Button1.Perform(CM_RECREATEWND, 0, 0); 
end; 

यह बटन की खिड़की संभाल के लिए बाध्य करेगा फिर से बनाना है और इस दृश्यों अनुसार क्रमबद्ध करने के लिए पर्याप्त हो रहा है। इसके आसपास काम करने के शायद वैकल्पिक तरीके हैं लेकिन यह सब मुझे अब तक मिला है।

+0

ग्रेट !! बहुत बहुत शुक्रिया डेव, आपका जवाब QC प्रस्तुत करने के लिए मेरी समस्या हल हो गया है अब तक – Raul

+0

+1 - की रोलिंग keep'em, दोस्तों करते हैं! –

+0

धन्यवाद, मैं बस इस बग में भाग गया और जल्दी से इस कामकाज के साथ आगे बढ़ सकता है। क्यूसी के लिए भी वोट दिया। –

संबंधित मुद्दे