I have DBCombobox
with CsOwnerDrawFixed
Style that connected to Tstringfield
.
sometimes database stringfield content doesn't exist in dbcombobox.Items
(because of User mistake in separate process) and dbcombobox
control show nothing. How can I show this data as text on dbcombobox
?
procedure TForm1.DBComboBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
with DBComboBox1.Canvas do
begin
if odselected in State then
Brush.Color:= $00D68759
else
Brush.Color:= $00FEECDD;
FillRect(rect);
TextOut(30, Rect.Top, DBComboBox1.Items[Index]);
Pen.Color := clwhite;
Brush.Style:= bsClear;
TextOut(Rect.Left + 4, Rect.Top, UpCase(DBComboBox1.Items[Index][1]));
Rectangle(Rect.Left + 1, Rect.Top + 1, Rect.Left +20, Rect.Top + DBComboBox1.ItemHeight-2);
end;
end;
I do this in two steps. after creating a Combobox
with this capabality, I inherited a DBCombobox
from manipulated combobox.
This is a simple Combobox test.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, DBCtrls;
type
TManipulatecombobox= class(stdctrls.TCombobox)
private
Ftext: string;
FOnDrawItem: TDrawItemEvent;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure Settext(Avalue: string);
protected
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); reintroduce; virtual;
property OnDrawItem: TDrawItemEvent read FOnDrawItem write FOnDrawItem;
public
property text: string read Ftext write Settext;
end;
TForm1 = class(TForm)
Edit1: TEdit;
DBComboBox1: TDBComboBox;
procedure FormCreate(Sender: TObject);
procedure Edit1Change(Sender: TObject);
private
Combo: TManipulatecombobox;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TManipulatecombobox.CNDrawItem(var Message: TWMDrawItem);
var
State: TOwnerDrawState;
begin
with Message.DrawItemStruct^ do
begin
State := TOwnerDrawState(LongRec(itemState).Lo);
if itemState and ODS_COMBOBOXEDIT <> 0 then
Include(State, odComboBoxEdit);
if itemState and ODS_DEFAULT <> 0 then
Include(State, odDefault);
Canvas.Handle := hDC;
Canvas.Font := Font;
Canvas.Brush := Brush;
if (Integer(itemID) >= 0) and (odSelected in State) then
begin
Canvas.Brush.Color := clHighlight;
Canvas.Font.Color := clHighlightText
end;
if Integer(itemID) >= 0 then
DrawItem(itemID, rcItem, State) else
if (Integer(itemID) = -1) and (odComboBoxEdit in State) then
DrawItem(itemID, rcItem, State)
else
Canvas.FillRect(rcItem);
if odFocused in State then DrawFocusRect(hDC, rcItem);
Canvas.Handle := 0;
end;
end;
procedure TManipulatecombobox.DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState);
begin
TControlCanvas(Canvas).UpdateTextFlags;
if Assigned(FOnDrawItem) then FOnDrawItem(Self, Index, Rect, State)
else
begin
Canvas.FillRect(Rect);
if Index = -1 then
Canvas.TextOut(Rect.Left + 2, Rect.Top, text);
if Index >= 0 then
Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
end;
end;
procedure TManipulatecombobox.Settext(Avalue: string);
begin
if Avalue <> Ftext then
begin
Ftext:= Avalue;
//I'm not sure this is a good way.
Invalidate;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
combo:= TManipulatecombobox.Create(self);
with combo do
begin
parent:= self;
SetBounds(20, 50, 120, 30);
Items.Add('item1');
items.Add('item2');
Style:= csOwnerDrawVariable;
end;
end;
procedure TForm1.Edit1Change(Sender: TObject);
begin
Combo.ItemIndex:= -1;
Combo.Settext(TEdit(sender).Text);
end;
end.
And finally, I copy all DBCombobox
class from VCL
code and change two functions.
TManipulateDBcombobox= class(TManipulatecombobox)
private
FDataLink: TFieldDataLink;
FPaintControl: TPaintControl;
procedure DataChange(Sender: TObject);
procedure EditingChange(Sender: TObject);
function GetComboText: string;
function GetDataField: string;
function GetDataSource: TDataSource;
function GetField: TField;
function GetReadOnly: Boolean;
procedure SetComboText(const Value: string);
.
.
end;
implementation
.
.
procedure TManipulateDBcombobox.SetComboText(const Value: string);
var
I: Integer;
Redraw: Boolean;
begin
if Value <> GetComboText then
begin
if Style <> csDropDown then
begin
Redraw := (Style <> csSimple) and HandleAllocated;
if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
try
if Value = '' then I := -1 else I := Items.IndexOf(Value);
ItemIndex := I;
finally
if Redraw then
begin
SendMessage(Handle, WM_SETREDRAW, 1, 0);
Invalidate;
end;
end;
if I >= 0 then Exit;
end;
// if Style in [csownerdrawfixed, csownerdrawvariable] then //?
text:= value;
end;
end;
function TManipulateDBcombobox.GetComboText: string;
begin
if Style in [csDropDown, csSimple] then Result := Text else
if ItemIndex < 0 then Result := text else Result := Items[ItemIndex];
end;