我做了一个类似combobox控件,但是有几个问题,请大家帮忙改一改 (100分)

  • 主题发起人 主题发起人 蔓草
  • 开始时间 开始时间

蔓草

Unregistered / Unconfirmed
GUEST, unregistred user!
unit text;

interface

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

type
TTestCombobox = class;
TMyComboBox=class(TListbox)
private
FEdit:TTestCombobox;

protected
procedure CreateParams(var params:TCreateParams);override;
procedure CreateWnd; override;
procedure WMSetFocus(var Msg:TWMSetFocus);message WM_SETFOCUS;
procedure WM_LButtonDown(var Msg:TWMMouse);message WM_LBUTTONDOWN;
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;
procedure WMKillFocus(var Msg:TWMKillFocus);message WM_KILLFOCUS;
procedure WM_KeyDown(var Msg:TWMKey);message WM_KEYDOWN;
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.WMKillFocus(var Msg: TWMKillFocus);
begin
inherited;
if FDowned then
HideCombobox;
end;

procedure TTestCombobox.WM_KeyDown(var Msg: TWMKey);
begin
case Msg.CharCode of
VK_UP,VK_Down:
begin
if FDowned then
begin
SendMessage(FMyCombobox.Handle,Msg.Msg,Msg.CharCode,Msg.KeyData);
end
else
Inherited;
end;
VK_Return,vk_space:
begin
text:=fmycombobox.Items[fmycombobox.itemindex];
if FDowned then hidecombobox; /////这句话怎么没有用,如果是空格键总是出现一个空格,怎么去掉呢
////我想在这里加上一个过程把焦点转移开,相当于TAB健,我写个几个都不管用,应该怎么写?
end;
else
Inherited;
end;
if not FDowned then
begin
ShowComboBox;
end
end;

procedure TTestCombobox.WM_LButtonDown(var Msg: TWMMouse);
begin
Inherited;
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:=fedit.width;///这句怎么没有用?
Height:=130;


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.CreateWnd;
begin
inherited;
inherited CreateWnd;
Items.Assign (Screen.Fonts);
end;

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


procedure TMyComboBox.WM_LButtonDown(var Msg: TWMMouse);
begin
inherited;
fedit.Text:=items[itemindex];////这句话永远也不发生,为什么?
end;

end.
 
本人视力不好,看不清楚
 
黑的红的都能看清,黄的实在是看的太累
 
不好意思,现在改好了![:)]
 
你写的这个东东是干什么用的?

TMyComboBox,TTestCombobox你到底要注册哪一个组件?

why? RegisterComponents('DevTools', [TTestCombobox]);

我简直受不了了。
TMyComboBox=class(TListbox)
private
FEdit:TTestCombobox;

TTestCombobox = class(TcustomEdit)
private
FMyComboBox:TMyComboBox;
上面的这两行我实在看不明白,TMyComboBox与TTestCombobox到底是什么关系?

 
TestCombobox是一个文本矿
mycombobbox是一个下拉矿,名字起的不好点!
 
To 蔓草:
看了一下你的代码,就你存在的问题提供一些意见供你参考。
(1)Width:=fedit.width;///这句怎么没有用?
我试过了,有起作用
(2)
procedure TMyComboBox.WM_LButtonDown(var Msg: TWMMouse);
begin
inherited;
fedit.Text:=items[itemindex];////这句话永远也不发生,为什么?
end
你想一想,由于你在WM_SETFOCUS事件中使它得不到焦点,所以根本没有鼠标事件发生
解决方法:去掉WM_SETFOCUS方法
(3)begin
text:=fmycombobox.Items[fmycombobox.itemindex];
if FDowned then hidecombobox; /////这句话怎么没有用,如果是空格键总是出现一个空格,怎么去掉呢
////我想在这里加上一个过程把焦点转移开,相当于TAB健,我写个几个都不管用,应该怎么写?
end;
这句当然有起作用只不过是作无用功罢了,看看你随后的语句
if not FDowned then
begin
ShowComboBox;
end
刚刚把它隐藏了,你又把它给显示出来了,看起来好像是什么都没发生,其实已经经历了
隐藏和重新显示两个阶段!
解决你的你个疑问之后,你的代码还有很多其他问题,首先
(1)CM_CANCELMODE事件中的写法导致你无法用鼠标来选择下拉框,只要你在下拉框位置
即使是滚动条也会立即隐藏下拉框!
应改为:
if (Msg.Sender <> Self) and (Msg.Sender <> FMyComboBox) then
HideComboBox;
同时在TMyComboBox类中增加procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
用来处理当在下拉框中用鼠标选中时隐藏下拉框
代码如下:inherited MouseUp(Button, Shift, X, Y);
FEdit.HideComboBox;
(2)到现在为止由于去掉了WM_SetFoucs事件,按照你的代码你会发现一显示下拉框
编辑框位置就失去焦点,这显然不是你希望的,这是你
TMyComboBox类的CreateParams和CreateWnd写法有写不恰当导致的,改为:
procedure TMyComboBox.CreateParams(var params: TCreateParams);
begin
inherited CreateParams(params);
with Params do
begin
//Style:=style or ws_popup;
EXStyle:=WS_EX_CLIENTEDGE or WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
end;
end;

procedure TMyComboBox.CreateWnd;
begin
inherited CreateWnd;
Windows.SetParent(Handle, 0);//设其Parent为桌面
CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
Items.Assign (Screen.Fonts);
end;
现在你在试试,一切都OK了,当然你还有许多可以改进的,比如给编辑框的画一个向下
的箭头,处理下拉框的MouseMove(当MouseDown时处理)事件增加使用的便捷性
在TMyComboBox类中增加KeyDown事件处理上下箭头的选择等

呵呵,如有什么不对的地方请各位大侠指正[:D][:D][:D][:D]
 
balaschen:你终于出现了,我回去实验一下,非常感谢你,太感谢你了!
 
balaschen:
(3)begin
text:=fmycombobox.Items[fmycombobox.itemindex];
if FDowned then hidecombobox; /////如果是空格键总是出现一个空格,怎么去掉呢
////我想在这里加上一个过程把焦点转移开,相当于TAB健,我写个几个都不管用,应该怎么写?
end;
在问问这两个问题,我在加分给你!
 
》》如果是空格键总是出现一个空格,怎么去掉呢
处理WM_Char消息
procedure TTestCombobox.WMKeyPress(var Msg: TWMKey);
begin
if Msg.CharCode=Vk_Space then
Msg.CharCode:=0
else
inherited;
end;
第二个问题如果你要实现按TAB键的效果好像有点麻烦,我去看看Windows消息帮助
 
总算找到了,加上这一句:GetParentForm(Self).Perform(CN_KEYDOWN,VK_TAB,0);[8D]
 
请将最终修改好的代码发送到zhulin@163.net
 
balaschen:
你真是神呀,根据你所说的所有问题都解决了,
我新加了一个按纽,但是想多得到几个事件的时
候出现了一点小问题,希望你能在百忙之中看一下,
我想多增加一个onkeydown或者onkeypress事件,但
是出问题了,详细请看:

另外请您到http://www.delphibbs.com/delphibbs/dispq.asp?lid=657979
上随便回答一下,是我以前问的一个问题,跟这个其实是一样的,那50分也
送给你!谢谢!:)[:)]
unit text111;

interface

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

type
TTestCombobox = class;
TMyComboBox=class(TListbox)
private
FEdit:TTestCombobox;
protected

procedure CreateParams(var params:TCreateParams);override;
procedure CreateWnd; override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure WM_LButtonDown(var Msg:TWMMouse);message WM_LBUTTONDOWN;
public
constructor Create(AOwner:TComponent);override;
end;


TTestCombobox = class(TEdit)
private
FMyComboBox:TMyComboBox;
FDowned:Boolean;
FListWidth:integer;
procedure ShowCombobox;
procedure HideComboBox;
function GetList: Tstrings;
procedure SetList(const Value: Tstrings);
protected
procedure CMCancelMode(var Msg:TCMCancelMode);message CM_CANCELMODE;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WM_LButtonDown(var Msg:TWMMouse);message WM_LBUTTONDOWN;
procedure WMKillFocus(var Msg:TWMKillFocus);message WM_KILLFOCUS;
procedure WM_KeyDown(var Msg:TWMKey);message WM_KEYDOWN;
public
Constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
published
// property OnKeyDown;
property ListWidth:integer read FListWidth write FListWidth default 120;
Property List:Tstrings read GetList write SetList;
{ Published declarations }
end;

THKlist = class(TWinControl)
private
FSpeedButton: TSpeedButton;
Ftext: TTestCombobox;

protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure SetText(Value: String);
function GetText: String;
function GetFont: TFont;

function GetListitems: Tstrings;
procedure SetListitems(const Value: Tstrings);

procedure SetFont(Value: TFont);
function GetOnButtonClick: TNotifyEvent;
procedure SetOnButtonClick(Value: TNotifyEvent);

function GetOnKeyDown: TNotifyEvent;
procedure SetOnKeyDown(Value: TNotifyEvent);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
Property Listitems:Tstrings read GetListitems write SetListitems;
property Text: String read GetText write SetText;
property Font: TFont read GetFont write SetFont;
property OnKeyDown: TNotifyEvent read GetOnKeyDown write SetOnKeyDown;
property OnButtonClick: TNotifyEvent read GetOnButtonClick write SetOnButtonClick;
// property Onenter: TNotifyEvent read GetOnchange write Setonchange;
end;


procedure Register;

implementation

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

{ TTestCombobox }

procedure TTestCombobox.CMCancelMode(var Msg: TCMCancelMode);
begin
inherited;
if (Msg.Sender <> Self) and (Msg.Sender <> FMyComboBox) then
HideComboBox;
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;



function TTestCombobox.GetList: Tstrings;
begin
result:=fmycombobox.Items;
end;



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



procedure TTestCombobox.SetList(const Value: Tstrings);
begin
Fmycombobox.Items.Assign(value);
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.WMKillFocus(var Msg: TWMKillFocus);
begin
inherited;
if FDowned then
HideCombobox;
end;

procedure TTestCombobox.WMSize(var Message: TWMSize);
begin

Fmycombobox.Width := Message.Width+21;

inherited;
end;

procedure TTestCombobox.WM_KeyDown(var Msg: TWMKey);
begin
if not FDowned then
begin
ShowComboBox;
end;
case Msg.CharCode of
VK_UP,VK_Down:
begin
if FDowned then
begin
SendMessage(FMyCombobox.Handle,Msg.Msg,Msg.CharCode,Msg.KeyData);
end
else
Inherited;
end;
VK_Return:
begin
GetParentForm(Self).Perform(CN_KEYDOWN,VK_TAB,0);
if fmycombobox.itemindex<>-1 then
text:=fmycombobox.Items[fmycombobox.itemindex];
if FDowned then hidecombobox;
end;
else
Inherited;
end;

end;

procedure TTestCombobox.WM_LButtonDown(var Msg: TWMMouse);
begin
Inherited;
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];
Height:=130;
Visible := False;
Parent:=TWinControl(AOwner);

end;

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

procedure TMyComboBox.CreateWnd;
begin
inherited;
inherited CreateWnd;
Windows.SetParent(Handle, 0);//设其Parent为桌面
CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
end;


procedure TMyComboBox.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
FEdit.HideComboBox;
end;

procedure TMyComboBox.WM_LButtonDown(var Msg: TWMMouse);
begin
inherited;
if itemindex<>-1 then
fedit.Text:=items[itemindex];
end;

{ THKlist }

constructor THKlist.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Ftext:= Ttestcombobox.Create(Self);
Ftext.Parent := self;
Ftext.Height := 21;

FSpeedButton := TSpeedButton.Create(Self);
FSpeedButton.Left := Ftext.Width;
FSpeedButton.Height := 19; // two less than TEdit's Height
FSpeedButton.Width := 19;
FSpeedButton.Caption := '...';
FSpeedButton.Parent := Self;

Width := Ftext.Width+FSpeedButton.Width;
Height := Ftext.Height;
end;

destructor THKlist.Destroy;
begin
FSpeedButton.Free;
Ftext.Free;
inherited Destroy;
end;

function THKlist.GetFont: TFont;
begin
Result := Ftext.Font;
end;

function THKlist.GetListitems: Tstrings;
begin
result:=ftext.List;
end;

function THKlist.GetOnButtonClick: TNotifyEvent;
begin
Result := FSpeedButton.OnClick;
end;

function THKlist.GetOnKeyDown: TNotifyEvent;
begin
Result := Ftext.OnKeyDown;////这句有问题
end;

function THKlist.GetText: String;
begin
Result := Ftext.Text;
end;

procedure THKlist.SetFont(Value: TFont);
begin
if Assigned(Ftext.Font) then
begin
Ftext.Font.Assign(Value);
fspeedbutton.Font.Assign(value);
end;
end;

procedure THKlist.SetListitems(const Value: Tstrings);
begin
Ftext.list.Assign(value);
end;

procedure THKlist.SetOnButtonClick(Value: TNotifyEvent);
begin
FSpeedButton.OnClick := Value;
end;

procedure THKlist.SetOnKeyDown(Value: TNotifyEvent);
begin
Ftext.OnKeyDown := Value;
end;

procedure THKlist.SetText(Value: String);
begin
Ftext.Text := Value;
end;

procedure THKlist.WMSize(var Message: TWMSize);
begin
inherited;
Ftext.Width := Message.Width-FSpeedButton.Width;
FSpeedButton.Left := Ftext.Width;
end;

end.
 
balaschen:
你在哪里呢,怎么不出来了呢?
 
奇怪,怎么没收到Email通知呢?
我中午看一下。
 
你的事件定义类型不匹配,把所有关于OnKeyDown和OnKeyPress的代码的TNotifyEvent改为
TKeyEvent就行了,TNotifyEvent定义的事件过程只有默认参数,只有TKeyEvent定义的
才具有Key,Shift等参数,建议你在定义事件的时候,如果是通用的可以参考一下Controls
单元的Type部分,在这里定义了大多数常用的事件如:TKeyEvent,TKeyPressEvent等。

题外话:看来你对控件的制作的一些细节还不是很了解,有空可以看看《delphi高级开发
指南》是所有介绍控件编程的书中最好的一本!你的另一个问题我看了,留下你的Mail,我
把我收集的一个控件给你参考。
 
非常感谢balaschen!!!!!!
 

Similar threads

后退
顶部