ホーム >プログラム >Delphi 6 ローテクTips

Unicode対応のTComboBox

TComboBoxの表示だけをUnicode対応に。

Unicodeに対応させるためにUnicodeをリストに持たせるTMyWStringsを活用します。

type
{TMyComboBox}
  TMyComboBox = class(TCustomComboBox)
  private
    F_slList: TMyWStrings;
    function GetText: WideString;
    procedure SetText(sWText: WideString);
  protected
    procedure SetStyle(csStyle: TComboBoxStyle); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
    procedure Clear; override;
    procedure AddItem(Item: WideString; AObject: TObject); reintroduce;
  published
    property AutoComplete default True;
    property AutoDropDown default False;
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    property Anchors;
    property BiDiMode;
    property CharCase;
    property Color;
    property Constraints;
    property Ctl3D;
    property DragCursor;
    property DragKind;
    property DragMode;
    property DropDownCount;
    property Enabled;
    property Font;
    property ImeMode;
    property ImeName;
    property ItemHeight;
    property ItemIndex default -1;
    property MaxLength;
    property ParentBiDiMode;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Sorted;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnChange;
    property OnClick;
    property OnCloseUp;
    property OnContextPopup;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnDrawItem;
    property OnDropDown;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMeasureItem;
    property OnSelect;
    property OnStartDock;
    property OnStartDrag;

    property Style;
    property Items: TMyWStrings read F_slList;
    property Text: WideString read GetText write SetText;
  end;
TCustomComboBoxから派生させます。
TComboBoxのメソッドやプロパティからUnicodeの表示に関連しそうなものをピックアップしていきます。CreateとDestroy、DrawItem、Clear、AddItem、SetStyleのメソッドにStyleとItems、Textプロパティを実装しました。
CreateとDestroy、DrawItem、Clearの四つのメソッドはoverrideします。AddItemとSetStyleはoverrideできない(SetStyleをoverrideするとスタックオーバーフローになってしまう)ので置き換えます。
reintroduce指令をつけることで警告メッセージを抑えています。
あとはStyleとItems、Textのプロパティを置き換えます。
//------------------------------------------------------------------------------
{TMyComboBox}
constructor TMyComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  F_slList := TMyWideStringList.Create(inherited Items);
end;

destructor TMyComboBox.Destroy;
begin
  F_slList.Free;
  inherited Destroy;
end;

procedure TMyComboBox.SetStyle(csStyle: TComboBoxStyle);
begin
  if (csStyle = csDropDownList) then begin
    //csDropDwonListはDrawItemイベントが起きないのでcsOwnerDrawFixedにする
    csStyle := csOwnerDrawFixed;
  end;
  inherited SetStyle(csStyle);
end;

//DrawItem
procedure TMyComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
  lrc_Rect: TRect;
begin
  if (Style in [csOwnerDrawFixed, csOwnerDrawVariable]) and (Assigned(OnDrawItem)) then begin
    OnDrawItem(Self, Index, Rect, State);
  end else begin
    with Canvas do begin
      FillRect(Rect);
      lrc_Rect := Rect;
      Inc(lrc_Rect.Left);
      DrawTextW(Handle, PWideChar(F_slList.Strings[Index]), -1, lrc_Rect, DT_VCENTER or DT_NOPREFIX or DT_SINGLELINE);
    end;
  end;
end;

//Clear
procedure TMyComboBox.Clear;
begin
  F_slList.Clear;
  ItemIndex := -1;
end;

procedure TMyComboBox.AddItem(Item: WideString; AObject: TObject);
begin
  F_slList.AddObject(Item, AObject);
end;

//Text
function TMyComboBox.GetText: WideString;
begin
  Result := F_slList.Strings[ItemIndex];
end;
procedure TMyComboBox.SetText(sWText: WideString);
begin
  F_slList.Strings[ItemIndex] := sWText;
end;

F_slListのCreateで引数にTCustomComboBoxのItemsを指定しているので、F_slListを通してWideStringからStringに変換したリストをTCustomComboBoxに実装されている(String型の)Itemsに保持させています。

StyleはcsDropDownを選んだときにcsOwnerDrawFixedに変換します。
これはDrawItemメソッドがcsOwnerDrawFixedとcsOwnerDrawVariableの時にしか呼ばれないからです。
そのため残念ながら編集ボックスつきのcsSimpleとcsDropDownを選択した時はDrawItemが呼ばれないのでUnicodeの表示には非対応になります。
どうしてもUnicodeの入力と表示のComboBoxが必要ならばCreateWindowW APIで作成するか、Unicode対応のEditとこのTMyComboBoxのStyleをcsOwnerDrawFixedにして組み合わせるかになるかと思います。
またこのコンポーネントをインストールして、設計時にフォームへドロップした場合StyleのデフォルトプロパティはcsDropDownのままなのでUnicodeの表示をするためにはcsOwnerDrawFixedかcsOwnerDrawVariableにする必要があります。

myComboBox.pas - ソースコードです。

制限

TComboBoxのリストの表示をUnicode対応にしますが、エディタでの入力は残念ながらUnicode非対応です。
TComboBoxのStyleでcsSimpleとcsDropDownを指定した場合は入力はもちろんのこと表示もUnicode非対応となります。
Unicode対応になるのはcsOwnerDrawFixedとcsOwnerDrawVariableだけです。
csDropDownListを指定した場合は自動的にcsOwnerDrawFixedに変更されます。

またプロパティのBevelEdgesやBevelInnerなんてのはいら〜ん、と思ってpublishedに書かなかったら「必要なプロパティがない」と怒られてプログラムが落ちてしまいました。
少なくともpublicにはしないとだめなようです。
だったら最初からpublicにしとくべきなんではないのかなぁ、、と思ってしまうわけですが、まぁ色々あるのでしょう。


2008-07-06: