How to use TVirtualStringTree AccessibleName or implement accessibility? - delphi

I can see that TVirtualStringTree has a property called AccessibleName yet, I don't see it working, that is, giving the string which is set to screen reader such as NVDA.
What I tried is setting this in the OnGetText event but that doesn't seem to produce any results (e.g. Sender->AccessibleName = "my node name";). All it reads is entire contents of the tree, not just a current node just the same as if I didn't make any change to the property, and if node is changed (using keyboard) it doesn't do anything.
What it should be reading is - Column name - column content - another column name - another column content etc. like it does with the regular TListView.
There seems to be an implementation of iAccessible interface here - https://github.com/Virtual-TreeView/Virtual-TreeView/blob/master/Source/VTAccessibility.pas
Can you share some example how to use VirtualTreeView built in accessibility to make the component readable to screen readers as it seems that such examples are really scarce?
Edit (for future googlers):
Related question which solves the C++ Builder accessiblity unit linking:
Implementing VirtualTreeView TVTDefaultAccessibleProvider in C++ Builder
Edit 2 (for future googlers):
Additionally, TVirtualStringTree also provides OnGetImageText. This event is used to provide accessible text for images used in the tree, for example if you have multiple images in a node to represent certain states you can describe these states with image labels.

You need to add VirtualTrees.Accessibility unit to the uses section (project or one of your units). This unit registers accessibility providers, it will read only the focused item in the tree along with column names.

Related

Delphi - comprehensive list of properties of object

For some particular object, I want the equivalent of copying (as text) the list of properties and events that appears in Delphi's Object Inspector.
My purpose is to be able to paste that into a spreadsheet, to be able to add notes to each item, add categorizations of properties that pertain to related functionality, or to compare to other objects (for example to align with inheritance ancestor or descendant).
So far as I know, Object Inspector doesn't have such a copy feature. So what's an alternative quick way to achieve this goal?
For what it's worth, I have Delphi's 1 through 7, 2007, XE, XE2, and Tokyo (of the latter, only Starter).
Clarification based on first few comments:
I do already know that items appearing on Object Inspector is the class's published properties, hence the information can be retrieved from the source files. However, the published properties may be distributed across multiple classes, and indeed multiple source files (due to inheritance), and the items themselves are not in a particularly convenient format. All surmountable. I simply hoped for a faster easier method, given that the Object Inspector's display is already so close to what I was looking for.
Since I don't have enough reputation to comment, I am writing this as an answer.
I think gwideman is asking for a way to copy inside Delphi's IDE, and without any coding with RTTI.
To an extend this is possible. What you need to do is simply select an object and copy (Ctrl-C). After that you can paste it to any text editor or even Excel. It should be something like this:
object Button1: TButton
Left = 60
Top = 510
Width = 80
Height = 25
Anchors = [akLeft, akBottom]
Caption = 'Save'
Enabled = False
TabOrder = 0
OnClick = Button1Click
end
Notice that even the event handlers are included.
You may also notice that the list is rather short. This is because properties that have the default values are skipped. This can be a problem if you need all properties. But if you just want to comment your settings this saves time and is the best.
If you need the whole list of published properties, you can easily get it in Delphi's help. Like TSpeedButton.
Finally, if you right-click on the form and click "View as Text", you can get the properties of the form and all its objects.

Can Orbeon controls have multiple values?

I think the answer is no, but the question has been put to me so I'd like to confirm. My understanding is that any custom XBL control that I create for use in Form Builder can have one and only one value. Is this correct?
I have always assumed this because the control name is then used in the data instance as the name of the node which contains the the value.
This question comes from the desire to have reusable components with multiple values, for example, an Address control so that addresses can be recorded consistently and the same set of fields does not need to be added many times. Orbeon does have some support for this in the form of Section Templates but because the control names stay the same in each instance of a Section Template this does not work well with our design.
The best idea I've had is that a custom control which records multiple values could encode all the values into a single text string for example in JSON. Of course, this is not ideal.
Are there any other options?
It is possible for controls to have multiple values. When that happens the values are typically stored in nested elements. I.e. a control could bound to an element <address>, and could create nested elements <street>, <city>,<country>, etc to store the different parts of the address.
In practice, you can look at how this is done in the Image Annotation annotation control (see wpaint.xbl), which creates nested elements <image> and <annotation>, leveraging the xxbl:mirror="true" functionality.

dbctrlgrid delete and populate entries at runtime

I want to load the content of of dbctrlgrid at runtime (from database). So I encountered several challenges:
How to detect if the dbctrlgrid is empty and/or how to clear it.
How to put Tlabel and Tdbtext on the panel. The main problem seems to be to find the right parent. dbctrlgrid doesn't work. There is an object called Tdbctrlpanel which should work, but I don't know how to access it. I could not find it in properties or methods of Tdbctrlgrid.
Any code snipplet is welcome
To answer 1)
You don't query the TDBCtrlGrid, you query the underlying dataset; if it .IsEmpty the grid is empty.
When people start using data aware (grid) components they have the tendency to see that as the 'data container' that you can query and modify, but that is not the case. See it as a view on your underlying data with some built-in editors that modify that data. Then the 'same rules' apply to you as to these editors: update the underlying dataset.
To add controls to a TDBCtrlGrid you have to set the controls parent to the Panel property of the TDBCtrlGrid. The problem is that this property is protected. There are several ways to overcome this limitation. One is shown at Delphi About: Accessing protected members of a component
This is a common technique known to Delphi programmers as the 'protected hack'.

Delphi TComboBox Dropdown fields filtering [duplicate]

Everyone probably knows what I mean, but to clarify the control would need to:
Fire an event when user edits the text. The event would provide a SuggestionList: TStrings which you could fill with matches/suggestions.
if the SuggestionList is not empty a drop down should appear.
Unlike combo, the control should not attempt to automatically select/auto complete or otherwise affect the editing.
So, is there a Delphi edit/combo control that works like that ?
Use the autocompletion feature built in to all Windows edit controls.
First, fill your TStrings object however you want. Then use GetOleStrings to create a TStringsAdapter to wrap it. (The adapter does not claim ownership of the TStrings object, so you must make sure you don't destroy it while the adapter is still live.) The adapter gives you an IStrings interface, which you'll need because the autocompletion feature requires an IEnumString interface to provide the completion matches. Call _NewEnum for that.
Next, call CoCreateInstance to create an IAutoComplete object. Call its Init method to associate it with the window handle of your edit control. If you're using a combo box, then send it a cbem_GetEditControl message to find the underlying edit window.
You can stop at that point and autocompletion should work automatically. You can disable autocompletion if you want, or you can set any number of autocompletion options.
You say you don't want autocompletion, but in the OS terminology, I think what you really don't want is called auto append, where the remainder of the string is entered into the edit box automatically as the user types, but selected so that further typing will overwrite it, and the user needs to delete the excess text if the desired value is shorter than one of the matches.
There is also auto suggest, which displays a drop-down list of suggestions.
You can enable either or both options. You don't need to filter the list of suggestions yourself; the autocomplete object filters the IEnumString list by itself.
You can use standard TComboBox and faststrings library (for stringMatches() function).
procedure TForm1.cbChange(Sender: TObject);
var
s:Integer;
tmpstr:string;
begin
//suggestions: tstringlist
cb.AutoComplete:=false;
tmpstr:=cb.Text;
cb.Items.Clear;
for s:=0 to suggestions.Count - 1 do
if StringMatches(suggestions[s],cb.Text+'*') then
cb.Items.Add(suggestions[s]);
cb.DroppedDown:=(cb.Items.Count<>0) and (Length(cb.Text)<>0);
cb.Text:=tmpstr;
cb.SelStart:=Length(cb.Text)
end;
If you just want to show a file or url list:
SHAutoComplete(GetWindow(eb_MyComboBox->Handle, GW_CHILD), SHACF_AUTOSUGGEST_FORCE_ON | SHACF_FILESYS_DIRS);
I first implemented this feature like Rob described it in his answer. Later I saw that TComboBoxEx has the property AutoCompleteOptions where I set acoAutoSuggest to True and acoAutoAppend to False. The ComboBox now filters its item list when doing some entry and shows the matching items.
I'm using RAD Studio 10 Seattle and XE2 but don't know if this feature is available in older versions.
To the last bit of your question: "So, is there a Delphi edit/combo control that works like that ?":
A bit late to the party but yes, I have written a free and open source component that implements the Google Place Autocomplete and Google Place Details API's:
It does inherit from the standard TComboBox but you can modify the code to work with any TEdit
https://carbonsoft.co.za/components/
or
https://github.com/RynoCoetzee/TRCGPlaceAutoCompleteCombo

How to sort data as I want in a VirtualExplorerTreeview (VirtualShellTools)

This is probably a very "dumb" question for whoever knows VirtualShellTools but I only started using it and couldn't find my answer in the demos' code. Please note that I'm also unfamiliar with virtualtreeview.
I use a VirtualExplorerTreeview to display a directory structure, linked with a VirtualExplorerListview to display a certain type of files in the selected directory as well as specific informations about them
I've been able to point them at the right place, link them as I wanted, filter everything in the listview, and looking at the demos I have a pretty good idea about how to add my own columns and draw it to display my custom data.
My issue lies with the Treeview: I would like to sort the directories displayed in the order I want; specifically, I want "My Docs" and other folder to appears first, then drives, then removable media. Looking in the TNamespace property I found how to distinguish them (Directory and Removable properties), but I don't know how to implement my own sort/what event I need. I tried CompareNode but that doesn't even seem to be called.
If you want to do everything yourself, then set toUserSort in the TVirtualExplorerTree.TreeOptions.VETMiscOptions property. That causes the control to just use the DoCompare method inherited from the virtual tree view, and that should call the OnCompareNodes event handler.
A better way is to provide a custom TShellSortHelper. Make a descendant of that class and override whichever methods you need. Create an instance of that class and assign it to the tree's SortHelper property. (The tree takes ownership of the helper; free the old one, but not the new one.) If the items are being sorted on a column that that class doesn't know how to compare, then handle the tree's OnCustomColumnCompare event.
To help you figure out exactly which methods you need to override or events you need to handle, set a breakpoint in TCustomVirtualExplorerTree.DoCompare and step through to see what gets called in various situations.

Resources