自己建立类似COMbobox控件!!!!(100分)

  • 主题发起人 主题发起人 jack9999
  • 开始时间 开始时间
J

jack9999

Unregistered / Unconfirmed
GUEST, unregistred user!
想编一个类似于COMBOBOX的控件,从Tedit继承,但不知下拉框如何弹出,需要弹出一TDBGRID!!!
各位高手,帮个忙吧!!!
 
从TCustomComboBox继承比较好吧,把DroppedDown设为FALSE,再自已作一个DBGrid套上去。
 
看看RX的控件源代码,你就会清楚下拉框如何弹出。
 
从TCustomComboBox继承比较好吧,把DroppedDown设为FALSE,再自已作一个DBGrid套上去。
不知如何进行弹出,象COMBOBOX的弹出部分可以在窗口之外,能否举例说明!!谢谢!!!
 
COMBOBOX不是Windows的基本组件吗?
 
把控件DBGrid设为WS_TOOLWINDOWS.
 
listen,dkjd
 
balaschen可以举个例子吗??谢谢!!!
 
type
TListGrid=class(TDBGrid)
private
protected
procedure Createparams(var parmas:TCreateparams);override;
public
constructor create(AOwner:TComponent);override;
end;

TMyCustomComboBox=class(TCustomEdit)
private
FListBox:TListGrid;//定义下拉Grid.
end;

.
.
.
procedure TListGrid.createparams(var parmas:TCreeateparams);
begin
override createparams(params);
with params do
begin
style=style or ws_toolwindow or ws_popupwindow;
end;
end;

当你显示下拉Grid时,用SetWindowPos来显示就可以在其他窗口之外.
由于出差,因此无法调试有些语法可能不对,其中ws_toolwindow等参数可以在Delphi的
Window32 SDK帮助里找到(Createwindows函数里有说明).
 
To balaschen
看过你的回答,做了实验,还不太明白,可以帮我写个例程吗??谢谢!!!

 
给你贴一个简单例子,单击编辑框可以显示和隐藏下拉框。
例子已编绎通过。
unit TestCombobox;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,Grids;

type
TTestCombobox = class;
TMyComboBox=class(TStringGrid)
private
FEdit:TTestCombobox;
protected
procedure CreateParams(var params:TCreateParams);override;
procedure WMSetFocus(var Msg:TWMSetFocus);message WM_SETFOCUS;
public
constructor Create(AOwner:TComponent);override;
end;
TTestCombobox = class(TCustomEdit)
private
FMyComboBox:TMyComboBox;
FDowned:Boolean;
procedure ShowCombobox;
procedure HideComboBox;
protected
procedure CMCancelMode(var Msg:TCMCancelMode);message CM_CANCELMODE;
procedure WM_LButtonDown(var Msg:TWMMouse);message WM_LBUTTONDOWN;
public
Constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
published
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('DevTools', [TTestCombobox]);
end;

{ TTestCombobox }

procedure TTestCombobox.CMCancelMode(var Msg: TCMCancelMode);
begin
inherited;
if FDowned then
begin
HideComboBox;
end;
end;

constructor TTestCombobox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMyComboBox:=TMyComboBox.Create(self);
FDowned:=false;
end;

destructor TTestCombobox.Destroy;
begin
FMyComboBox.Free;
FMyComboBox:=nil;
inherited Destroy;
end;

procedure TTestCombobox.HideComboBox;
begin
ShowWindow(FMyCombobox.handle,SW_HIDE);
FDowned:=not FDowned;
end;

procedure TTestCombobox.ShowCombobox;
var
Point:TPoint;
begin
Point.x:=Left;
Point.y:=top+Height;
Point:=Parent.ClienttoScreen(Point);
SetWindowPos(FMyComboBox.Handle,HWND_TOP,Point.x,Point.y,0,0,SWP_NOACTIVATE or SWP_HideWindow or SWP_NOSIZE); ShowWindow(FMyComboBox.Handle,SW_SHOW);
FDowned:=not FDowned;
end;

procedure TTestCombobox.WM_LButtonDown(var Msg: TWMMouse);
begin
if not FDowned then
begin
ShowComboBox;
end
else
begin
HideCombobox;
end;
end;

{ TMyComboBox }

constructor TMyComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FEdit:=TTestCombobox(AOwner);

ControlStyle:=ControlStyle + [csNoDesignVisible, csReplicatable,
csAcceptsControls];


Width:=134;
Height:=130;

ColCount:=2;
RowCount:=5;
FixedCols:=0;

ScrollBars:=ssNone;

Visible := False;
Parent:=TWinControl(AOwner);

//ScrollBars:=ssNone;
end;

procedure TMyComboBox.CreateParams(var params: TCreateParams);
begin
inherited CreateParams(params);
with Params do
begin
Style:=style or ws_popup;
EXStyle:=EXStyle or WS_EX_CLIENTEDGE or WS_EX_TOOLWINDOW;
end;
end;

procedure TMyComboBox.WMSetFocus(var Msg: TWMSetFocus);
begin
Inherited;
FEdit.SetFocus;
end;

end.
 
上回贴的有点小错误,这是修改过的。
 
To balaschen
谢谢你的例子!!!但我还有几个问题不明白,请帮忙解答!!
1、我将stringgrid改为dbgrid,请问如何连接数据库,并在edit输入时进行动态查询?
2、以下代码使strigngrid不能获得焦点,那又怎样移动条目并选择呢??
procedure TMyComboBox.WMSetFocus(var Msg: TWMSetFocus);
begin
Inherited;
FEdit.SetFocus;
end;
多谢了,请帮个忙!!!!!
 
To balaschen
非常感谢你给我的例子,我做了以下改动:
1定义了三个GridNumber,GridChinese,GridEnglish三个属性用作对不同输入方式的查询选择,属性值为数据库的字段名
2定义了GridWidth为下拉数据表的宽度
3定义了DataSource为数据源
但还有一些问题请教!
1下拉DBGrid不能用鼠标或键盘选择?
2如果想过滤数据应该怎么做?即每次按键后重新查询而不用Locate!!
以下是我改后的程序!!!请帮忙解答,分数不够可以再加!!!

unit JackCombobox;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,Grids,DBGrids,DB,DBCtrls;

type
TJackCombobox = class;

TMyComboBox=class(TDBGrid)
private
FEdit:TJackCombobox;
protected
procedure CreateParams(var params:TCreateParams);override;
procedure WMSetFocus(var Msg:TWMSetFocus);message WM_SETFOCUS;
public
constructor Create(AOwner:TComponent);override;
end;

TJackCombobox = class(TEdit)
private
FDataLink: TFieldDataLink;
FMyComboBox:TMyComboBox;
FDowned:Boolean;
FFocused:Boolean;
FGridWidth:integer;
FDataSource:TDataSource;
FGridQuery:TDataSet;
FGridNumber:string;
FGridChinese:string;
FGridEnglish:string;
procedure ShowCombobox;
procedure HideComboBox;
function GetDataSource: TDataSource;
procedure SetDataSource(Value: TDataSource);
protected
procedure WMSIZE(var Msg:TWMSize);message WM_SIZE;
procedure CMCancelMode(var Msg:TCMCancelMode);message CM_CANCELMODE;
public
Constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
procedure Change;override;
procedure DoEnter;override;
procedure DoExit;override;
published
property GridWidth:integer read FGridWidth write FGridWidth default 120;
property DataSource:TDataSource read GetDataSource write SetDataSource;
property GridNumber:string read FGridNumber write FGridNumber;
property GridChinese:string read FGridChinese write FGridChinese;
property GridEnglish:string read FGridEnglish write FGridEnglish;
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('JackTools', [TJackCombobox]);
end;

{ TJackCombobox }

procedure TJackCombobox.CMCancelMode(var Msg: TCMCancelMode);
begin
inherited;
if FDowned then
begin
HideComboBox;
end;
end;

constructor TJackCombobox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDataLink := TFieldDataLink.Create;
FDataLink.Control := Self;
FGridWidth:=Width;
FMyComboBox:=TMyComboBox.Create(self);
FDowned:=False;
FFocused:=False;
end;

destructor TJackCombobox.Destroy;
begin
FMyComboBox.Free;
FMyComboBox:=nil;
inherited Destroy;
end;

procedure TJackCombobox.HideComboBox;
begin
SetWindowPos(FMyComboBox.Handle,HWND_TOP,0,0,0,0,SWP_NOACTIVATE + SWP_HideWindow + SWP_NOSIZE +SWP_NOZORDER);
FDowned:=not FDowned;
end;

procedure TJackCombobox.ShowCombobox;
var
Point:TPoint;
begin
Point.x:=Left;
Point.y:=top+Height;
Point:=Parent.ClienttoScreen(Point);
FMyCombobox.Width:=GridWidth;
SetWindowPos(FMyComboBox.Handle,HWND_TOP,Point.x,Point.y,0,0,SWP_NOACTIVATE + SWP_HideWindow + SWP_NOSIZE +SWP_NOZORDER);
SetWindowPos(FMyComboBox.Handle,HWND_TOP,Point.x,Point.y,0,0,SWP_NOACTIVATE + SWP_ShowWindow + SWP_NOSIZE +SWP_NOZORDER +SWP_NOMOVE);
FDowned:=not FDowned;
end;

function TJackCombobox.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;

procedure TJackCombobox.SetDataSource(Value: TDataSource);
begin
if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
FMyCombobox.DataSource:=FDataLink.DataSource;
end;

procedure TJackCombobox.WMSIZE(var Msg:TWMSize);
begin
FMyCombobox.Width:=GridWidth;
end;

procedure TJackCombobox.Change;
var FindName:string;
begin
if not(csDesigning in ComponentState) and FFocused then
begin
fgridquery:=FDataLink.DataSource.DataSet;
if Text<>'' then
begin
if Text[1] in ['0'..'9'] then
FindName:=FGridNumber
else if (Text[1] in ['A'..'Z']) or (Text[1] in ['a'..'z']) then
FindName:=FGridEnglish
else
FindName:=FGridChinese;
end;
fGridQuery.Locate(FindName,Text,[loPartialKey]);
if not FDowned then
ShowComboBox;
end;
inherited;
end;

procedure TJackCombobox.DoEnter;
begin
FFocused:=True;
inherited;
end;

procedure TJackCombobox.DoExit;
begin
FFocused:=False;
if FDowned then
HideComboBox;
inherited;
end;

{ TMyComboBox }

constructor TMyComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FEdit:=TJackCombobox(AOwner);

ControlStyle:=ControlStyle + [csNoDesignVisible, csReplicatable,csAcceptsControls];

Width:=FEdit.GridWidth;
Height:=130;
Options:=[dgColumnResize,dgColLines,dgRowLines,dgTabs,dgRowSelect,dgAlwaysShowSelection,dgConfirmDelete,dgCancelOnExit];

DataSource:=FEdit.FDataSource;
ReadOnly:=True;
ScrollBars:=ssVertical;

Visible := False;
Parent:=TWinControl(AOwner);

end;

procedure TMyComboBox.CreateParams(var params: TCreateParams);
begin
inherited CreateParams(params);
with Params do
begin
Style:=style or ws_popup;
EXStyle:=EXStyle or WS_EX_CLIENTEDGE or WS_EX_TOOLWINDOW;
end;
end;

procedure TMyComboBox.WMSetFocus(var Msg: TWMSetFocus);
begin
Inherited;
FEdit.SetFocus;
end;

end.


 
>>1下拉DBGrid不能用鼠标或键盘选择?
对于键盘选择:由于下拉Grid不能接受焦点,应而不能接受键盘消息,可以如下处理:
在TTestCombobox中增加一个按键消息WM_KEYDOWN.
TTestCombobox = class(TCustomEdit)
private
....
procedure WM_KeyDown(var Msg:TWMKey);message WM_KEYDOWN;
...

--------------------------------------------------------------
procedure TTestCombobox.WM_KeyDown(var Msg: TWMKey);
begin
case Msg.CharCode of
VK_UP,VK_Down,VK_Return://你想发送给下拉Grid的按键;
begin
if FMyComboBox.Visible then
begin
SendMessage(FMyCombobox.Handle,Msg.Msg,Msg.CharCode,Msg.KeyData);
end
else
Inherited;
end;
else
Inherited;
end;
end;
对于鼠标选择:下拉Grid可以接收鼠标消息的。
用鼠标或键盘选择下拉DBGrid只要在TJackCombobox中增加响应的消息函数进行处理就可
以了,代码我就不贴了。

>>2如果想过滤数据应该怎么做?即每次按键后重新查询而不用Locate!!
这个问题我再想想,不过最近在赶项目比较忙 :)

 
to jack9999:
你“每次按键后重新查询而不用Locate!!”是什么意思?能解释一下吗?
 
to balaschen:
我的意思是把不符合输入字符的纪录过滤掉!!!现在只是实现在相似的记录处定位!!
 
如过你的意思是动态检索的话可以如下:
注:(1)没有经过测试,只是一种思路,你自己测试。
(2)你的问题是“但不知下拉框如何弹出,需要弹出一TDBGRID”固本次解答超出
问题范围,如果解决问题得再给我加分:)
在TTestCombobox覆载其父类的Change过程:
TTestCombobox = class(TCustomEdit)
private
....
protected
procedure Change;override;
...

-----------------------
procedure TTestComboBox.Change;
begin
if FMyComboBox.Visible then
begin
try
//假设DataSource的数据源为TTable,你可以进行“is”判断是Table还是Query
with DataSource.DataSet as Table do
begin
Filetered:=true;
Fileter:=FMyComboBox.Columns[0].FieldName+' like ''%'+Text+'''';
{你可以根据DataSet和DBGrid的一些重要属性进行设置}
end;
except
//这里进行异常处理
end;
end;
end;


 
请有兴趣的网友到<a href="http://www.delphibbs.com/delphibbs/DispQ.asp?LID=475176">小调查:你认为StringGrid应该具有那些特性?</a> 看看
 
to balaschen:
分数只是小问题,可以在加200分,不够再加!!!我正在试验,成功后给你答复!!!!
 
后退
顶部