2012-04-26 6 views
7

Eine TDateTime-Auswahl ist eine ComboBox, in der die Dropdownliste durch einen Kalender ersetzt wird. Ich verwende XE2 VCL Styles und die Änderung des Styles hat keinen Einfluss auf TDateTimePicker Color & Schriftfarbe. Ich habe den Kalender-Stil mit dieser question ändern, aber die Lösung ist nicht OK für die ComboBox, keine Idee? Jetzt plane ich, eine TComboBox für die Verwendung mit einem TMonthCalendar zu erben, aber ich würde wissen, ob jemand eine bessere Lösung hätte.Stileigenschaften für TDateTimePicker

+2

Was meinen Sie mit "die Lösung ist nicht OK für die Komponente"? –

+1

@TOndrej Im TDateTimePicker hast du eine ComboBox und wenn du darauf klickst den Kalender.Ich habe den Kalenderstil geändert, aber nicht den Kombo-Stil. Meine Frage war nicht klar: Ich werde es bearbeiten! – philnext

+4

'während nicht zugewiesen (RRUZ) aktualisieren ':-) – TLama

Antwort

15

Um die Umgehung der CalColors Eigenschaft zu verwenden, können Sie die Windows-Theme in der Drop-Down-Fenster des deaktivieren muss TDateTimePicker-Komponente, für die Sie die DTM_GETMONTHCAL Nachricht verwenden müssen, um das Fensterhandle zu erhalten.

prüfen diese Probe 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

Ändern Sie die Hintergrundfarbe des "Combobox" des TDateTimePicker ist eine Aufgabe, die Fenster selbst begrenzt, weil zwischen anderen Faktoren

  1. Dieses Steuerelement verfügt nicht über die vom Eigentümer gezeichnete Kapazität Stadt,
  2. Und wenn Sie versuchen, mit der SetBkColor Funktion hat keinen Effekt in diesem Steuerelement, weil die WM_CTLCOLOREDIT Nachricht wird nicht von diesem Steuerelement behandelt.

So eine mögliche Lösung ist abfangen der WM_PAINT und WM_ERASEBKGND Nachrichten und schrieb Ihren eigenen Code, um die Kontrolle zu malen. Wenn Sie die Vcl-Stile verwenden, können Sie einen Style-Hook verwenden, um diese Nachrichten zu verarbeiten.

Überprüfen Sie diesen Code (nur als 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. 

Hinweis: Diese Art Haken, nicht die fokussiert (ausgewählt) Elemente im Inneren Textsteuerung (Combobox) des TDateTimePicker zeichnen i Lass diese Aufgabe für dich.

enter image description here

UPDATE 2

Ich schrieb einen vcl Stil Haken, der die gesamte Logik beinhaltet die vcl Stil richtig an die TDateTimePicker Komponente anzuwenden, ohne das Ereignis OnDropDown zu verwenden oder das OnCreate-Ereignis des Formulars . Sie können die vcl Stil Haken here (als Teil des vcl styles utils Projekt) finden

es nutzen zu können, müssen Sie die Vcl.Styles.DateTimePickers Einheit zu Ihrem Projekt hinzufügen und den Haken auf diese Weise registrieren.

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

Nein, der Kalender ist noch gestylt (dank Ihrer vorherigen Antwort), ich muss die Combo stylen !! – philnext

+1

Ihr letztes Update ist böse. Gut gemacht! –

+0

Gracias @LeonardoHerrera, es ist eine sehr gute Lösung für die Chilenische Küche. – RRUZ

2

Für den Kalender selbst ... auf der Grundlage Ihrer anderen Frage ...

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

Ich muss die Combo stylen, nicht den Kalender! – philnext

+1

Also, ich denke, Sie müssen die Komponente erben und die OnPaint-Methode überschreiben, um dies zu tun ... Lassen Sie uns andere zukünftige Kommentare sehen ... – Whiler

+0

Ja, ich denke, eine TCustomComboBox mit einem Kalender zu erben, aber ich dachte, jemand hatte eine bessere Lösung. – philnext

Verwandte Themen