delphidelphi-xe

How do I know when a control can be focused?


I have my own Treeview control derived from TCustomTreeView.

I have added some of my own procedures to the class such as adding nodes. When this procedure is called at runtime I wanted the newly added node to be selected and for the Treeview to be focused so the new node is highlighted.

Here is a extract:

procedure TMyTreeView.AddGroup(AName: string);
var
  Node: TTreeNode;
  Obj: TGroup;

  procedure AddToTree;
  begin
    Obj := TGroup.Create(AName);
    FGroups.Add(Obj);

    Node := Items.AddObject(Node, AName, Obj);
    with Node do
    begin
      ImageIndex := 0;
      SelectedIndex := 0;
    end;

    Selected := Node;
    SetFocus;
  end;

begin
  Node := nil;
  AddToTree;
end;

The above works but I am facing the common error message when calling from the Forms OnCreate event:

Cannot focus a disabled or invisible window

I know you can use the OnActivate event or just don't use OnCreate at all which will not result in the error, but anyone else who may use the component may not realise this.

So I wanted to know if there is a way to determine if my Treeview (or any control) is able to receive the focus, then I could add a little checking of my own, something like:

if ControlIsFocusable then
begin
  Selected := Node;
  SetFocus;
end;

I know there is the Loaded procedure you can override which tells us when the control is loaded but then that would only work on first run. If the control became hidden by the user at runtime (or was not visible to begin with) the Cannot focus a disabled or invisible window error is still going to show up.

The dirty way to do it when not run in the debugger is:

try
  Selected := Node;
  SetFocus;
except
end;

But that defeats the purpose and I hate handling errors in this way.

So basically I wanted to know if there was a way to determine if a control can receive focus, so that we can set the focus to it?


Solution

  • I'm not going to answer the question that you asked, because I think you are doing this wrong.

    The control should not call SetFocus on itself. I can imagine no scenario where that is the correct behaviour. The form or application or framework should determine focus. Not the control.

    Imagine what happens when you have a form with two such controls? Imagine using the keyboard to focus a button, which you then press with the SPACE bar. If the action attached to the button calls your control's method which then changes the focus, you've just gone against the platform UI guidelines. You control now places a severe burden on any application that attempts to consume it.