Board index » delphi » Solving the resolution problem (2nd post)

Solving the resolution problem (2nd post)

The following article was posted on the wrong news server
(forums.borland.com instead of newsgroups.borland.com) in
a period when some of the newsgroups were down (2001-03-15).

I am therefore posting it for a second time and I apologize to those
who already saw it.

--------------------------------------------------------------------------------------------------

I currently desing my applications in 1024*768 but I am still having
some problems when running them with other resolutions.

I carefully read Borland's technical document TI2861 (now renamed
0,1410,15944,00.html) and also did some research on DejaNews. Using
the gathered information, I wrote the code at the bottom of this post.
The idea was to call a procedure SetupDisplay from the OnCreate event
handler of each new form.

This, however, doesn't solve the problem:
  - in higher resolution, the form becomes much too large for the
    screen and all controls are misplaced
  - in lower resolution, the form and its font are much too small
    and, again, everything is misplaced.

I found that things are not as bad if the assignments
<<<
    Form.Width:= (Form.Width * ScreenWidth) div devScreenWidth;
    Form.Height:= (Form.Height * ScreenHeight) div devScreenHeight;

Quote

are removed from the procedure (otherwise, it would seem that the form
 is rescaled twice).

Things even improve if we further remove the lines
<<<
    for i:= (Form.ControlCount - 1) downto 0 do
      begin
        Form.Controls[i].Left:= (Form.Controls[i].Left * ScreenWidth) div
                                devScreenWidth;
        Form.Controls[i].Top:= (Form.Controls[i].Top * ScreenHeight) div
                                devScreenHeight;
      end; {for}

Quote

and the lines
<<<
    for i:= (Form.ControlCount - 1) downto 0 do
      TFooClass(Form.Controls[i]).Font.Size:=
        (TFooClass(Form.Controls[i]).Font.Size * ScreenWidth) div
        devScreenWidth;
Quote

using only the ScaleBy procedure.

But, still, everything is far from perfect. Surely some setting has been
overlooked.

In the past, I have seen many posts by programmers struggling with this
issue. The replies contained good suggestions but never a definitive
solution.

It is possible to solve this once and for all?

        Andre

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

{==========================================================================}

 unit UniScale;

  {filename: UniScale.pas
   author:  Andre Ratel
   created: 2000-05-14
   last revision: 2001-03-15}

{--------------------------------------------------------------------------}

{This unit contains variables and procedures for resizing a form under
 various screen resolutions.
 We decided to put them in a separate unit instead of pasting them in
 each unit associated to each form of the project. This way, if there
 are some changes to be made, we will have just one file to edit.
 ref.: Document TI2861 from Borland Web site.}

{Usage:
   - The form should have its properties set as follows

        Property       Default value    New value
        ================================================
        AutoScroll     True             False
        AutoSize       False            False
        BorderStyle    bsSizable        bsSingle or
                                        bsDialog
        Position       poDesigned       poDesigned or
                                        poScreenCenter
        Scaled         True             True

   - If BorderStyle is set to bsSingle, then BorderIcons.bsMaximized should
     be set from True to False.
   - The Form's OnCreate event handler should contain the line
       SetupDisplay(Screen.Width, Screen.Height, TForm(Self));
     Typecasting on the last argument is necessary, otherwise we would get
     the following error message from the compiler
       "Types of actual and formal var parameters must be identical."}

interface

uses
  Forms;

{Adapting a form and its controls to the current MS Windows settings:}
  procedure SetupDisplay(ScreenWidth, ScreenHeight: integer;
                         var Form: TForm);

implementation

uses
  Controls;

type
  {Needed to get at protected font property in procedure SetupDisplay:}
    TFooClass = class(TControl);

procedure SetupDisplay(ScreenWidth, ScreenHeight: integer; var Form: TForm);
  {This procedure resizes the form Form and its controls according to the
   current screen resolution.
   It is to be called by the form's OnCreate event handler.
   The arguments are
     ScreenWidth: the Screen.Width
     ScreenHeight: the Screen.Height
     Form: the form to be resized.}
const
  {The conditions under which applications are currently developped:}
    devScreenWidth = 1024;
    devScreenHeight = 768;
    devPPI = 120;
    {rem: This corresponds to Windows being configured for a screen
          resolution of 1024*768 pixels with LargeFonts. (The value of
          PixelsPerInch is 120 for LargeFonts and 96 for SmallFonts.
          Other values are possible if the user chose Custom in the
          MS Windows Diplay Properties dialog box.)}
var
  {For iterating on the form's controls:}
    i: cardinal;
begin
  {No need for readjusments if the conditions are the same:}
    if ((ScreenWidth = devScreenWidth) and
        (ScreenHeight = devScreenHeight) and
        (Form.PixelsPerInch = devPPI)) then
      Exit;
  {Changing the form's font:}
    if (ScreenHeight < devScreenHeight) then
      Form.Font.Name:= 'Arial';
    {rem: - If the current resolution is lower than the one used for
            developping the application, we use the scalable TrueType
            Arial font. Arial being a stroke font, it will give text
            within a pixel of the desired height.
            On the other hand, if the current resolution is the same or
            is better than the one used for developping the application,
            we keep the default bitmapped MS Sans Serif font since it
            gives nice thick characters.
          - A few tests have shown that keepng MS Sans Serif with a lower
            resolution often resulted in having labels, static text or
            memo strings clipped out of their container.}
  {Rescaling the form:}
    Form.Width:= (Form.Width * ScreenWidth) div devScreenWidth;
    Form.Height:= (Form.Height * ScreenHeight) div devScreenHeight;
  {Repositioning the form, if needed:}
    if (Form.Position = poDesigned) then
      begin
        Form.Left:= (Form.Left * ScreenWidth) div devScreenWidth;
        Form.Top:= (Form.Top * ScreenHeight) div devScreenHeight;
      end; {if}
      {rem: If Position is set to other values than poDesigned, then
            repositioning is not needed.}
  {Rescaling the form and all its controls:}
    if (ScreenWidth/devScreenWidth <= ScreenHeight/devScreenHeight) then
      Form.ScaleBy(ScreenWidth, devScreenWidth)
    else
      Form.ScaleBy(ScreenHeight, devScreenHeight);
    {rem: Here, we use the smallest scaling factor.}
  {Repositioning each control inside the window:}
    for i:= (Form.ControlCount - 1) downto 0 do
      begin
        Form.Controls[i].Left:= (Form.Controls[i].Left * ScreenWidth) div
                                devScreenWidth;
        Form.Controls[i].Top:= (Form.Controls[i].Top * ScreenHeight) div
                                devScreenHeight;
      end; {for}
  {Adjusting the size of each child control's font:}
    for i:= (Form.ControlCount - 1) downto 0 do
      TFooClass(Form.Controls[i]).Font.Size:=
        (TFooClass(Form.Controls[i]).Font.Size * ScreenHeight) div
        devScreenHeight;
end; {SetupDisplay}

end.

Quote

PS:

In Delphi 4's on-line help, we find:
<<<
ChangeScale can be used to change the scale of a form and all its controls
for a different screen resolution or font size. Because ChangeScale modifies
the controls Top, Left, Width, and Height properties, it changes the position
of the control and its children as well as their size.

Quote

and
<<<
Call ScaleControls to rescale only the children of the control, while leaving
the control itself the same size.
Quote

However, ChangeScale and ScaleControls cannot be called by our SetupDisplay
procedure since they are not public methods.

Furthermore, still from the on-line help:
<<<
Call ScaleBy to rescale the control and all its children. ScaleBy modifies
the Height and Width properties of the controls, but it does not change the
Top and Left properties; therefore, the size of the controls changes, but
not the coordinates of the top-left corners of the controls.

Quote

If this means what it says, then using ScaleBy will resize the form and its
font so the lines
<<<
    Form.Width:= (Form.Width * ScreenWidth) div devScreenWidth;
    Form.Height:= (Form.Height * ScreenHeight) div devScreenHeight;
Quote

and
<<<
    for i:= (Form.ControlCount - 1) downto 0 do
      TFooClass(Form.Controls[i]).Font.Size:=
        (TFooClass(Form.Controls[i]).Font.Size * ScreenHeight) div
        devScreenHeight;
Quote

should not appear in our procedure. But this seems to contradict the
information found in Borland's TI2861 document.

-=-
Rem: For my email address, you need to remove the 'nojunk.'
     from what appears in the header.

 

Re:Solving the resolution problem (2nd post)


Quote
"Andre Ratel" <ara...@nojunk.vif.com> wrote in message

news:3ac175bf.26167516@newsgroups.borland.com...

Quote

> I currently desing my applications in 1024*768 but I am still having
> some problems when running them with other resolutions.

One of the dirty little details which has never been adequately treated,
IMO.

Quote
> This, however, doesn't solve the problem:
>   - in higher resolution, the form becomes much too large for the
>     screen and all controls are misplaced
>   - in lower resolution, the form and its font are much too small
>     and, again, everything is misplaced.

There are a number of possibilities, none of them very pretty.

One of them, which we use in a shipping app, is to write code which adjusts
things for each resolution. It's a royal pain for maintenance, but gives us
compkete control over optimizing the appearance of all forms at all
resolutions.

Another is to procure one of the numerous components which *attempt* to
address this issue. There are basically two sorts: one takes the view that
every app has the same general purpose as, say, a word processor, and does
not scale controls; the other attempts to scale all the controls,
maintaining the appearance of the forms at all resolutions. for my apps, the
former approach is just wrong, and the latter *sort of* works. One of the
{*word*193} features of the problem is that a) Windows doesn't support fractional
point sizes in fonts, and some of the components are sized by the font
assigned to them, and b) a linear integral font resolution lacks adequate
resolution (pun intended) where we need it most: at the low end of the
scale. This, in my view, is the one thing, more than any other, which stands
between anyone and a clean solution to this problem.

Quote
> But, still, everything is far from perfect. Surely some setting has been
> overlooked.

Uh, yeah. See my earlier comment about font sizes. In a string grid, for
example, we can assert a default row height, in pixels; in a dbgrid,
however, the row height is controlled by the font selection -- instant
incompatibility in multiple resolutions. This one is easy to address,
however. Collect your data in queries, and populate string grids with it, so
you maintain control over row height.

Quote
> In the past, I have seen many posts by programmers struggling with this
> issue. The replies contained good suggestions but never a definitive
> solution.

We've all struggled, I think. Some have fewer problems with it than others.
The problem is at its worst when you have forms populated with many small
controls, and no edit box taking up the majority of the real estate, as it
would in an editor. You can design at large fonts, and then your forms look
anemic in small fonts. Or design in small fonts, and they just don't work in
large fonts. In my own case, I design software which runs on turnkey systems
at 1024x768 small fonts, so I don't have to deal with it.

Quote
> It is possible to solve this once and for all?

I suspect not, until Windows supports fractional point sizes in its font
engine. I've read many claims of solutions, but they only work for some form
styles, in my experience. The only solution I know which works for ALL cases
is to write code which adjusts things according to the screen height and
width factors at run time. It's a maintenance issue, but the results are
reliable.

Bill

Re:Solving the resolution problem (2nd post)


Quote
Andre Ratel <ara...@nojunk.vif.com> wrote in message

3ac175bf.26167...@newsgroups.borland.com...

Quote
> I currently desing my applications in 1024*768 but I am still having
> some problems when running them with other resolutions.

> I carefully read Borland's technical document TI2861 (now renamed
> 0,1410,15944,00.html) and also did some research on DejaNews. Using
> the gathered information, I wrote the code at the bottom of this post.
> The idea was to call a procedure SetupDisplay from the OnCreate event
> handler of each new form.

Hi , i already answered to a similar question on this newsgroup :
i have copied and pasted the previous answer :
Sorry but i have no much time to compare my code with yours , so i can only
suggest you to try it and see if the results for you are good (P.S. on my
application it works well enough but only for resolution more than 800X600
(design resolution) : i found that on 640X480 the fonts are too large but
perhaps you could add code to modify fonts too ...).
However if you test the code on your Pc screen you can write me a report of
what you see ,thanx .
Quote
> Hi :
> This is how i have solved the problem with my applications :

> Add to the project a unit like this one :

> {Copyright Francesco Savastano 2000 : this unit is free}

> unit screenadjust;

> interface
> uses Forms,controls ;

> procedure screenres(sender : tform; designwidth,designheight:integer);

> implementation

> procedure screenres(sender : tform; designwidth,designheight:integer);
> var
>   I,wth,ht,lft,up: Integer;
>   numx,numy:real;
>   classref:tclass;
>   xres,yres:integer;
>   formpixelsperinch:integer;
>   begin
> xres:= screen.width;
> yres:= screen.height;
> formpixelsperinch:=96;
> numx:=formpixelsperinch/(screen.pixelsperinch)*xres/designwidth;
> numy:=formpixelsperinch/(screen.pixelsperinch)*yres/designheight;
> with sender do begin
>   width:=round(width/designwidth*xres);
>   height:=round(height/designheight*yres);
>   for I := 0 to ComponentCount -1 do
>      begin
>       classref:=components[i].classtype;
>        if components[i] is tcontrol then
>        begin
>        with components[i] as tcontrol  do
>        begin
>        wth:=width;
>        ht:=height;
>        lft:=left;
>        up:=top;
>        width:= round(wth*numx);
>        height:= round(ht*numy);
>        left:= round(lft*numx);
>        top:= round(up*numy);
>        end;
>        end;
>   end;
>   end;
>   end;

> end.

> After this you only have to add the : " uses screenadjust " line to any
> unit with a form in your program and write in the "oncreate" event of the
> form the following call to procedure "screenres" :

> Procedure tform1create(sender:tobject);
> begin
> screenres(form1,1024,768);  { if you designed that form on a 1024X768
> screen else 800X600 or 640X480 : this is also useful if you designed your
> project forms at different resolutions ! )
> end;

Re:Solving the resolution problem (2nd post)


On Tue, 27 Mar 2001 22:28:52 -0800, "William Meyer" <wme...@earthlink.net>
wrote:

Quote
>One of them, which we use in a shipping app, is to write code which adjusts
>things for each resolution. It's a royal pain for maintenance, but gives us
>compkete control over optimizing the appearance of all forms at all
>resolutions.

Yes, but things are not obvious. For example, let's say I design an application
with the settings
    devScreenWidth = 1024;
    devScreenHeight = 768;
    devPPI = 96; {Small Fonts}
and let's say that the client area of the main form has the following dimensions
    Form1.ClientWidth: 592
    Form1.ClientHeight: 373.

If the user runs my application with the settings 800*600, Small Fonts, I can
resize the main form by putting the following lines in its FormCreate event
handler
  {Rescaling the form:}
    Form1.ClientWidth:= (Form1.ClientWidth * Screen.Width) div devScreenWidth;
    Form1.ClientHeight:= (Form1.ClientHeight * Screen.Height) div
                                               devScreenHeight;
No problem there.
On the other hand, if the application is run at 800*600 with Large Fonts, the
dimensions of the client area will automatically become
    Form1.ClientWidth: 729
    Form1.ClientHeight: 459
prior to any resizing command. If I get it right, this means that these will be
the values used in the above calculations, not the original 592 and 373.

And, of course, what I have just said for forms also applies to labels, edit
boxes, buttons, etc..

One way out of this would be to design each form under all possible screen
settings, read all the necessary values from the Object Inspector, and put
then in some kind of array to be used by the FormCreate event handler. But
is this RAD?

Quote
> One of the
>{*word*193} features of the problem is that a) Windows doesn't support fractional
>point sizes in fonts, and some of the components are sized by the font
>assigned to them, and b) a linear integral font resolution lacks adequate
>resolution (pun intended) where we need it most: at the low end of the
>scale. This, in my view, is the one thing, more than any other, which stands
>between anyone and a clean solution to this problem.

I agree that fonts are a major problem. Nothing is more maddening than
to change screen settings and to see edit boxes no longer big enough to
contain their strings, labels cut off at the edge of a panel or incomplete
button captions. But I also had controls piling up one against the other
or misaligned. I had also glyphs too big for their buttons.

Quote
>The only solution I know which works for ALL cases
>is to write code which adjusts things according to the screen height and
>width factors at run time. It's a maintenance issue, but the results are
>reliable.

This is what I was trying to do with the procedure of my previous post. But I
then found out that using screen height and width is not enough. One also
has to take into account whether Small fonts or Large Fonts are being used
and how each type of control will be affected by this choice.

        Andre

-=-
Rem: For my email address, you need to remove the 'nojunk.'
     from what appears in the header.

Re:Solving the resolution problem (2nd post)


Quote
"Andre Ratel" <ara...@nojunk.vif.com> wrote in message

news:3ac30495.1897028@newsgroups.borland.com...

Quote
> >The only solution I know which works for ALL cases
> >is to write code which adjusts things according to the screen height and
> >width factors at run time. It's a maintenance issue, but the results are
> >reliable.

> This is what I was trying to do with the procedure of my previous post.
But I
> then found out that using screen height and width is not enough. One also
> has to take into account whether Small fonts or Large Fonts are being used
> and how each type of control will be affected by this choice.

The best component I have used for this issue is ElasticForm, from QSystems.

http://home.flash.net/~qsystems/

It's not perfect, but comes pretty close.

Bill

Re:Solving the resolution problem (2nd post)


On Thu, 29 Mar 2001 03:44:21 -0800, "William Meyer" <wme...@earthlink.net>
wrote:

Quote
>The best component I have used for this issue is ElasticForm, from QSystems.

>http://home.flash.net/~qsystems/

>It's not perfect, but comes pretty close.

Thanks for the information. I also noticed, on their Web page, that  they
have a component QSLabel for subscripts, superscripts, and Greek
letters. This looks interesting.

        Andre

-=-
Rem: For my email address, you need to remove the 'nojunk.'
     from what appears in the header.

Re:Solving the resolution problem (2nd post)


Quote
On Wed, 28 Mar 2001 11:11:47 +0200, "p " <francescos...@tiscalinet.it> wrote:
>Hi , i already answered to a similar question on this newsgroup :
>i have copied and pasted the previous answer :

Thanks for the listing.

Quote
>Sorry but i have no much time to compare my code with yours ,

Some  important differences are that
    -  you don't use the ScaleBy procedure
    - you are using the PixelsPerInch property when calculating the
      the scaling factors.

Quote
>However if you test the code on your Pc screen you can write me a report of
>what you see ,thanx .

I tried it with one of my applications. The overall appearance is very good
but there are some problems:
    - two of the (regular) labels are cut off : their right and bottom portions
      are missing
    - in addition to this, I use small images on which text is being written.
      This is the only way I can get subscipts and mix Greek letters with
      ordinary characters. Their bottom portions are also cut off.
This is when going from 1024*768 Small fonts to 800*600 Small Fonts.
But maybe, one of the parameters in the Object Inspector is not set
correctly.

I guess there is no simple overall solution to this problem. Strangely, the
best results I got so far were obtained when I didn't try to resize the form
and each of its controls. I have, however, to make some compromises
between the Small Fonts and the Large Fonts settings. And when these
design time compromises are not good enough, some code has to be
added to rescale at run time just the most offending controls. But it is a
case by case approach.

Thanks again.

        Andre

PS: Maybe I am missing something but, in your listing, variable classref is
    not used at all.

-=-
Rem: For my email address, you need to remove the 'nojunk.'
     from what appears in the header.

Other Threads