0

I have a TCustomControl descendant and I've been looking at TGrid as an example. In its Mouse, ScrollBar, and keyboard events, when deciding whether to call Invalidate(), they use these:

  1. HandleAllocated

  2. ParentForm.ActiveControl = Self

  3. (csDesigning in ComponentState)

  4. ParentForm.Designer.Modified

Now, what are the rules of when you can and should not use these tests to allow Invalidate to be called? Is that the correct way of saying it?

Why is the Handle disappearing and not dealt with some other way?

Please tell me about IDesigner, as I've never used it before.

Last, is their a time when the user uses the component and the Handle is not available for use also?

I see the point of making an object after TCustomControl that tests all events in the messages with:

If HandleAllocated and (ParentForm.ActiveControl = Self) and (csDesigning in ComponentState)

I'm guessing here, but why not override Invalidate() and invoke inherited Invalidate; if a Handle is there, as the Canvas needs a Handle. This might be seen late but stabilizes code.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770

2 Answers2

0

Now what is the rules of when you can and should not use these tests to allow Invalidate to go ahead.

The tests have nothing to do with Invalidate() itself. The csDesigning check in particular is a dead give-away that the component acts differently at design-time than it does at run-time.

Why is the handle disappearing and not dealt with some other way.

VCL windows are not persistent. They can and do get destroyed and recreated dynamically during the app's lifetime. It can happen when certain properties are set, or when Forms are hidden and shown, etc. If a component wants to use its Handle but not force an immediate recreation, it can check HandleAllocated before using the Handle.

And Tell me about IDesigner as I've never used it before?

It is an interface for allowing components to interact with the Form Designer at design-time. The most common use is to call Designer.Modified to let the Form Designer and Object Inspector know that something has changed that requires them to update themselves.

Last is their a time when the user uses the component and the handle is not available for use also?

Yes, it can happen.

If HandleAllocated and (ParentForm.ActiveControl = Self) and (csDesigning in ComponentState). I'm guessing hear, but why not override Invalidate and invoke Inherited Invalidate; if a handle is their

That would require someone to call Invalidate() to begin with. And, more importantly, it would impose the restrictions on every call to Invalidate() under all circumstances, rather than imposing the restrictions only in the particular pieces of code that are acting differently at design-time vs run-time.

as the canvas needs a handle.

The canvas handle is provided by the OS to the control during paint operations. The control is not painted when it does not have a window, though.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Ok no surprizes. So If I was writing in MouseDown and wanted to make sure I have a handle what would you use (I would use GetParentForm(Self) first and find check for nil) then ether 1/ ParentForm.ActiveControl = Self 2/ ParentForm.SetFocus. – user2522301 Jul 31 '15 at 22:20
  • None of those. If your control is receiving mouse events then it (or its `Parent` control, in the case of a `TGraphicControl` descendant) must have had a valid window in order to receive the mouse messages. There is no need to check whether a window handle exists or not. – Remy Lebeau Jul 31 '15 at 22:34
  • I'm trying to use TCustomControl, Are you saying the object can call events as the form is changed that can lose its handle. – user2522301 Jul 31 '15 at 23:00
  • `TCustomControl` is a `TWinControl` descendant, and thus has its own window, so mouse/keyboard messages are delivered directly to the control. It has to have a valid window in order to receive them. Which means inside your control's overridden `Key...()` and `Mouse...()` methods, its `Handle` should always be valid, which means its `Parent.Handle` window is also valid (since a child window cannot exist without a parent window), and so on all the way up to the parent `TForm.Handle` window. – Remy Lebeau Jul 31 '15 at 23:02
  • I need to know that thanks. Also what is going on with my CustomControl descendant at create time when I take out of my Create; Parent := TWinControl(AOwner); Having this code in, it creates a wrong handle but without the handle I have an error message but do not know were its coming from. I guess its an event that HandleAllocated has not been checked some were. Could it be scrollbars? as TWinControl..... has no scrollbars. – user2522301 Aug 01 '15 at 00:00
  • It means you are doing something during construction that you should not be doing. You are correct that setting the `Parent` in the constructor is wrong. The `Parent` is assigned by the caller after construction. If you need to do something that requires the `Handle`, you have to wait until the `Parent` is assigned first, so override either the `Loaded()` and/or `SetParent()` methods. – Remy Lebeau Aug 01 '15 at 03:02
  • Reading between the lines and TGrid I can get the idea a bit. – user2522301 Aug 02 '15 at 21:43
0

Mouse down gains focus. and checking focus or the handle you protect canvas errors when calling invalidate. But the idea is to identify focus before changing data.