14

Using DXE2, I've written a form generator that creates both .pas and .dfm files. I am working on a routine that will allow me to modify different properties in the the dfm, such as Font.Height and TabOrder.

When I open a generated file in notepad, everything looks exactly as I expect it to. When I open it up in Delphi, the properties get changed! The thing that is so frustrating is that I am using a form originally designed in the Delphi IDE as my template. I don't understand why Delphi won't respect my simple changes...

For example, the original Font.Height is -11. I read in the dfm, change it to -17, and save it. In notepad, it shows the -17. When I open it in Delphi, it shows up as -21!

Any ideas/tips/suggestions would be greatly appreciated!

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
skippix
  • 481
  • 1
  • 6
  • 14

2 Answers2

16

My guess is that you have a mismatch between the PixelsPerInch on your machine and the value stored in the .dfm file. When Delphi reads the .dfm file it will scale any dimensions according to the ratio of the .dfm file PixelsPerInch and your machine's current PixelsPerInch.

Typical values of PixelsPerInch are 96dpi and 120dpi. Note that 17*120/96 = 21.

Now, as for TabOrder, the IDE will always write out the form order in consecutive values. So, if you have any values missing in your .dfm file then the IDE will write out a different version of the TabOrder values.

Note that you can't get Delphi to leave your .dfm file alone. Once you make any modification to the design space, and save the form, Delphi will stream it out in its preferred format.

This is really an unavoidable consequence of the way .dfm files are handled. The IDE never edits .dfm files directly in the same way it does with your .pas files. Instead it reads the .dfm file in, creates the components defined on the form, and assigns their properties. When the .dfm file needs to be saved again, the components are asked to stream themselves out. So the underlying model that is holds the settings is a TComponent instance (often a form for example) owned by the IDE rather than the .dfm file.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • ARRRGGG!!! So, basically, if I'm going to persist rolling my own forms, I should altogether leave the IDE out of it? – skippix Mar 29 '12 at 14:41
  • 2
    Even when your `PixelsPerInch` matches, that stream-in-stream-out approach causes lots of chaos. `TImageList` is the worst offender, and it's all kind of unavoidable, due to MS Common Controls internals. Eventually many developers find they need DFM-review before each version control commit. (See my answer) I imagine a tool to review DFM changes and to revert accidental ones, could be built. Maybe I'll build one. – Warren P Mar 29 '12 at 15:10
  • 1
    @WarrenP Yeah, I know all about .dfm hell. And I always review before commit. For me I find that my custom component sometimes loses its properties when it is hosted inside a frame, i.e. the inherited keyword in the .dfm file. – David Heffernan Mar 29 '12 at 15:14
3

What I do is let the IDE make what changes it wants to, and use Tortoise{HG,SVN,etc}+KDIFF3 to review (using its merge feature) and only commit the changes that I make, reversing those that the IDE made that I don't want to keep.

Steps:

  1. Go to the commit dialog of your version control system.

  2. For each DFM in the list, right click and "View Diff" or "Visual Diff" or whatever the view-differences command in your version control app is called.

  3. Your diff tool will come up. I use KDIFF3, but some people use BeyondCompare. I click "Merge -> Merge Current file" and then I revert all changes that it makes that I don't want.

  4. Save results of merge. Commit it.

Believe me, the craziness of DFMs is something that you will be astounded at. Every time you open a DFM and change it, every single TImageList in it will be modified, creating a difference for you to commit in your version control system, and if you have more than 1 developer on your team, you are just about guaranteed "merge conflicts". Start practicing "DFM hygiene" and you'll thank yourself later. When you do a manual merge like this, you're basically deciding to keep or revert, each "hunk" of the delta that would be committed into your version control system. What is shown below as "Conflict" is really "A or B choice". Hit Ctrl+1 to choose A, hit Ctrl+2 to choose B, and continue. You can quickly go through a huge number of accidental changes, keep only those which you intended to make, and then commit your DFM.

enter image description here

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 3
    Who keeps their images in .dfm files? Resources are the only way to go. – David Heffernan Mar 29 '12 at 15:02
  • 2
    ImageLists loading from Resources is a very good idea. I have been transitioning to using those for such reasons. But that does kill your designtime fun, doesn't it? How would you design and layout a UI and visually select an image when it's not yet loaded at designtime? Also, TQuery type components with the SQL hard-coded in DFMs is Really Evil and should be killed with fire, unless it's Day 0 and you're just prototyping. – Warren P Mar 29 '12 at 15:14
  • I know, I don't think there is a good solution. As you know, my app does lots of DPI based scaling and so I need to be able to load different sized icons at runtime. That means image lists are just out. Of course, one could create an image list that used resource names to identify images. I guess that could be made to work at design time easily enough. – David Heffernan Mar 29 '12 at 15:24
  • 5
    A custom image list that use resource names is what we're using here, it works well, and promotes sharing resources across image lists. On the downside, it means you also need to make your own image list editors (with resource preview, since you can't use the file explorer to know what you're selecting) – Eric Grange Mar 29 '12 at 15:35
  • @DavidHeffernan - I still keep my images in my dfm files... :-( – Leonardo Herrera Mar 29 '12 at 15:38
  • 2
    Eric; That would be a cool blog post. (Custom image list editor with resource preview.) Please post a link on your blog or somewhere with a sample, if you have time. – Warren P Mar 29 '12 at 15:38
  • 2
    @EricGrange - is that marvel downloadable from somewhere? :-) – Leonardo Herrera Mar 29 '12 at 15:38
  • Thanks, everyone! I'm glad to know I'm not nuts (well, at least as far as this issue goes...) I will probably end up building a simple DFM sanitizer that allows me to maintain *my* property settings. – skippix Mar 29 '12 at 17:19
  • @WarrenP: Wait, what's so bad about keeping SQL queries in the DFM? It gives you a simple place to hold them that's easily accessible from the IDE, it handles multi-line strings quite well (unlike placing the SQL in the .pas files, which I have seen people do before,) and if you're doing it right, your data-access components are on Data Modules, which don't have visual components that the IDE will rearrange at the drop of a hat. – Mason Wheeler Mar 29 '12 at 17:41
  • 1
    What's bad isn't that it's in the DFM, it's that Delphi can do some crazy things with that SQL multiline string formatting. Now imagine two people make changes to a 30 line query. One makes a change at line 3 and one makes a change at line 5. WHat was perfectly readable in designtime SQL designer is not readable when merging that dfm. Now take those two versions of that DFM, and merge it for me. Can you do it? ANy change of any byte anywhere in the query can cause a ripple effect in the resulting DFM. Nasty. – Warren P Mar 29 '12 at 17:45
  • I've been pushing for developers here to start keeping images within actual files, and loading them upon startup. Resources are also an ideal way to go too, but files keep the EXE size from growing abnormally. For example, our home screen of our software has more image data in its DFM than it does any other properties. Extracting all the images out to files is going to cut our EXE size almost in half (there's some rather large images in this EXE) – Jerry Dodge Mar 29 '12 at 19:07
  • @Jerry What does it matter if the images are in the exe or in separate files? Why would it make any difference, other than making deployment a hassle due to all the extra files. – David Heffernan Mar 29 '12 at 19:11
  • @DavidHeffernan Smaller EXE size, and deployment is no hassle at all. We update our clients' EXE's all the time, but the images practically never need updating. Plus, we have multiple EXE's which use the exact same image (for example, splash screen, logos, button icons, etc.). So each EXE re-uses the same images. We're also looking into user customization, for example, user can modify an image to fit their wants. – Jerry Dodge Mar 29 '12 at 22:33
  • @jerry Smaller exe size doesn't have the advantages that you think it does. But sharing between apps makes sense. Your app is a little different though. Most of us have images for toolbar buttons and the like. Your images are of a different nature. – David Heffernan Mar 30 '12 at 06:21
  • No one size fits everybody. I see Jerry's points and David's as equally important and valid. As long as everybody who makes a decision considers both (a) ease of deployment and (b) graceful failures in case of missing external dependencies, I see few reasons to prefer David or Jerry's point of views exclusively. They're both right, sometimes. Customization of splash screen images is very important for many vertical market apps. Ergo external splash bitmap. I think we can all agree that the combination of TImageList+designtime-DFM-with-large-high-color images is bad. – Warren P Mar 30 '12 at 13:42
  • 1
    Add to this the eternal ExplicitWidth/Explicit... mangling of Delphi in the DFM files (even when neither Align or Anchor are used) and it often becomes a mess. I wish DFM were XML and pretty printed. That would make some of it easier. And a bugfree IDE of course (: For the Explicit*, see http://stackoverflow.com/questions/2476690/delphi-why-does-explicitwidth-and-explicitheight-keep-appearing-in-dfm-files#comment2471470_2477026 – Jeroen Wiert Pluimers Jan 29 '15 at 12:28
  • I don't wish that. XML is a special hell. And you can " me on it. :-) – Warren P Jan 29 '15 at 22:52