We've started using VirtualTreeView v5.5.3 with Delphi7 since 1 year and love it!
We would like to use the full potential of the component, but there is only a little information about the BeginSynch method in the help file.
When should BeginSynch + EndSynch be used compared to BeginUpdate + EndUpdate?
Which one should be nested into the other?
What methods can be used in which case? (Sort, ScrollIntoView, MoveTo, NodeHeight, isVisible[], ... ) to group manipulations before painting to speed up the app?
To my understanding they have different, almost opposite purposes, and for your use case you would need BeginUpdate.
BeginUpdate is typically called when you want to do a lot of updates, and you don't want redrawing etc to happen during that process. Many controls, including TListBox and TDBGrid, have this possibility to speed up bulk updates.
BeginSynch is related to events, especially the OnChange event. The VirtualTreeView can fire the OnChange event with some delay when you set the ChangeDelay property to a value higher than 0.
This also means that you may miss some events. If you make two changes in rapid succession, you may only get one event, or you may get the event later than desired.
BeginSynch will start a synchronous mode that fires the OnChange event immediately after (in sync with) the change being made, overriding the ChangeDelay property. Starting this sync mode is easier than saving the value of the ChangeDelay property and restoring it afterwards.
So in a way, you could say that BeginUpdate and BeginSync are almost opposites of each other, in terms of speed, but really it's just about what your usecase is. For your case ("grouping manipulations") you would definitely use BeginUpdate.
The documentation on BeginSynch could be a bit more clear in this regard. It refers to BeginUpdate because it's a similar kind of mechanism (entering some kind of update mode, with a correlating EndSomething method), while actually it should refer to ChangeDelay which it is functionally related to. It's also interesting that the 'Send feedback' link at the bottom of the documentation is not actually a link...
Related
ngOnChanges is deprecated in favour of ngAfterChanges, but the former was given a list of properties that changed. The latter gets nothing. How do I know what changed so I can only perform expensive actions if a particular #Input changed?
Calculating the list of changes was actually expensive itself. So it was dropped instead I would suggest having a setter mark if something has changed for just the expensive inputs.
I have a huge VCL Forms application in delphi and there is an option to display or hide a certain control (MyControl) on each form. Right now the traditional option is enabled, so MyControl should be hidden at runtime.
In Delphi Designer both Controls are visible. Every form is derived from a MyForm-class and in its OnCreate-Procedure the Visible-property of a MyControl (if available) is set to false (according to the traditional option enabled). This does work (as I can see with breaking points and watching expressions). For almost all forms this results in the MyControl not showing.
However for one certain form at some point the MyControl-component itself or any other part of the program sets the MyControls' visibility to true again. How do I find out where this happens?
I am using Delphi 10.1.
my approach:
I've tried to watch the visible-property through the watching-expressions-window using several breaking points. But of course the watching-expression is not available anywhere in the Code (myControl.Visible will only work if the breakingpoint is somewhere myControl is defined). I set a breaking-point anywhere I could evalute myControl.Visible but the magic seems to happen somewhere in between.
So my question: is there some kind of a global variable name, so that I can evalute and watch the visible-property wherever the debugger pauses the program?
a different approach:
I set a data- and an address-breakingpoint but they never fire. Only when I close the program they pause the program a few times.
As advised in the comments, if this is your code you can modify the property to use a Setter and then set a breakpoint on the setter. However if this is not your code and it simply exposes the variable (field) then changing the code to include a setter can be anywhere from triovial to impossible depending on what else needs to be recompiled when you make the change.
If this is your own custom component then you can redeclare an inherited property to use a setter.
If this is not your own custom component - you could make it a custom component and simply change the setter for the property.
You can set a memory breakpoint to alert you to when a memory location changes but your success with this may vary.
I encourage you to experiment with the conditions you can put on breakpoints, get the debugger to work for you.
I have a control derived from TStringGrid.
During creation I want to access the Cancas to do some one time initializing.
I can't do it in Create because the Canvas is not ready yet. I also can't do it in CreateWnd because CreateWnd it is called multiple times.
There are some cheap tricks (use a Boolean variable) to initialize that var only once but I would like to know how to do it the 'nice way'.
So, since Create and CreateWnd is not a good place, where during the creation of a control can I initialize the var ONLY once.
The simple answer is that you should not cache this value. Calculate the value on demand, when you need it.
Caching is something that you should avoid doing. The problem with caching is that you have to make sure that you never work with a stale value. You need to respond to anything that might result in a change in the value and update your cached value.
It's easy to get that updating logic wrong. Even if you get it right, you've just added a whole load of complexity to your code. And you always want to avoid that if possible. In the case of a physical font metric, they are cheap to obtain in comparison with what you use them for. Invariably you will be using the font metric as part of your painting code. And surely that is many orders of magnitude more expensive than obtaining a font metric.
So, you can make all your problems go away by the very simple expedient of not caching, and obtaining the font metric as and when you need it. By all means wrap it up in a property with a getter method to make the code as clean as possible.
I have a utility routine that I call when validating user input in a dialog fails. It sets focus to the offending control, beeps and displays an appropriate message to the user. This works well as long as the offending control is not hidden. Now I have to adapt this to a situation where the relevant controls are children of some kind of collapsible group boxes (possibly even nested), and I have to make sure that the "ancestor" boxes are expanded before calling SetFocus.
Now I have a few possibilities:
Build knowledge about the collapsible component into the error reporting routine. I'd like to avoid that as the routine should rather stay generic.
Pass an callback that can be called prior to (or instead of) SetFocus. This is error prone because one has to remember to pass the callback at all the relevant places.
My favourite solution would probably be an event (or overrideable method) (probably in TWinControl) that tells a container control "please make sure you and you child controls are visible" but I don't know of such a thing.
Any ideas how I can handle this situation?
Define an interface with a method called something like: EnsureVisible.
Implement it for all your components (you may need to derive your own versions of some of these components). This allows different controls to have quite different behaviour.
When a control needs to make sure it is visible it walks its parents and calls EnsureVisible if the interface is implemented.
If you don't like interfaces then do it with a custom Windows message, but you get the basic idea.
In my opinion the best solution would be a separate routine that builds knowledge about all container controls, allowing the dialog validation routine to stay generic and at the same time being focused enough to be easily tested and maintained. Something along the lines of:
procedure ForceControlVisible(C: TControl);
begin
// Recursive code
if Assigned(C.Parent) then ForceControlVisible(C.Parent);
// Code specific to each container control class
if C is TTabSheet then
begin
// Code that makes sure "C" is the active page in the PageControl
// goes here. We already know the PageControl itself is visible because
// of the recursive call.
end
else if C is TYourCollapsibleBox then
begin
// Code that handles your specific collapsible boxes goes here
end
end;
OOP-style methods that rely on virtual methods or implementing interfaces would be way more elegant, but require access to the source code of all the controls you want to use: even if you do have access to all required sources, it's preferable not to introduce any changes because it makes upgrading those controls difficult (you'd have to re-introduce your changes after getting the new files from the supplier).
Each component knows its Parent. You can walk up the list to make each parent visible.
Delphi components have CreateWnd and CreateWindowHandle (and DestroyWnd and DestroyWindowHandle). They're both intended to be overridden by descendants, right? And not intended to be called except by the underlying VCL implementation?
What's the difference between them; when should either of them be overridden?
So far most of the answers here are pretty much on the mark and you would do well to heed their advice. However, there is a little more to this story. To your specific question about when you would override one or the other, I'll try and nutshell things a little bit.
CreateParams();
In general, most of the time all you really need to do is to override CreateParams(). If all you want to do is to subclass (remember Windows style "subclassing?" See Petzold's seminal work on Windows programming) an existing control class and wrap it up in a VCL control, you do this from CreateParams. You can also control what style bits are set and other various parameters. We've made the process of creating a "subclass" very easy. Just call CreateSubClass() from your CreateParams() method. See the core VCL controls for an example such as TCheckBox or TButton.
CreateWnd();
You would override this one if you need to do a little bit more with the window handle once it is created. For instance, if you have a control that is some kind of list, tree, or otherwise requires post-creation configuration, you'd do that here. Call the inherited CreateWnd, and when it returns (you know you have a valid handle if you return from CreateWnd because it will raise an exception if something went awry), just apply your extra magic. A common scenario is to take the data that is cached in an instance TStrings list and actually move it into the underlying window control. The TListBox is a classic example of this.
CreateWindowHandle();
I had to go refresh my memory on this one, but it seems this is one is rarely, if ever, overridden. In the few cases inside VCL itself, it appears that it is used to work around specific Windows version and locale oddities with some controls, such as the TEdit and TMemo. The other more clear-cut case is in TCustomForm itself. In this case it is there to support the old MDI (mutli-document interface) model. In this case MDI children cannot be created using the normal CreateWindowEx() API, you have to send a message to the MDI parent frame to actually create the handle. So the only reason to overide this method is if the actual process of creating the handle is done via a means completely different than the old tried-and-true CreateWindowEx().
I did notice that your question was merely asking about the creation process, but there are corresponding methods that are overridden in some cases for both handle destruction and the "voodoo" that sometimes surrounds handle recreation. But these are other topics that should be covered separately :-).
CreateWnd first calls CreateParams, then calls CreateWindowHandle using the created Params. Generally, you'll override CreateWnd and CreateParams rather than CreateWindowHandle.
I hope this helps!
Who does what:
CreateWnd is the general contractor that creates the fully formed window for a WinControl.
First, it has to set the required attributes for the WindowClass by calling CreateParams and making sure it is correctly registered.
Then it gets the window actually created, by calling CreateWindowHandle which returns the resulting Handle from the OS.
After that, we have a valid window able to process messages, and CreateWnd does the final grooming, adjusting different visual aspects like size, font, etc.
There is also later step done by CreateHandle, after CreateWnd is finished, to help the VCL in managing its windows (identification, parentage,...).
I'm sure that the final answer can only come from the people involved in the creation of the VCL (Allen?), but IMHO the virtual method with the least responsibility / which is lowest in the chain of calls should be overridden. That's why I have always overridden CreateParams() and CreateWindowHandle(). This looks like a good fit since they are both called by CreateWnd(), and both do only one special thing.
In the end it's probably a matter of preference.