Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
ow to Create a descendant of a component to enhance functionality Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
08-Jan-03
Category
VCL-General
Language
Delphi 2.x
Views
91
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Lou Adler

Adding an accelerator key to a TPageControl

Answer:

This tip is an example of extending the functionality of a component by creating a 
descendant. While implicit to the discussion at hand, here's where the power of an 
object-oriented language such as Delphi lays. As you'll see in the code below, it 
doesn't take much to create new functionality of an object by creating a 
descendant. The point of this is that had I not been using an object-oriented 
language, I would have had to re-write the original code of the TPageControl, then 
add the extended functionality. Fortunately, the VCL, which is really an object 
hierarchy, allows me to transparently inherit and retain the ancestral 
functionality and concentrate on the new functionality. You gotta love it!

For those of you new to Delphi, an accelerator key is a key that is pressed in 
combination with the Alt key to execute a command. They're sometimes called 
keyboard shortcuts or hotkeys, and you'll typically see them in menus as the 
underlined letter of a menu item. For instance, the "F" in the File menu selection 
is an accelerator key for that item. So to open up the File menu, you'd press Alt-F.

Accelerator keys aren't limited to just menu items. In fact, for almost any Caption 
property or a Caption-like property (e.g. Radio Group items) of a component, you 
can define an accelerator key. All you need to do is place an "&" before a 
letter to designate it as an accelerator key. This is useful with VCL components 
like a TRadioGroup's Items, which allow the user to quickly select the radio button 
choice with the touch of a key. However, not all VCL components will respond to 
accelerator keystrokes if you define them. TPageControl in Delphi 2.0, which 
replaces TTabbedNotebook, is one of those components. And with it, accelerator key 
functionality would be particularly useful.

The only method I know for implementing accelerator key functionality in a 
TPageControl is to create a new component. There's another way, but you have to 
create menu and define hotkeys for menu items with equivalent functionality 
(they'll turn your pages for you), and that's a pretty kludgy way of doing things. 
Besides, the code to accomplish what we want is actually very simple.

Below is the unit code for a descendant of TPageControl that adds accelerator key 
functionality. We'll discuss the particulars after the listing:

1   unit accel;
2   
3   interface
4   
5   uses
6     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7     ComCtrls;
8   
9   type
10    TAccelPageCtrl = class(TPageControl)
11    private
12      { Private declarations }
13      procedure CMDialogChar(var Msg: TCMDialogChar); message CM_DIALOGCHAR;
14    protected
15      { Protected declarations }
16    public
17      { Public declarations }
18    published
19      { Published declarations }
20    end;
21  
22  procedure register;
23  
24  implementation
25  
26  procedure TAccelPageCtrl.CMDialogChar(var Msg: TCMDialogChar);
27  var
28    I: Integer;
29    Okay: Boolean;
30  begin
31  
32    Okay := False;
33  
34    inherited; //call the inherited message handler.
35  
36    //Now with our own component, start at Page 1 (Item 0) and work to the end.
37    for I := 0 to PageCount - 1 do
38    begin
39      //Is key pressed accelerator key in Caption?
40      Okay := IsAccel(Msg.CharCode, Pages[I].Caption) and CanChange(I); 
41  		//this is the fix
42      //It is, so change the page and break out of the loop.
43      if Okay then
44      begin
45        Msg.Result := 1; //you can set this to anything, but by convention it's 1
46        ActivePage := Pages[I];
47        Change;
48        Break;
49      end;
50    end;
51  
52  end;
53  
54  procedure register;
55  begin
56    RegisterComponents('BD', [TAccelPageCtrl]);
57  end;
58  
59  end.


As you can see from the above. all that's required to add accelerator key response 
is a simple message handler procedure. The message we're interested in is 
CM_DialogChar, a Delphi custom message type encapsulated by TCMDialogChar, which is 
a wrapper type for the Windows WM_SYSCHAR message. WM_SYSCHAR is the Windows 
message that is used to trap accelerator keys; you can find a good discussion of it 
in the online help. The most important thing to note is what happens when the 
TAccelPageCtrl component detects that a CM_DialogChar message has fired.

Take a look at the CMDialogChar procedure, and note that all that's going in the 
code is a simple for loop that starts at the first page of the descendant object 
and goes to the last page, unless the key that was pressed happened to be an 
accelerator key. We can easily determine if a key is an accelerator key with the 
IsAccel function, which takes the key code pressed and a string (we passed the 
Caption property of the current TabSheet). IsAccel searches through the string and 
looks for a matching accelerator key. If it finds one, it returns True. If so, we 
set the message result value and change the page of TAccelPageCtrl to the page 
where the accelerator was found by setting the ActivePage property and calling the 
inherited Change procedure from TPageControl.

I haven't used TPageControl since I created this component because of how easy TAccelPageCtrl makes switching from TabSheet to TabSheet. It's far easier to do a Alt- combination than use the mouse when you're at the keyboard. Play around with this and you'll be convinced not to use the standard VCL TPageControl.

			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC