How can I create a Delphi Object Inspector at run time and use my own components with it? - delphi

Like the title says. I want to add an Object Inspector to my form at rum time, and when I click other components, it should have two way data binding with them.
That is, if I, for instance, change the top property of a TPanel in the object inspector, then the panel should move; and, if I drag the panel, the object inspector should reflect its Top & Left properties.
Of course, I mean this to work for all proprieties, and select a new component each time the user clicks one at run time.
I don't even know where to start :-(
[Update] I do know, however, that I would strongly prefer to use Delphi components, and nothing 3rd party

No, you cannot use the Object Inspector in your own code. It's a proprietary part of the IDE, and it is not available as source or a component. It never has been, and I highly doubt it will ever be. It's also integrated with the rest of the IDE (the Code Editor and Form Designer), neither of which are available as components either. It's functionality is contained in packages that are design-time only, and are not licensed for use outside the IDE (you can't use them in your application).
In addition, most of the property editors that are invoked by the Object Inspector are also implemented in design-time only packages that wouldn't be available to your application either.

Related

When activating OLEControl in my PowerBuilder application, toolbar items disappear

I have created a COM Interop Control in C# to use in my PB application. If I add an ole control to my userobject and select my C# object in the painter, then an olecustomcontrol is created and everything works as expected. However, in order to use a 64-bit version of my object when building the project for a 64-bit platform (in PB Classic 12.6) I added an ole control but hit cancel when asked to select an object, so an olecontrol is created and I can use InsertClass to select my object at runtime. This is working for me but I have one issue: when the user clicks in my control, activating it, the toolbar icons on my MDI window disappear. From the research I have done, it sounds like PB may expect the ole object to provide the menus and toolbars, but my PB menu items are unaffected, it is just the toolbar. My control does contain a toolbar (the control is a rich text editor I created to workaround some shortcomings of the built in control) but I have also tried creating a new Interop Control with only a plain text box on it and got the same results. Actually I also tried using one of the Microsoft controls (Microsoft InkEdit Control) installed on my system, and again got the same results.
Does anyone know how I can fix this toolbar problem? (I'm at a loss, but I'm guessing it may be that I need to somehow tell PB to ignore OLE toolbars and/or tell my C# object not to advertise a toolbar.)
Ah, that legacy code we have to support for decades...
The following would take some research and may not eventually solve the problem, but I'd give it a try. I'd implement a "proxy" COM object that'd serve as an extra layer between your .NET OLE control and its OLE container. Such object would be exposed as OLE control to the PB runtime, and as OLE Container to the .NET control, and forward the COM methods calls between the two. It'd be much easier to code this layer with C++/ATL, but it should be doable with bare C#, too.
Then I'd watch the calls made on IOleInPlaceFrame and IOleInPlaceUIWindow interfaces and block those which lead to the undesired toolbar behavior (if any). I'd also limit the set of OLE control interfaces exposed to the PB runtime to some bare minimum.
The implementation details of AxHost and Control classes might be helpful here, as well as the ATL library source code.
This seems a bug. I created a very simple application that retrieves data into ole control and there was no code in any menu items. As soon data is fetched and ole control gets focus the main MDI toolbar disappear. Somebody should report that bug to SAP.
https://answers.sap.com/questions/300798/toolbar-disappear-when-ole-control-get-focus.html

Preventing component creation - Delphi

I am creating an application which makes use of several TTabsheets (from the TPageControl component). Is it possible to prevent a component (in this case a tab) from being created during the program startup? I want to manually create the tabs at a later stage.
This is not a dynamic component. It was created in the Delphi 2010 IDE.
Thanks!
If you include components in the designer, then they will be created when the form is created. Nothing you can do to stop that.
The logical conclusion is that you need to create the components at run time. One obvious way to make that easier is to put the components on a frame and create that at run time. That will allow you to group related components and do the visual design and property specification at design time, but then postpone creation until you know you need them.

Custom PropertyEditors - They never seem to appear

Information
I seem absolutely clueless as to how I should manage my component packages and install custom property editors. I have spent the last week or so looking at examples and tutorials, I must clearly be doing something wrong as my property editors never show up in the Object Inspector and I require step by step instructions to try and solve this frustration.
Component Package
I currently have one package, and it is set to designtime and runtime in the options. Added to this package are the units to my components (ie, MyButton, MyListBox etc) - Additionally I have a unit containing the RegisterComponents procedure. I can build and install this now, add my components to a new project and run them without any problems.
Adding a custom PropertyEditor
It gets tricky and confusing for me now that I want to introduce a property editor to my components from the package above.
TMyButton for example is a custom button with my own paint methods, it already has published properties to allow changing the appearance of the button - In addition there is also a published list to allow selecting preset appearance settings, example:
TMyButtonStyle = (bsStyle1, bsStyle2, bsStyle3)
I want to take away the list of preset styles and instead add a property to the Object Inspector called 'PresetStyles'. This property will be of paDialog, I want to a show a form where I can visually see the different button styles - a more graphical way of selecting a preset style then from a simple list.
Which packages do I need
If I understand, you need to split designtime packages and runtime packages?
Does this mean I need two register units, one for the components and one for the Property Editors?
I am not full sure how to manage this, as I said my current package is designtime and runtime, I am not sure what package type I should split it into. If I make a new designtime package for the Property Editors, and make the other package runtime only I lose the install button. Even writing this now is confusing me.
Installing the PropertyEditor
One of the articles I tried following was one from this page: http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0097.html
The only thing I changed was add my own dialog form, and change the register code from:
RegisterPropertyEditor(TypeInfo(string), TMdSoundButton, 'SoundUp', TSoundProperty);
to
RegisterPropertyEditor(TypeInfo(string), TMyButton, 'PresetStyles', TSoundProperty);
I know it still says TSoundProperty, I just left it like that until I could get it working then I would change the class name.
Conclusion
What is the correct way of splitting/managing packages between actual components and the design side ie PropertyEditors?
The PropertyEditor never appears on TMyButton in the Object Inspector and I have a feeling it must be something to do with not configuring the packages correctly or something.
I would really appreciate some kind of assistance here, even a link to a really good tutorial guide or something as nothing I am doing seems to work, even using a lot of the examples are not working for me.
I currently have one package, and it is set to designtime and runtime in the options.
To implement custom property/component editors, you MUST separate your code into two packages - one runtime only package containing just the implementation code for the components themselves, and one designtime only package that contains just the implementation code for the component registrations and custom editor(s). The designtime package needs to specify the runtime package, and the designide package, in its Requires list. The runtime package is what gets compiled into executables. The designtime package is what the IDE uses to get your components to appear in the Component Palette and Form Designer and interact with them.
Does this mean I need two register units, one for the components and one for the Property Editors?
No. The runtime package should have no registrations at all. That belongs in the designtime package instead. You can have a single Register() function in the designtime package that registers everything.
If I make a new designtime package for the Property Editors, and make the other package runtime only I lose the install button.
You cannot install a runtime package into the IDE, only a designtime package.
One of the articles I tried following was one from this page: http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0097.html
The only thing I changed was add my own dialog form, and change the register code from:
RegisterPropertyEditor(TypeInfo(string), TMdSoundButton, 'SoundUp', TSoundProperty);
to
RegisterPropertyEditor(TypeInfo(string), TMyButton, 'PresetStyles', TSoundProperty);
Does your TMyButton component actually define a PresetStyles property that is a String type? You cannot define a property editor for a property that does not exist.
Without knowing exactly how your PresetStyles property is implemented in the component itself and what it represents, it probably does not make much sense to invoke a popup Dialog for a String property (except maybe for things like filenames and such). Based on your description, it probably makes more sense to implement a component editor instead of a property editor, and leave your existing TMyButtonStyle property alone to use the IDE's default editor for enum properties. To invoke your popup dialog, the component editor would allow the user to right-click on the component itself and choose "Edit" (or whatever other string value you decide to name it) from the popup menu, or just double-click on the component, in the Form Designer. You can then display and edit the component as desired, and assign any changes to the component when the dialog is closed.
The PropertyEditor never appears on TMyButton in the Object Inspector and I have a feeling it must be something to do with not configuring the packages correctly or something.
It is hard to know for sure since you did not show any of your actual code yet.
If I understand, you need to split designtime packages and runtime packages?
Does this mean I need two register units, one for the components and one for the Property Editors?
No. One registration unit that registers both the components ánd the property editors is enough, as long as that registration unit isn't used at runtime (which normally isn't). This applies to the unit containing the property editor too. Prevent using DesignEditors.pas at runtime, and then you're fine.
Component Package
It is OK to have one package for both today. In the past it made sense to split them if an application was
distributed with runtime packages to reduce the total size. I like to split them up to now to
seperate the implementation and the design interface.
Which packages do I need
If you have two packages the runtime packages must be referenced in 'Requires' in the design time package.
Therefore you only have to register the design time package. The runtime package ist implicit loaded into the IDE.
In your case with one package you have to register this.
Installing the PropertyEditor
There is something wrong with the first parameter. It must be the typeinfo of the property.
RegisterPropertyEditor(TypeInfo(TMyButtonStyle), TMdSoundButton, 'PresetStyles', TSoundProperty);
TSoundProperty should be a descand from TEnumProperty.
Conclusion
Go on with one package. The property should appear with the changed code. If not check that the property is not readonly.

Turn off context menu for Component applied by CnPack (design time)

After I installed cnPack, right clicking on a component in my form seems to have taken away any specific items that the component itself may have applied.
eg, right clicking on any Dev Express component will usually bring up version details. Now I get a bunch of other context menu items and the Dev Express ones have disappeared.
Is there a wizard or some other option I can disable to stop this? I can't find one anywhere.
Thanks
EDIT
Restarting Delphi fixed it in the short term - but has come back again so I'd still like to find a resolution to this....
Right-click menus are controlled by component editors, and AFAIK there can only be one component editor registered to a particular class type at a time. If CnPack's design-time package is loaded after DevExpress's design-time package, then CnPack's component editor will be the last one registered and take priority.

Best Way to Replace a Visual Component in Delphi

In a Delphi Form, I would like to replace one visual component with another. Example: I want to replace a Panel component with an ElPanel from a 3rd party package.
I would like all identical properties and events of the first component to be transferred to the new one, and all the components that belong to the first component (e.g. Toolbars, memos,status bars, etc.) to end up placed on the new component exactly where they were on the first one.
Is there a best/easiest way to do this other than adding the new component to the form and meticulously transferring every property, event and component to it one-by-one?
I do it as following:
Right click on the form and choose (View as Text).
Press Ctrl + F to search for the Component class name like TPanel and replace it with TElPanel
Switch back to back to the form (View as form)
In the interface section replace the TPanel with TElPanel.
if you have many components using GExperts will be more feasible solutions.
You can use GExperts or you can do it by hand.
To do it by hand, open the .dfm in notepad and replace all the class names. (Replace TPanel with TElPanel for example). When you've made all your changes, open the .pas file with Notepad, and do the same thing.
Make sure you add the required units to your uses clause.
Then open the form in the IDE and clean up any mismatched events or unknown property problems.
If I recall the excellent free GExperts plugin does this. Right click your form and select "Replace Components". http://www.gexperts.org
IMHO, the big drawback of the Replace component GExpert is that it changes the order of the components in the source code. That is not very VCS friendly. :-)
If you have other components inside a container doing this replacement with GExperts will cause some ugly exceptions and possibly unexpected behaviour in the IDE.
So, the best solution is to edit the .dfm file where you want (inside or outside the IDE) and replace manually the types of the components that you want to change. Maybe it will cause some exceptions too, but the IDE will managed them.
If you do it inside the IDE, after switching to design view if you save the .dfm inmediately the IDE will ask you to change the type of the variables related to the components you touched, liberating you to do it.
To convert between text and binary dfm formats, use the convert.exe tool in the Delphi bin\ directory. – Tim Knipe (Oct 28 at 4:15)
You can also use the context menu of the form designer - at least with BDS 2006. It's the last menu item ("Text-DFM" in a German IDE).
In my project I had to convert few doezens forms from one set of components to another.
I have created small perl script to convert components and its properties and do all neccesary mapings.
The script is quick&dirty solution but it is highly configurable. It scanns all dfm and pas files in project direcotory and convert dfm components definitions according to rules that you should provide in ObjectBeginFound, PropertyFound, ObjectEndFound procedures/events.
DFM files should be in text mode. Tested on Delphi 5 files. I don't know if it will be compatible with newer versions. Please send posts if you find it out.
USAGE:
perl.exe cxdfm.pl > logfile.txt
DOWNLOAD LINK
http://dl.dropbox.com/u/15887789/cxdfm.pl

Resources