Jump to content
A.M. Hoornweg

PixelsPerInch property in datamodules and services :-(

Recommended Posts

Hello all,

 

it is *extremely* annoying that Delphi 11 writes a property "PixelsPerInch" into dfm files of type tDatamodule and tService.  Such objects are totally non-visual so what the heck ?
This property cause runtime errors when such projects are compiled with Delphi 10 or older.  I now have to manually strip it from each and every data module using Notepad!

Share this post


Link to post
40 minutes ago, A.M. Hoornweg said:

Such objects are totally non-visual so what the heck ?

They are visual in the designer and the designer has to know the resolution the datamodule has been designed last.

 

I know this is annoying and even error prone. That's why I made a suggestion to store all dfm with an implicite PixelsPerInch value of 96 and scale only for designing: Option to design in Screen PPI but save in 96 PPI

33 minutes ago, Fr0sT.Brutal said:

CnPack has plugin for stripping out excess props on DFM save

That may cause the non-visual components on the datamodule moving out of sight in the designer when the datamodule is opened about 2-3 times.

Share this post


Link to post
type
  {$I jedi.inc}
  {$IFDEF DELPHI28_UP}
    {$DEFINE HasPixelsPerInch}
  {$ENDIF}

  TBaseDataModule = class(TDataModule)
  {$IFNDEF HasPixelsPerInch}
  protected
    // Ignore PixelsPerInch property in TFrame introduced since Delphi 11
    procedure DefineProperties(Filer: TFiler); override;
    procedure IgnorePixelsPerInch(Reader: TReader);
  {$ENDIF}
  end;

{$IFNDEF HasPixelsPerInch}
procedure TBaseDataModule.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  Filer.DefineProperty('PixelsPerInch', IgnorePixelsPerInch, nil, False);
end;

procedure TBaseDataModule.IgnorePixelsPerInch(Reader: TReader);
begin
  Reader.ReadInteger;
end;
{$ENDIF}

I created a base module to solve this kind of issue 

  • Like 5
  • Thanks 1

Share this post


Link to post
16 hours ago, Uwe Raabe said:

They are visual in the designer and the designer has to know the resolution the datamodule has been designed last.

 

I know this is annoying and even error prone. That's why I made a suggestion to store all dfm with an implicite PixelsPerInch value of 96 and scale only for designing: Option to design in Screen PPI but save in 96 PPI

That may cause the non-visual components on the datamodule moving out of sight in the designer when the datamodule is opened about 2-3 times.

AFAIK there is no property "scaled" in tService and tDatamodule, so why would the designer need to know PixelsPerInch if it's not supposed to do any scaling? There's "Width" and "Height" so it can still create the window big enough to display the placed components.

 

 

As a workaround, I've written a command line application that detects if a DFM is tdatamodule or a tservice and if so, removes the "pixelsperinch" property. Maybe I should do the same for tFrame because I intend to always use 96 dpi in design mode. The tool is now integrated in my Finalbuilder build scripts and so far it looks promising.  If it is error-free, I may use it inside a pre-commit hook in SVN as well.

 

 

 

 

Share this post


Link to post
5 hours ago, baoquan.zuo said:

type
  {$I jedi.inc}
  {$IFDEF DELPHI28_UP}
    {$DEFINE HasPixelsPerInch}
  {$ENDIF}

  TBaseDataModule = class(TDataModule)
  {$IFNDEF HasPixelsPerInch}
  protected
    // Ignore PixelsPerInch property in TFrame introduced since Delphi 11
    procedure DefineProperties(Filer: TFiler); override;
    procedure IgnorePixelsPerInch(Reader: TReader);
  {$ENDIF}
  end;

{$IFNDEF HasPixelsPerInch}
procedure TBaseDataModule.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  Filer.DefineProperty('PixelsPerInch', IgnorePixelsPerInch, nil, False);
end;

procedure TBaseDataModule.IgnorePixelsPerInch(Reader: TReader);
begin
  Reader.ReadInteger;
end;
{$ENDIF}

I created a base module to solve this kind of issue 

I like the idea, but it would require changing existing projects. Existing datamodules, services and frames would need to inherit from new classes.  Maybe it would be more elegant to write a patching unit for older Delphi versions that hooks into the dfm reader and ignores PixelsPerInch. 

Share this post


Link to post
1 hour ago, A.M. Hoornweg said:

why would the designer need to know PixelsPerInch if it's not supposed to do any scaling?

The Left and Top properties of the components on the datamodule as well as its Width and Height are stored in the DFM. When you design a datamodule on a system with 200% scaling and open that later on a system with 100% scaling the datamodule would be shown twice as large. The other way round, when you design a datamodule with 100% (like all datamodules created in previous Delphi versions) and open that on a 200% system, most of the components and their names would probably overlap, because the icons and fonts are scaled in the designer (otherwise they were way too small). When Delphi 11 opens one of those old datmodule it correctly assumes that it was designed with 100% and scales it to 200%. When saving would omit to store the used PixelsPerInch value in the DFM the (already scaled) datamodule would be treated as designed in 100% according to the scheme described and scaled again. 

 

Don't get me wrong: I think this is the wrong approach. Scaling for designing is good, but when saving it should be forced to downscale to 96 PPI again. That way the additional PixelsPerInch property in the DFM can be removed. I also suggest to adopt this behavior for forms and frames accordingly.

  • Like 1

Share this post


Link to post
2 hours ago, A.M. Hoornweg said:

I like the idea, but it would require changing existing projects. Existing datamodules, services and frames would need to inherit from new classes.  Maybe it would be more elegant to write a patching unit for older Delphi versions that hooks into the dfm reader and ignores PixelsPerInch. 

Just a small change:

unit DMSomething;

uses ..., NoDPIDataModule; // add this

type
  TDataModule = NoDPIDataModule.TDataModule; // and this

  TDMSomething = class(TDataModule)
  ...

 

Share this post


Link to post
4 hours ago, Fr0sT.Brutal said:

Just a small change:


unit DMSomething;

uses ..., NoDPIDataModule; // add this

type
  TDataModule = NoDPIDataModule.TDataModule; // and this

  TDMSomething = class(TDataModule)
  ...

 

Would it not be necessary to change the DFM file too (change "object" into "inherited") because of this inheritance?

Share this post


Link to post
2 hours ago, A.M. Hoornweg said:

Would it not be necessary to change the DFM file too (change "object" into "inherited") because of this inheritance?

IDK. Check it yourself 😉 this is kinda trick so it's hard to predict when it will work and when won't

Share this post


Link to post
3 hours ago, A.M. Hoornweg said:

Would it not be necessary to change the DFM file too (change "object" into "inherited") because of this inheritance?

Yes, definitely. Otherwise strange things will happen sooner later. Usually later, when you have completely forgotten that you did this.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×