Reputation: 16612
I have a custom component (inheriting from TCustomPanel
) that consists of two other components (let's say two edits). How do I get the tab order right when using the component?
In the tab order designer I can only access the component itself which cannot have focus because it is a panel. What happens at runtime is that I can access the edits using the tab key, but only after the two buttons below the component got focused.
How can I change the tab order in this situation?
Upvotes: 8
Views: 5262
Reputation: 43659
The tab order of those nested controls within your component is distinct from the tab order of the form on which your component resides. The tab order of the component in the tab order list of the form desides when you tab to the nested controls. Once all tab order lists combined, they result in the final cycle:
TabOrder=0
) TabOrder=1
)TabOrder=2
)
TabOrder=0
)TabOrder=1
)TabOrder=3
)To be able to set the tab order of the panel component design time:
Publish the TabOrder
property for your component and set it in the object inspector:
type
TMyPanel = class(TCustomPanel)
published
property TabOrder;
end;
At runtime it is always possible to set the tab order of the component since the TabOrder
property is declared public in TWinControl
.
... which cannot have focus because it is a panel.
No, a panel can aqcuire focus just fine, but will not by default. This is handled with the TabStop
property, which is False
by default. You don't want TabStop
to set True
for your component since (1) a panel has no indicator it has focus and (2) it is not desired (I imagine).
Changing the tab order of the nested controls is preferably done in the constructor of your component, or at runtime.
To be able to set the tab order of the nested controls within you component at design time requires some more work. I do not think you want that, but since my previous answer (deleted) was rubbish (and voted on, strangly) I have worked out an example as compensation.
First, notice that setting the tab order of those edits with the tab order editor in the designer (right click on the panel component) will change the tab order, but it will not last. That is because those changes are not streamed to the DFM.
To be able to stream/save the design time changes of the controls, you need to publish them:
type
TMyPanel = class(TCustomPanel)
private
FEdit1: TEdit;
FEdit2: TEdit;
public
constructor Create(AOwner: TComponent); override;
published
property Edit1: TEdit read FEdit1;
property Edit2: TEdit read FEdit2;
end;
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FEdit1 := TEdit.Create(Self);
FEdit1.SetBounds(10, 10, 100, 21);
FEdit1.Name := 'Edit1';
FEdit1.Parent := Self;
FEdit1.SetSubComponent(True);
FEdit2 := TEdit.Create(Self);
FEdit2.SetBounds(10, 41, 100, 21);
FEdit2.Name := 'Edit2';
FEdit2.Parent := Self;
FEdit2.SetSubComponent(True);
end;
Of course this publishes áll properties of those controls and now users can change whatever they want. To prevent this, consider limiting the published properties of the TEdit
controls:
unit MyPanelEdit;
interface
uses
DesignEditors, Unit2, DesignIntf, SysUtils, Classes, TypInfo, StdCtrls;
type
TEditProperty = class(TComponentProperty)
private
function FilterFunc(const ATestEditor: IProperty): Boolean;
public
function GetAttributes: TPropertyAttributes; override;
procedure GetProperties(Proc: TGetPropProc); override;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterPropertyEditor(TypeInfo(TEdit), TMyPanel, '', TEditProperty);
end;
{ TEditProperty }
function TEditProperty.FilterFunc(const ATestEditor: IProperty): Boolean;
begin
Result := ATestEditor.GetName = 'TabOrder';
end;
function TEditProperty.GetAttributes: TPropertyAttributes;
begin
Result := [paSubProperties];
end;
procedure TEditProperty.GetProperties(Proc: TGetPropProc);
var
LComponents: IDesignerSelections;
LDesigner: IDesigner;
begin
LComponents := GetSelections;
if LComponents <> nil then
begin
if not Supports(
FindRootDesigner(LComponents[0]), IDesigner, LDesigner) then
LDesigner := Designer;
GetComponentProperties(LComponents, [tkInteger], LDesigner, Proc,
FilterFunc);
end;
end;
end.
This limits the properties of the published TEdit
properties to show only TabOrder
.
Upvotes: 14