2012-04-26 24 views
7

Un selector TDateTime es un ComboBox donde la lista desplegable se reemplaza por un calendario. Uso XE2 VCL Styles y el cambio de estilo no afecta a TDateTimePicker Color & Color de fuente. He cambiado el estilo de calendario con este question pero la solución no está bien para el ComboBox, ¿alguna idea? Ahora planeo heredar un TComboBox para usarlo con un TMonthCalendar pero sabría si alguien tuviera una mejor solución.Propiedades de estilo para TDateTimePicker

+2

¿Qué quiere decir con "la solución no está bien para el componente"? –

+1

@TOndrej En el TDateTimePicker tiene un ComboBox y cuando hace clic en él, el Calendario.Cambié el estilo del calendario pero no el combo. Mi pregunta no estaba clara: ¡la editaré! – philnext

+4

'mientras no está asignado (RRUZ) do Refresh' :-) – TLama

Respuesta

15

Con el fin de utilizar la solución de la propiedad CalColors, debe desactivar el tema de Windows en la caída de la ventana de la baja Componente TDateTimePicker, para eso debe usar el mensaje DTM_GETMONTHCAL para obtener el identificador de ventana.

Comprobar esta muestra 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

ACTUALIZA 1

Cambiar el color de fondo del "cuadro combinado" de la TDateTimePicker es una tarea limitada por el propio Windows, debido entre otros factores

  1. Este control no tiene la capacidad dibujada por el propietario ciudad,
  2. Y si se intenta utilizar la función SetBkColor no tiene efecto en este control porque el mensaje WM_CTLCOLOREDIT no está a cargo de este control.

lo tanto, una posible solución es interceptar los mensajes WM_PAINT y WM_ERASEBKGND y escribió su propio código para pintar el control. Cuando utiliza los estilos de Vcl, puede usar un gancho de estilo para manejar estos mensajes.

Comprobar el código (sólo como una prueba de concepto)

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. 

Nota: Este gancho estilo no saca los elementos enfocados (seleccionados) en el control de texto interno (cuadro combinado) de la TDateTimePicker, i deja esta tarea para ti.

enter image description here

ACTUALIZACIÓN 2

simplemente escribí un gancho estilo VCL que incluye toda la lógica para aplicar el estilo VCL adecuadamente al componente TDateTimePicker, sin utilizar el evento OnDropDown o el evento OnCreate del formulario . Puede encontrar el gancho de estilo here VCL (como parte del proyecto vcl styles utils)

Para usarlo, hay que añadir la unidad Vcl.Styles.DateTimePickers a su proyecto y registrar el gancho de esta manera.

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

No, el calendario aún está diseñado (gracias a su respuesta anterior), ¡necesito diseñar el Combo! – philnext

+1

Su última actualización es perversa. ¡Gran trabajo! –

+0

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

2

Para el propio calendario ... Con base en su otra pregunta ...

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

Necesito diseñar el combo, ¡no el calendario! – philnext

+1

Entonces, creo que necesita heredar el componente y anular el método OnPaint para hacer esto ... veamos otros comentarios futuros ... – Whiler

+0

Sí, considero heredar un TCustomComboBox con un calendario, pero pensé que alguien tenía un mejor solución. – philnext

Cuestiones relacionadas