怎样使自己设计的控件具有输入焦点?(100分)

  • 主题发起人 主题发起人 donkey
  • 开始时间 开始时间
D

donkey

Unregistered / Unconfirmed
GUEST, unregistred user!
我自己设计了一个控件,从customcontrol继承的,但是无法具有输入焦点,
请问如何解决?
 
customcontrol.setfous
你试试看,好吗?
 
在控件代码的哪个地方setfocuse?我怎样才知道应该setfocuse?例如当前的焦点不再我的
控件上,当他安下tab键时,我怎么知道?
 
自己响应消息WM_SETFOCUS,WM_KILLFOCUS。

当你的控件得到焦点时,WM_SETFOCUS事件被触发,可以在此事件脚本中调用函数
DrawFocusRect画一个虚框以表明你的控件得到焦点了。

当你的控件失去焦点时,WM_KILLFOCUS被触发,重新进行正常画,以表明你的控件
失去焦点了。
 
我在控件里重载了消息
private
procedure DoFocused(var Message:TMessage);message WM_SETFOCUS;
.....
但是没有被触发,请问为什么?
 
不可能呀!我的一个控件就是响应这两个消息的。
-------------------------------------------
下面是我的C++Builder代码:

void __fastcall WMSetFocus(TWMSetFocus& Message);
void __fastcall WMKillFocus(TWMKillFocus& Message);

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SETFOCUS,TWMSetFocus,WMSetFocus);
MESSAGE_HANDLER(WM_KILLFOCUS,TWMKillFocus,WMKillFocus);
END_MESSAGE_MAP(TPanel);

-------------------
//WMSetFocus
void __fastcall TExtPanel::WMSetFocus(TWMSetFocus& Message)
{
if(!TabStop)
{
PostMessage(this->Handle,WM_NEXTDLGCTL,0,(WPARAM)false);
return;
}
FGetFocus = true;

if(FOnSetFocus != NULL)
FOnSetFocus(this);

if(FDrawFocusRect)
Invalidate();

Message.Result = 1;
}
//---------------------------------------------------------------------------
//WMKillFocus
void __fastcall TExtPanel::WMKillFocus(TWMKillFocus& Message)
{
FGetFocus = false;

if(FOnKillFocus != NULL)
FOnKillFocus(this);

if(FDrawFocusRect)
Invalidate();

Message.Result = 1;
}
//---------------------------------------------------------------------------

void __fastcall TExtPanel::Paint()// Override
{
TPanel::Paint();

//............... Some code here

//画焦点
if(FDrawFocusRect && FGetFocus)
{
int Offset = 2;

this->Canvas->Brush->Color = clWhite;

Rect = TRect(0,0,this->Width,this->Height);
Rect.Left = Rect.Left + Offset;
Rect.Top = Rect.Top + Offset;
Rect.Right = Rect.Right-Offset;
Rect.Bottom = Rect.Bottom - Offset;

this->Canvas->DrawFocusRect(Rect);
}
}
 
inherite from WinControl and override the WM_SETFOCUS or WM_KILLFOCUS.
 
后来我发现,如果把TabStop设为true,就可以通过按Tab键获得焦点。
to BCB_FANS :
WM_SETFOCUSE,WM_KILLFOCUSE
这两个消息处理后应该将返回值设置为零,其英文文档如下
An application should return zero if it processes this message
我的代码和你的差不多,但是我发现如果用鼠标单击它并不能使它获得焦点,消息也没有
触发。
实现代码如下:
private
FFocused:Boolean;
......
protect
procedure DoFocused(var Message:TWMSetFocus);message WM_SETFOCUS;
procedure DoUnFocused(var Message:TWMKillFocus);message WM_KILLFOCUS;
......
public
function Focused:Boolean;override;
Constructor Create(AOwner:TComponent);override;
......


constructor TImageButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TabStop :=true; //这里必须有
FUpImage := TBitmap.create;
FHotImage := TBitmap.Create;
FDownImage := TBitmap.Create;
FUpImage.Dormant ;
FHotImage.Dormant ;
FDownImage.Dormant ;
FMouseState := msUp;
FTransParent := false;
DoTransParent ;
end;

procedure TImageButton.DoFocused (var message:TWMSetFocus);
begin
FFocused :=true;
message.Result :=0;
Invalidate ;
end;

procedure TImageButton.DoUnFocused(var message:TWMKillFocus);
begin
FFocused :=false;
message.Result :=0;
Invalidate ;
end;

function TImageButton.Focused :Boolean;
begin
Result:=FFocused ;
end;
 
顺便问一句,焦点的确切含义是什么?
 
首先要确认一点:只有具有窗口句柄的控件才能具有焦点。所有从TGraphicControl继承
而来的控件都无法获得焦点,象TSpeedButton,TLabel控件就无法得到焦点。

你的TImageButton是从哪里继承而来的???
 
同意BCB_FANS的话:只有具有窗口句柄的控件才能具有焦点
 
后来我又发现Borland的标准按钮TButton无法使用快捷键,例如把Captipn设置成
'&Button',但是按Ctrl+B无法选中这个按钮,而且按钮处于选中状态,按Enter键
无效,只有按空格键才有效。

下面是ImageButton的定义
type
TMouseState = (msUp, msDown);
TImageButton = class(TCustomControl)
private
{ Private declarations }
TempImg: TBitmap;
FUpImage: TBitmap;
FDownImage: TBitmap;
FHotImage: TBitmap;
FMouseState: TMouseState;
FTransParent: Boolean;
FFocused:Boolean;
procedure DoTransParent;
procedure SetUpImage(Value: TBitmap);
procedure SetHotImage(Value: TBitmap);
procedure SetDownImage(Value: TBitmap);
procedure SetTransParent(Value:Boolean);
protected
{ Protected declarations }
procedure Paint; override;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y:
Integer);override;
procedure DoFocused(var Message:TWMSetFocus);message WM_SETFOCUS;
procedure DoUnFocused(var Message:TWMKillFocus);message WM_KILLFOCUS;
procedure Loaded; override;
procedure KeyPress(var Key: Char); override;
 
TImageButton从TCustomControl继承过来,而TCustomControl又从TWinControl继承过来,
已经具备了获得焦点的条件。既然还是无法得到焦点,那有可能是消息映射出问题。更改
一下代码再试试:

procedure DoFocused(var Message:TWMSetFocus);message WM_SETFOCUS;
procedure DoUnFocused(var Message:TWMKillFocus);message WM_KILLFOCUS;

改为:

procedure DoFocused(var Message:TWMSetFocus);message CM_GOTFOCUS;
procedure DoUnFocused(var Message:TWMKillFocus);message CM_LOSTFOCUS;

不过为什么我的控件直接响应消息WM_SETFOCUS,WM_KILLFOCUS就没有问题呢???郁闷...

 
我是这样解决的:
1.设置TabStop:=true;
2.重载Click,在Click里SetFocuse;这是因为在源代码里也是使用类似的代码
这样无论是鼠标还是按Tab都可以选中了,但是对于Caption:='&Button',按下Alt+B或是B
均无法响应。
请问BCB_FAns,你的可以吗?
 
不好意思,今天下午有事,不能及时回复。晚上回来才开始研究。
---------------------------------------------------------
以前我一直没有注意到这个问题,看到你的疑惑后,再试我的控件发现也同样不行。马上研究VCl源码,搞定 !

所有这些消息都是通过CM_DIALOGCHAR来传递的,看TButton的源码:

procedure TButton.CMDialogChar(var Message: TCMDialogChar);
begin
with Message do
if IsAccel(CharCode, Caption) and CanFocus then
begin
Click;
Result := 1;
end else
inherited;
end;

procedure TControl.Click;
begin
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute
else if Assigned(FOnClick) then
FOnClick(Self);
end;

这就是为什么按Alt+B可以执行TButton的脚本却不能让它得到焦点的原因,因为只执行Click()而没有执行SetFocus()。

-----------------------------------------------------------

看完这两段源码应该知道怎么办了吧?(下面是C++Builder语法)

1、得到焦点,重载函数Click(),如:

DYNAMIC void __fastcall TExtPanel::Click()
{
this->SetFocus();//先设置焦点

TCustomControl::Click();//继续
}

2、响应(Alt+B)之类快捷消息,也就是响应消息CM_DIALOGCHAR

void __fastcall CMDialogChar(TCMDialogChar &Message);

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_DIALOGCHAR,TCMDialogChar,CMDialogChar);
END_MESSAGE_MAP(TCustomCOntrol);

void __fastcall TExtPanel::CMDialogChar(TCMDialogChar &Message)
{
//.......忽略
}

--------------------------------------------------------------

当然,你用Delphi做这些东西更加方便,直接把TButton的源码拷贝过来就行了。
 
不知道你注意到没有,其实TButton的Caption如果设置成'&Button',不管是按shift+b,B,
Alt+b都有效的,但是Ctrl+B无效。
但是如果使用ACtion,则ACtion上的shortCut有效。
所以到此,问题已经基本解决了。多谢。
我们交个朋友吧,liaojb@21cn.com
msn:liaojb@msn.com
QQ:984392
 
呵呵,交个朋友当然可以,只是我只有E-Mail:slwqw@163.com ,没有QQ和MSN。
 
大家都解决了
 
多人接受答案了。
 
后退
顶部