2012-04-26 22 views
7

Selektor TDateTime to ComboBox, w którym lista rozwijana zastępowana jest kalendarzem. Używam stylów XCL VCL i zmiana stylu nie wpływa na kolor czcionki TDateTimePicker & Kolor czcionki. Zmieniłem styl kalendarza za pomocą tego question, ale rozwiązanie nie jest w porządku dla żadnego pomysłu na ComboBox? Teraz mam zamiar odziedziczyć TComboBox do użytku z TMonthCalendar ale wiem, czy ktokolwiek miał lepsze rozwiązanie.Właściwości stylu dla TDateTimePicker

+2

Co rozumiesz przez "rozwiązanie nie jest poprawne dla komponentu"? –

+1

@TOndrej W TDateTimePicker masz ComboBox i po kliknięciu na nim Kalendarz.Zmieniłem styl kalendarza, ale nie kombi. Moje pytanie nie było jasne: będę je edytować! – philnext

+4

'while not Assigned (RRUZ) do Refresh' :-) – TLama

Odpowiedz

15

w celu wykorzystania obejścia nieruchomości CalColors, należy wyłączyć motyw Windows w rozwijanym oknie Komponent TDateTimePicker, do którego należy użyć komunikatu DTM_GETMONTHCAL, aby uzyskać uchwyt okna.

Sprawdź to próbka App

unit Unit15; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ImgList, Vcl.StdCtrls, Vcl.ComCtrls; 

type 
    TForm15 = class(TForm) 
    DateTimePicker1: TDateTimePicker; 
    procedure DateTimePicker1DropDown(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form15: TForm15; 

implementation 


{$R *.dfm} 

uses 
    Winapi.CommCtrl, 
    Vcl.Styles, 
    Vcl.Themes, 
    uxTheme; 

Procedure SetVclStylesColorsCalendar(DateTimePicker: TDateTimePicker); 
Var 
    LTextColor, LBackColor : TColor; 
begin 
    uxTheme.SetWindowTheme(DateTimePicker.Handle, '', '');//disable themes in the calendar 
    //get the vcl styles colors 
    LTextColor:=StyleServices.GetSystemColor(clWindowText); 
    LBackColor:=StyleServices.GetSystemColor(clWindow); 

    DateTimePicker.Color:=LBackColor; 
    //set the colors of the calendar 
    DateTimePicker.CalColors.BackColor:=LBackColor; 
    DateTimePicker.CalColors.MonthBackColor:=LBackColor; 
    DateTimePicker.CalColors.TextColor:=LTextColor; 
    DateTimePicker.CalColors.TitleBackColor:=LBackColor; 
    DateTimePicker.CalColors.TitleTextColor:=LTextColor; 
    DateTimePicker.CalColors.TrailingTextColor:=LTextColor; 
end; 


procedure TForm15.DateTimePicker1DropDown(Sender: TObject); 
var 
    hwnd: WinAPi.Windows.HWND; 
begin 
    hwnd := SendMessage(TDateTimePicker(Sender).Handle, DTM_GETMONTHCAL, 0,0); 
    uxTheme.SetWindowTheme(hwnd, '', '');//disable themes in the drop down window 
end; 

procedure TForm15.FormCreate(Sender: TObject); 
begin 
    SetVclStylesColorsCalendar(DateTimePicker1); 
end; 

end. 

enter image description here

UPDATE 1

Zmiana koloru tła "combobox" z TDateTimePicker jest zadaniem ograniczone przez Windows, ponieważ między innymi czynnikami

  1. Ta kontrola nie ma wyciągniętego właściciela miasto,
  2. A jeśli spróbujesz użyć funkcji SetBkColor, nie ma to wpływu na tę opcję, ponieważ komunikat WM_CTLCOLOREDIT nie jest obsługiwany przez tę kontrolkę.

Możliwe jest więc przechwycenie wiadomości WM_PAINT i WM_ERASEBKGND i napisanie własnego kodu, aby pomalować formant. Gdy używasz stylów Vcl, możesz użyć haka Style do obsługi tych wiadomości.

Sprawdź ten kod (tylko jako proof of concept)

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ImgList, Vcl.StdCtrls, Vcl.ComCtrls; 

type 
    TForm15 = class(TForm) 
    DateTimePicker1: TDateTimePicker; 
    DateTimePicker2: TDateTimePicker; 
    procedure DateTimePicker1DropDown(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    end; 


var 
    Form15: TForm15; 

implementation 


{$R *.dfm} 

uses 
    Winapi.CommCtrl, 
    Vcl.Styles, 
    Vcl.Themes, 
    Winapi.uxTheme; 

type 
TDateTimePickerStyleHookFix= class(TDateTimePickerStyleHook) 
private 
    procedure WMPaint(var Message: TMessage); message WM_PAINT; 
    procedure PaintBackground(Canvas: TCanvas); override; 
public 
    constructor Create(AControl: TWinControl); override; 
end; 

TDateTimePickerStyleHookHelper = class helper for TDateTimePickerStyleHook 
public 
    function GetButtonRect_: TRect; 
end; 


Procedure SetVclStylesColorsCalendar(DateTimePicker: TDateTimePicker); 
Var 
    LTextColor, LBackColor : TColor; 
begin 
    Winapi.uxTheme.SetWindowTheme(DateTimePicker.Handle, '', '');//disable themes in the calendar 
    //get the vcl styles colors 
    LTextColor:=StyleServices.GetSystemColor(clWindowText); 
    LBackColor:=StyleServices.GetSystemColor(clWindow); 

    DateTimePicker.Color:=LBackColor; 
    //set the colors of the calendar 
    DateTimePicker.CalColors.BackColor:=LBackColor; 
    DateTimePicker.CalColors.MonthBackColor:=LBackColor; 
    DateTimePicker.CalColors.TextColor:=LTextColor; 
    DateTimePicker.CalColors.TitleBackColor:=LBackColor; 
    DateTimePicker.CalColors.TitleTextColor:=LTextColor; 
    DateTimePicker.CalColors.TrailingTextColor:=LTextColor; 
end; 


procedure TForm15.DateTimePicker1DropDown(Sender: TObject); 
var 
    hwnd: WinAPi.Windows.HWND; 
begin 
    hwnd := SendMessage(TDateTimePicker(Sender).Handle, DTM_GETMONTHCAL, 0,0); 
    Winapi.uxTheme.SetWindowTheme(hwnd, '', '');//disable themes in the drop down window 
end; 

procedure TForm15.FormCreate(Sender: TObject); 
begin 
    //set the colors for the TDateTimePicker 
    SetVclStylesColorsCalendar(DateTimePicker1); 
    SetVclStylesColorsCalendar(DateTimePicker2); 
end; 


{ TDateTimePickerStyleHookHelper } 
function TDateTimePickerStyleHookHelper.GetButtonRect_: TRect; 
begin 
Result:=Self.GetButtonRect; 
end; 

{ TDateTimePickerStyleHookFix } 
constructor TDateTimePickerStyleHookFix.Create(AControl: TWinControl); 
begin 
    inherited; 
    OverrideEraseBkgnd:=True;//this indicates which this style hook will call the PaintBackground method when the WM_ERASEBKGND message is sent. 
end; 

procedure TDateTimePickerStyleHookFix.PaintBackground(Canvas: TCanvas); 
begin 
    //use the proper style color to paint the background 
    Canvas.Brush.Color := StyleServices.GetStyleColor(scEdit); 
    Canvas.FillRect(Control.ClientRect); 
end; 

procedure TDateTimePickerStyleHookFix.WMPaint(var Message: TMessage); 
var 
    DC: HDC; 
    LCanvas: TCanvas; 
    LPaintStruct: TPaintStruct; 
    LRect: TRect; 
    LDetails: TThemedElementDetails; 
    sDateTime : string; 
begin 
    DC := Message.WParam; 
    LCanvas := TCanvas.Create; 
    try 
    if DC <> 0 then 
     LCanvas.Handle := DC 
    else 
     LCanvas.Handle := BeginPaint(Control.Handle, LPaintStruct); 
    if TStyleManager.SystemStyle.Enabled then 
    begin 
     PaintNC(LCanvas); 
     Paint(LCanvas); 
    end; 
    if DateMode = dmUpDown then 
     LRect := Rect(2, 2, Control.Width - 2, Control.Height - 2) 
    else 
     LRect := Rect(2, 2, GetButtonRect_.Left, Control.Height - 2); 
    if ShowCheckBox then LRect.Left := LRect.Height + 2; 
    IntersectClipRect(LCanvas.Handle, LRect.Left, LRect.Top, LRect.Right, LRect.Bottom); 
    Message.wParam := WPARAM(LCanvas.Handle); 

    //only works for DateFormat = dfShort 
    case TDateTimePicker(Control).Kind of 
    dtkDate : sDateTime:=DateToStr(TDateTimePicker(Control).DateTime); 
    dtkTime : sDateTime:=TimeToStr(TDateTimePicker(Control).DateTime); 
    end; 

    //draw the current date/time value 
    LDetails := StyleServices.GetElementDetails(teEditTextNormal); 
    DrawControlText(LCanvas, LDetails, sDateTime, LRect, DT_VCENTER or DT_LEFT); 

    if not TStyleManager.SystemStyle.Enabled then 
     Paint(LCanvas); 
    Message.WParam := DC; 
    if DC = 0 then 
     EndPaint(Control.Handle, LPaintStruct); 
    finally 
    LCanvas.Handle := 0; 
    LCanvas.Free; 
    end; 
    Handled := True; 
end; 


initialization 
    TStyleManager.Engine.RegisterStyleHook(TDateTimePicker, TDateTimePickerStyleHookFix); 

end. 

Uwaga: Ten hak styl nie wyciągnąć skupiony (wybrane) elementy kontroli wewnętrznej tekstu (combobox) w TDateTimePicker, i niech to zadanie dla ciebie.

enter image description here

UPDATE 2

Właśnie napisał hak styl VCL, który obejmuje całą logikę zastosować styl VCL odpowiednio do komponentu TDateTimePicker, bez korzystania z OnDropDown zdarzenie lub onCreate zdarzenie formularza . Można znaleźć haka here stylu VCL (jako część projektu vcl styles utils)

Aby z niego skorzystać należy dodać jednostkę Vcl.Styles.DateTimePickers do projektu i zarejestrować hak w ten sposób.

TStyleManager.Engine.RegisterStyleHook(TDateTimePicker, TDateTimePickerStyleHookFix); 
+1

Nie, kalendarz jest jeszcze stylizowany (dzięki twojej poprzedniej odpowiedzi), muszę stylizować Combo !! – philnext

+1

Twoja ostatnia aktualizacja jest niegodziwa. Dobra robota! –

+0

Gracias @LeonardoHerrera, es grato ver a otro desarrollador chileno por aca. – RRUZ

2

dla samego kalendarza ... w oparciu o inne pytanie ...

procedure SetVclStylesMonthCalColors(calColors: TMonthCalColors); 
var 
    LTextColor, LBackColor : TColor; 
begin 
    //get the vcl styles colors 
    LTextColor:=StyleServices.GetSystemColor(clWindowText); 
    LBackColor:=StyleServices.GetSystemColor(clWindow); 

    //set the colors of the calendar 
    calColors.BackColor:=LBackColor; 
    calColors.MonthBackColor:=LBackColor; 
    calColors.TextColor:=LTextColor; 
    calColors.TitleBackColor:=LBackColor; 
    calColors.TitleTextColor:=LTextColor; 
    calColors.TrailingTextColor:=LTextColor; 
end; 

Procedure SetVclStylesColorsCalendar(MonthCalendar: TMonthCalendar); 
Var 
    LTextColor, LBackColor : TColor; 
begin 
    uxTheme.SetWindowTheme(MonthCalendar.Handle, '', '');//disable themes in the calendar 
    MonthCalendar.AutoSize:=True;//remove border 

    SetVclStylesMonthCalColors(MonthCalendar.CalColors); 
end; 


procedure TForm1.dtp1DropDown(Sender: TObject); 
var 
    rec: TRect; 
begin 
    uxTheme.SetWindowTheme(DateTime_GetMonthCal(dtp1.Handle), '', ''); 
    MonthCal_GetMinReqRect(DateTime_GetMonthCal(dtp1.Handle), rec); 
    SetWindowPos(GetParent(DateTime_GetMonthCal(dtp1.Handle)), 0, rec.Left, rec.Top, rec.Width, rec.Height,0); 
    SetWindowPos(DateTime_GetMonthCal(dtp1.Handle), 0, rec.Left, rec.Top, rec.Width, rec.Height,0); 
    SetVclStylesMonthCalColors(dtp1.CalColors); 
end; 
+0

Potrzebuję stylu combo, a nie kalendarza! – philnext

+1

Myślę więc, że musisz dziedziczyć komponent i zastąpić metodę OnPaint, aby to zrobić ... zobaczmy inne przyszłe komentarze ... – Whiler

+0

Tak, uważam, że dziedziczyłem TCustomComboBox z kalendarzem, ale myślałem, że ktoś ma lepsze rozwiązanie. – philnext

Powiązane problemy