单击PageControl中的右上方的左右箭头时触发什么事件? ( 积分: 50 )

  • 主题发起人 主题发起人 gencheng
  • 开始时间 开始时间
G

gencheng

Unregistered / Unconfirmed
GUEST, unregistred user!
单击PageControl中的右上方的左右箭头时,PageControl的执行结果让人很不满意,我想让它执行我的自定义过程!
谁告诉我,单击PageControl中的左右箭头时触发什么事件?执行的是什么过程?
 
“PageControl中的右上方的左右箭头”,就是当在 PageControl中增加多个页面时,一屏显示不下,自动在右上角出现的左右箭头。
 
Delphi标准PageControl似乎未提供这个操作的事件.
 
总应该有这个事件处理过程吧,要不它执行什么代码?
 
唉呀,它封装是M$的COM组件,根本未提供相应的事件(内部当然有实现了).
 
单击PageControl中的左右箭头时发送 windows 的 WM_LBUTTONDOWN 消息。
控件截获 WM_LBUTTONDOWN 消息后,仅仅是判断鼠标的位置,如果位置在左右箭头按钮上时执行相应动作。
Windows 的消息是有限的,不可能任意一个控件的任意一个动作都发出各自不同的消息。
 
问题是单击PageControl的任何一处都将发送 windows 的 WM_LBUTTONDOWN 消息,所以单凭这一点无法判断是否是在箭头按钮上单击,还需取得箭头按钮的句柄吧!

另外:默认的单击箭头按钮产生的默认动作也太差劲了,实在是想改变它的执行动作!
 
哪个"箭头按钮"在windows中的控件名是什么?
 
PageControl有一个procedure ScrollTabs(Delta: Integer);其中是这样获取箭头按钮句柄的:
var
Wnd: HWND;
...
Wnd := FindWindowEx(Handle, 0, 'msctls_updown32', nil);
Handle 应该是PageControl的Handle了,那么'msctls_updown32'就应该是这个箭头按钮的Name了
在CommCtrl.pas有这样的定义
const
{$EXTERNALSYM UPDOWN_CLASS}
UPDOWN_CLASS = 'msctls_updown32';

{参考Windows SDK,英文有限,可能有错,:)}
这是一个Windows标准的up-down controls,当点击up-down controls时会给其parent control先发送UDN_DELTAPOS消息,之后发送WM_HSCROLL或WM_VSCROLL消息,
UDN_DELTAPOS消息包含了up-down controls的当前position和欲设置新的position,处理此消息可以确定是否允许up-down controls设置新的position。
TCustomUpDown均有处理这三个消息的procedure,可以参考。



procedure TForm1.FormCreate(Sender: TObject);
begin
OldWndProc := PageControl1.WindowProc;
PageControl1.WindowProc := NewWndProc;
end;

procedure TForm.NewWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_NOTIFY:
with TWMNotify(Message) do
if NMHdr^.code = UDN_DELTAPOS then
begin
//PNMUpDown(NMHdr).iPos; ...
LongBool(Result) := True; //不允许修改Position,这样的话点击箭头按钮就没反应了
end;
WM_HSCROLL:
begin
//TWMHScroll(Message).ScrollCode; ...
end;
else OldWndProc(Message);
end;
end;
end;
 
老兄说的话我一定认真看看!
上次的问题多亏了老兄,我已经把调用hlp的处理过程封装成了一个组件(TWhat),老兄看看给提点意见。源码在这里:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3707252
 
已经有了一个初步的构思,这两天正在写实现代码。
ANiDelphi大侠提供的都是比较关键的东西。
 
根据上面的思路写了一个PageControl组件,有点问题。请大侠看看!!
代码如下:
Unit RLpageControl;

Interface

Uses
SysUtils, Classes, Controls, ComCtrls, Windows, Messages, CommCtrl;

Type
TOnUpDownClickNextEvent = Procedure(Sender: TObject) Of Object; //关联的右键头按钮事件
TOnUpDownClickPriorEvent = Procedure(Sender: TObject) Of Object; //关联的左键头按钮事件
TRLpageControl = Class(TPageControl)
Private
UpDownWnd: HWND;
UpDownControl: TWinControl;
OldWndProc: TWndMethod;
FUpDownNextClick: TOnUpDownClickNextEvent;
FUpDownPriorClick: TOnUpDownClickPriorEvent;
Procedure OnUpDownNextClick(Sender: TObject);
Procedure OnUpDownPriorClick(Sender: TObject);
Protected
{ Protected declarations }
Public
Constructor Create(AOwner: TComponent); Override;
Procedure SetUpDownNextClick(UpDownOnNextClick: TOnUpDownClickNextEvent); Virtual; //用于设置右键头按钮事件指针
Procedure SetUpPriorPriorClick(UpDownOnPriorClick: TOnUpDownClickPriorEvent); Virtual; //用于设置左键头按钮事件指针

Published
Procedure NewWndProc(Var Message: TMessage);
End;

Procedure Register;

Implementation

Procedure Register;
Begin
RegisterComponents('GenCheng', [TRLpageControl]);
End;

{ TRLpageControl }

Constructor TRLpageControl.Create(AOwner: TComponent);
Begin
Inherited Create(AOwner);
If Not (csDesigning In ComponentState) Then //设计期不执行
Begin
OldWndProc := self.WindowProc;
self.WindowProc := NewWndProc;
End;
End;

Procedure TRLpageControl.NewWndProc(Var Message: TMessage);
Begin
Case Message.Msg Of
WM_NOTIFY:
With TWMNotify(Message) Do
If NMHdr^.code = UDN_DELTAPOS Then
Begin
PNMUpDown(NMHdr).iPos:=?????? //这一句该如何写
UpDownWnd := FindWindowEx(Handle, 0, 'msctls_updown32', Nil);
UpDownControl := FindControl(UpDownWnd);
LongBool(Result) := True; //不允许修改Position,这样的话点击箭头按钮就没反应了
End;

WM_HSCROLL:
Begin
If TWMHScroll(Message).ScrollCode = SB_THUMBPOSITION Then
If TWMHScroll(Message).Pos > ???? Then //这一句中的问号部分该如何写???
OnUpDownNextClick(UpDownControl)
Else
If TWMHScroll(Message).Pos < ???? Then //这一句中的问号部分该如何写???
OnUpDownPriorClick(UpDownControl);
End;
Else
OldWndProc(Message);
End;
End;

Procedure TRLpageControl.OnUpDownNextClick(Sender: TObject);
Begin
If Assigned(FUpDownNextClick) Then
FUpDownNextClick(Sender);
End;

Procedure TRLpageControl.OnUpDownPriorClick(Sender: TObject);
Begin
If Assigned(FUpDownPriorClick) Then
FUpDownPriorClick(Sender);
End;

Procedure TRLpageControl.SetUpDownNextClick(
UpDownOnNextClick: TOnUpDownClickNextEvent);
Begin
FUpDownNextClick := UpDownOnNextClick;
End;

Procedure TRLpageControl.SetUpPriorPriorClick(
UpDownOnPriorClick: TOnUpDownClickPriorEvent);
Begin
FUpDownPriorClick := UpDownOnPriorClick;
End;

End.
 
LongBool(Result) := True; //不允许修改Position,这样的话点击箭头按钮就没反应了
改为:
LongBool(Result) := false;
发现点击左右箭头可以执行指定动作了!
 
问题彻底解决了,组件也封装好了。ANiDelphi真是高手!!!!
不能控制PageControl的左右箭头按钮的神话被打破了,可以在左右箭头按钮事件中挂接任何指定的自定义处理过程!!!
感谢ANiDelphi!!!!
 
http://www.51zhan.com 最好的网址站
http://www.51zhan.com 最好的网址站
http://www.51zhan.com 最好的网址站
 
如果封装成组件的话,
OldWndProc,Procedure NewWndProc(Var Message: TMessage);这些就不用了。
可以重载WndProc
protected
procedure WndProc(var Message: TMessage); override;

当然也可以直接处理这两个消息
private
procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;


没事做,写了个
unit Unit1;

interface

uses
Windows, Messages, Classes, ComCtrls;

type
TLRClickingEvent = procedure(Sender: TObject; var AllowClick: Boolean) of Object;

TLRPageControl = class(TPageControl)
private
IsLeftBtn: Boolean;
FOnLeftClick, FOnRightClick: TNotifyEvent;
FOnLRClicking: TLRClickingEvent;
procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
procedure DoLeftClick;
procedure DoRightClick;
procedure DoLRClicking(var AllowClick: Boolean);
published
property OnLeftClick: TNotifyEvent read FOnLeftClick write FOnLeftClick;
property OnLRClicking: TLRClickingEvent read FOnLRClicking write FOnLRClicking;
property OnRightClick: TNotifyEvent read FOnRightClick write FOnRightClick;
end;

implementation

uses
CommCtrl;

{ TLRPageControl }

procedure TLRPageControl.DoLeftClick;
begin
if Assigned(FOnLeftClick) then FOnLeftClick(Self);
end;

procedure TLRPageControl.DoLRClicking(var AllowClick: Boolean);
begin
if Assigned(FOnLRClicking) then FOnLRClicking(Self, AllowClick);
end;

procedure TLRPageControl.DoRightClick;
begin
if Assigned(FOnRightClick) then FOnRightClick(Self);
end;

procedure TLRPageControl.WMHScroll(var Message: TWMHScroll);
begin
inherited;
if Message.ScrollCode = SB_THUMBPOSITION then
if IsLeftBtn then DoLeftClick
else DoRightClick;
end;

procedure TLRPageControl.WMNotify(var Message: TWMNotify);
var
AllowClick: Boolean;
begin
inherited;
with Message do
if NMHdr^.code = UDN_DELTAPOS then
begin
IsLeftBtn := PNMUpDown(NMHdr).iDelta < 0;
AllowClick := not LongBool(Result);
DoLRClicking(AllowClick);
LongBool(Result) := not AllowClick;
end;
end;

end.
 
本来我觉得这次自己写的组件应该差不多,和ANiDelphi大侠写的一比较,发现差距不小。尤其是判断是左右哪个按钮的时候用的方法太笨拙。
仔细看了一下,发现自己要改进的地方居然有3,4项之多,汗。。。
说实话,50分对于从这贴中学到的东西来说真是太少了,请ANiDelphi大侠多多包涵。。
我觉的在大富翁,ANiDelphi大侠的指导方法很好!开始给你指出问题的关键所在,并不给你完整的实现代码,由你自己根据这个思路写具体的实现代码。等你写出后,再给你指出什么地方不对,那些地方需要改进。最后由你自己写出一个比较好的组件代码。
当然,这次就更好了。这次我可以拿自己写的与ANiDelphi大侠写的对照,找出自己的不足,以及自己平时惯用的方法有什么问题,可以有什么更好的方法解决类似问题。
好了,问题圆满解决。结帖!
从来都没有像最近这几天这么痛快过!!!痛快!!
 
后退
顶部