2

I have problems when I use ComboBox in Delphi XE2 with Custom styles(Emerald Light Slate) and this property:

BiDiMode := bdRightToLeft;
Style := csDropDownList;

That ComboBox without Custom style:

enter image description here

And with Custom styles(Emerald Light Slate):

enter image description here

How i can fix it?

Pejman Nikram
  • 570
  • 2
  • 11
  • 26

2 Answers2

5

The issue it seems located in the DrawItem method of the TComboBoxStyleHook (the vcl style hook of the TComboBox), you can fix this overriding this method.

Try this sample code (this solution is far from being perfect but is a start)

type
  TComboBoxStyleHookFix = class(TComboBoxStyleHook)
  protected
    procedure DrawItem(Canvas: TCanvas; Index: Integer;
      const R: TRect; Selected: Boolean); override;
  end;

{ TComboBoxStyleHookFix }

procedure TComboBoxStyleHookFix.DrawItem(Canvas: TCanvas; Index: Integer;
  const R: TRect; Selected: Boolean);
var
  DIS  : TDrawItemStruct;
  Text : string;
begin
  if Control.BiDiMode<>bdRightToLeft then
   inherited
  else
  begin
    FillChar(DIS, SizeOf(DIS), 0);
    DIS.CtlType := ODT_COMBOBOX;
    DIS.CtlID := GetDlgCtrlID(Handle);
    DIS.itemAction := ODA_DRAWENTIRE;
    DIS.hDC := Canvas.Handle;
    DIS.hwndItem := Handle;
    DIS.rcItem := R;
    Text:=TComboBox(Control).Items[Index];    
    DIS.rcItem.Left:=DIS.rcItem.Left+ (DIS.rcItem.Width-Canvas.TextWidth(Text)-5);    
    DIS.itemID := Index;
    DIS.itemData := SendMessage(ListHandle, LB_GETITEMDATA, 0, 0);
    if Selected then
      DIS.itemState := DIS.itemState {or ODS_FOCUS} or ODS_SELECTED;
    SendMessage(Handle, WM_DRAWITEM, Handle, LPARAM(@DIS));
  end;
end;

and use in this way

 TStyleManager.Engine.RegisterStyleHook(TComboBox, TComboBoxStyleHookFix);

enter image description here

Don't forget report this bug in the QC page of Embarcadero.

RRUZ
  • 134,889
  • 20
  • 356
  • 483
0

I fixed the above code and its problems were fixed(RTL alignment & focus color) and it was tested and there is no problem. Thanks from @RRUZ:

unit ComboBoxStyleHookFix;

interface

uses
  Vcl.Forms,
  Vcl.StdCtrls,
  Vcl.Graphics,
  Winapi.Windows,
  System.Classes,
  Winapi.Messages;

type
  TComboBoxStyleHookFix = class(TComboBoxStyleHook)
  protected
    procedure DrawItem(Canvas: TCanvas; Index: Integer; const R: TRect; Selected: Boolean); override;
  end;

implementation

procedure TComboBoxStyleHookFix.DrawItem(Canvas: TCanvas; Index: Integer; const R: TRect; Selected: Boolean);
var
  DIS: TDrawItemStruct;
  Text: string;
  R1: TRect;
begin
  if Control.BiDiMode <> bdRightToLeft then
    inherited
  else
  begin
    FillChar(DIS, SizeOf(DIS), 0);
    DIS.CtlType := ODT_COMBOBOX;
    DIS.CtlID := GetDlgCtrlID(Handle);
    DIS.itemAction := ODA_DRAWENTIRE;
    DIS.hDC := Canvas.Handle;
    DIS.hwndItem := Handle;
    DIS.rcItem := R;
    Text := TComboBox(Control).Items[Index];
    DIS.rcItem.Left := DIS.rcItem.Right + 11;
    DIS.itemID := Index;
    DIS.itemData := SendMessage(ListHandle, LB_GETITEMDATA, 0, 0);
    Canvas.Font.Name := Application.DefaultFont.Name;
    Canvas.Font.Size := Application.DefaultFont.Size;
    if Selected then
    begin
      Canvas.Font.Color := clWhite;
      DIS.itemState := DIS.itemState { or ODS_FOCUS } or ODS_SELECTED;
      Canvas.Brush.Color := $00D77800;
    end;
    Canvas.FillRect(R);
    R1 := R;
    DrawText(Canvas.Handle, PChar(Text), -1, R1, DT_SINGLELINE or DT_RTLREADING or DT_RIGHT);
    // Canvas.TextRect(R, TComboBox(Control).Width - Canvas.TextWidth(Text) - 5, R.Top + 1, TextM(Text));
    // Canvas.TextOut(TComboBox(Control).Width - Canvas.TextWidth(Text) - 5, R.Top + 1, Text);
    SendMessage(Handle, WM_DRAWITEM, Handle, LPARAM(@DIS));
  end;
end;

end.

Project1.dpr:

program Project1;

uses
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls,
  System.Types,
  Vcl.Graphics,
  System.SysUtils,
  Winapi.Windows,
  System.Classes,
  Vcl.Controls,
  Winapi.Messages,
  Vcl.Themes,
  ComboBoxStyleHookFix in 'ComboBoxStyleHookFix.pas',
  Unit1 in 'Unit1.pas' {Form1} ,
  Vcl.Styles;

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.DefaultFont.Name := 'Arial';
  Application.DefaultFont.Size := 10;
  TStyleManager.TrySetStyle('Windows10');
  TStyleManager.Engine.RegisterStyleHook(TComboBox, TComboBoxStyleHookFix);
  Application.CreateForm(TForm1, Form1);
  Application.Run;

end.