Date/Time Picker as Property Editor in a TCollectionItem descendant - delphi

I'm writing a component which requires properties of type Date, Time, and Date/Time. I would like these properties to be visible in the Object Inspector, with an option to use a popup property editor.
I have tried TDate as a published property, and this gives me the results I need for just Date alone. However I need the same thing for TTime and TDateTime but they don't come with a property editor, and in fact it won't even accept any value I type in there either.
I have found the TDateTimeProperty which can be used as a property editor, or so I understand anyway. I have done the necessary implementation when registering this component. This property I need to apply it to is actually a TCollectionItem descendant, not necessarily a part of the component but within it.
This is how I'm registering it...
RegisterComponents('My Page', [TMyComponent]);
RegisterPropertyEditor(TypeInfo(TDateTime), TMyCollectionItem, 'MyPropName', TDateTimeProperty);
Although this compiles, when I install it, there is no property editor on this property. I have tried using my component's class name in place of TMyCollectionItem but same issue.
What am I doing wrong here to show this property editor?

You don't need to register the built-in property editors for TDateTime, TDate and TTime. They are already registered. That's why your attempts to register them have no impact.
The built-in property editors for these types simply convert between the underlying floating point value and a string representation. They don't implement date time pickers or anything like that.
You say:
However I need the same thing for TTime and TDateTime but they don't come with a property editor, and in fact it won't even accept any value I type in there either.
That is in fact incorrect. They do come with property editors. They are the same built-in property editors that you named in your question. And they do accept values. They don't accept the values you provided because you provided invalid values.
If you want to register a property editor that does provide a visual date time picker, then you will have to write the property editor yourself.

Related

TPageControl: how to prevent changing Style property

I want to prevent a descendant of TPageControl from having a Style property except tsTabs.
At first glance I tried to override SetStyle, but it is declared private in the base class. anyone have ideas?
TPageControl does not natively support what you are asking for. To accomplish what you are asking for, you would have to either:
have your component re-declare the Style property with new getter/setter methods, and then have the setter exit without doing anything. However, the inherited Style property will still technically be accessible at runtime if the user of the component really wants to access it.
derive your component from TCustomTabControl instead of TPageControl, and re-implement everything that TPageControl does, but without promoting the protected Style property. However, the inherited Style property will still technically be accessible at runtime if the user of the component really wants to access it.
have your component override the virtual CreateParams() method and force the TCS_TABS window style in the TCreateParams.Style field. The Style property will still have whatever value the user assigns (which will also affect the behavior of the TabPosition property), but at least the underlying window will always behave as if the tsTabs style were being used.
use a detouring library to hook TCustomTabControl.SetStyle() directly at runtime and make it return without doing anything.

Custom component properties LiveBindings

I've got problems with binding string properties to TLabel.
TGotManager = class(TComponent)
..
..
published
property HotQ1: String read FHotQ1 write SetHotQ1;
property HotQ2: string read FHotQ2 write SetHotQ2;
..
I did create a component because I don't want to use a TPrototypeDatasource.
My goal is to bind both properties to TLabel.text via the designer.
I did this with help from the answer here: Delphi: Making a component visible to live binding
Example 1:
//with this only HotQ1 is bindable via the designer.
[ObservableMember('HotQ1')]
TGotManager = class(TComponent)
Example 2:
//with this only HotQ2 is bindable via the designer.
[ObservableMember('HotQ1')]
[ObservableMember('HotQ2')]
TGotManager = class(TComponent)
The problem is that I only can bind one property via the designer. When dragging that property other ones which are compatible light up green. When dragging the second property the other ones stay red.
I don't get more then one property to work with visual Livebindings. I do get it to work via:
http://docwiki.embarcadero.com/RADStudio/Seattle/en/The_Entire_Project_and_Observing_the_Results
also for reference and automating things further this page from the Australian user group: http://www.adug.org.au/technical/vcl/using-livebindings-to-connect-the-ui-to-objects/
I don't accept this as an answer because this did not solve the problem. It provided a work around.

TShape and Integer Value

I'm recently working on an Dart-Counter.
I have a Dartboard presented on a TImage and for every counting position there is a TShape.
Is it possible to assigne a value to a TShape, because the TShape does not like integer?
Thanks.
You could use the Tag property to store your integer value, if nothing else is using that property.
Tag has no predefined meaning. The Tag property can store any additional integer value for the convenience of developers.
Another way would be to derive a sub-class of TShape and add a property to store the information. This would allow you to give the property a more meaningful name, and make the intent clear.
I would comment though that building up a complex visual user interface out of TShape objects is perhaps an inefficient and error prone way to go about your task. Usually for a task like this is would be better to make a custom control that painted itself appropriately, without the use of sub-components.

Delphi: Property with combobox editor in Object Inspector. Get Form components in a list [duplicate]

This question already has an answer here:
How to create a component property that lists other components?
(1 answer)
Closed 8 years ago.
I want to edit published property in the Object Inspector via dropdown list.
Let's say it's DataSet: TDataSet.
I'm not started yet, but using this http://delphi.about.com/library/bluc/text/uc092501c.htm I will create a property editor and in GetValues method I should do some job to find out which components, that are descendats of TDataSet, are already on the Form that I'm designing now.
Yet didn't find any examples of it. How should I provide access to the current form inside my PropertyEditor.GetValues method or there is another approach?
Why it is NOT this: How to create a component property that lists other components?
Because at certain times in a drop-down list should be listed components of two or more types. At last - I need to hold in the Property a pointer to certain component, which would be not the same type, as it is declared.
I repeat: Property: TClassNone and shoud be listed there: TClassOne, TClassTwo and TClass Three, which are not descendatns of TClassNone.
All I think you need to do is make it a published property of your component and let Delphi's default property editor do its work:
type
TMyComponent = class(TComponent)
...
published
property DataSet: TDataSet read GetDataSet write SetDataSet;
end;
For example, I think TDataSource works like this without registering any special property editor for it.
Sorry, I was too hasty in writing the original answer. Here's an edit:
Write a descendant of TComponentProperty and override GetValues. Have a look at the TInterfaceProperty implementation in DesignEditors which filters the selection only to instances of components supporting the interface assignable to the property.

Delphi: How do i know what my property editor is editing?

i have a property editor (descendant of TPropertyEditor) that is used to edit a property.
When it comes time to edit my property, how do i know what property of what object i'm editing? If i'm going to edit a property, i have to know what property i'm editing.
i've been pulling my hair out, sifting through the Delphi help, the online help, and the TPropertyEditor and descendant source code, and i can't find the answer.
i expected something like:
TPropertyEditor = class(...)
public
procedure Initialize(TheObject: TObject; ThePropertyName: string);
end;
As far as i can tell, my property editor is created, and i will be told to "Edit", and i just have to divine what property they wanted me to edit.
From the help:
Editing the property as a whole
You can optionally provide a dialog
box in which the user can visually
edit a property. The most common use
of property editors is for properties
that are themselves classes. An
example is the Font property, for
which the user can open a font dialog
box to choose all the attributes of
the font at once.
To provide a
whole-property editor dialog box,
override the property-editor class’s
Edit method.
Edit methods use the same
Get and Set methods used in writing
GetValue and SetValue methods. In
fact, an Edit method calls both a Get
method and a Set method. Because the
editor is type-specific, there is
usually no need to convert the
property values to strings. The editor
generally deals with the value “as
retrieved.”
When the user clicks the ‘...’ button
next to the property or double-clicks
the value column, the Object Inspector
calls the property editor’s Edit
method.
Within your implementation of
the Edit method, follow these steps:
Construct the editor you are using
for the property.
Read the current
value and assign it to the property
using a Get method.
When the user
selects a new value, assign that value
to the property using a Set method.
Destroy the editor.
Answer
It's tucked away, and not documented, but i found out how. The property i'm editing that i edit:
TheCurrentValue := TMyPropertyThing(Pointer(GetOrdValue));
Now that i have the value, i can edit it. If i want to replace the property with some other object:
SetOrdValue(Longint(TheNewValue));
The full code:
Create a property editor that descends from TClassProperty:
TMyPropertyEditor = class(TClassProperty)
public
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
end;
First is the housekeeping, telling Delphi's object inspector that my property editor will display a dialog box, this will make a "..." appear next to the property:
function TMyPropertyEditor.GetAttributes: TPropertyAttributes;
begin
//We show a dialog, make Object Inspector show "..."
Result := [paDialog];
end;
Next is the actual work. When the user clicks the "..." button, the object inspector calls my Edit method. The trick that i was missing is that i call my GetOrdValue method. Even though my property isn't an ordinal, you still use it, and just cast the resulting thing to an object:
procedure TMyPropertyEditor.Edit;
var
OldThing: TMyPersistentThing;
NewThing: TMyPersistentThing;
begin
//Call the property's getter, and return the "object" i'm editing:
OldThing:= TMyPersistentThing(Pointer(GetOrdValue));
//now that i have the thing i'm editing, do stuff to "edit" it
DoSomeEditing(OldThing);
//i don't have to, but if i want to replace the property with a new object
//i can call the setter:
NewThing := SomeVariant(OldThing);
SetOrdValue(Longint(NewThing));
end;
If I understand your question right, you're wondering how you're supposed to actually find the value you need to be editing, especially if the object in question contains more than one of them. The answer is that the IDE sets that up for you and the property editor comes "preloaded" by the time Edit is called. TPropertyEditor comes with a bunch of GetValue methods that your Edit function can use to retrieve the value. Or if it's not one of those types, (if it's an object descended from TPersistent, for example,) then you can call GetOrdValue and cast the result to a TPersistent.
Also, you might want to check out TJvPersistentPropertyEditor in the JvDsgnEditors unit of the JVCL to use as a base class. It provides some of the functionality for you.
BTW if you really need it, you can use the GetName method, which will give you the name of the property, but you usually shouldn't have to. And be careful if you're inheriting from something other than TPropertyEditor itself, as GetName is virtual and can be overridden.
A property editor keeps the information about which objects and properties it's editing in the private FPropList variable. The IDE fills that in by calling your editor's SetPropEntry method. You're then generally supposed to call the various methods of TPropertyEditor to find out the properties' values.
It's not really supposed to matter which property you were asked to edit. Your property editor edits properties of a particular type. For in-place editing, your editor provides an implementation of SetValue that translates the string from the Object Inspector into a value of the proper type for the property, and then you call the appropriate Set function, such as SetOrdValue or SetIntfValue. For whole-property editing, the IDE won't call SetValue. Instead, it will call Edit, and you're expected to call GetOrdValue or GetIntfValue (for example) yourself, since your editor already knows what type of property it's designed to edit.
Remember that property editors, in general, can edit multiple properties simultaneously. The name of the property will be the same for all of them, but the type of component they belong to may vary, and thus so may their getters and setters. Call your property editor's GetName method to find out the name. To get the objects, call GetComponent for each index from 0 to PropCount - 1. (Be careful; there's no range checking in those Get functions.) You can also check whether a specific object is in the list by calling HasInstance. The GetPropInfo method will tell you the PPropInfo pointer for the first property, but I don't think that will necessarily be equal to the pointers of all the other properties. Aside from that, you don't get direct access to the PPropInfo data, but again, it really shouldn't matter. If you think you need that for your editor, you're probably doing something wrong; post a new question with more specific information about your underlying task.
Property editors only care about (and are registered for) the type of the property, not the specific property itself.

Resources