Link to home
Start Free TrialLog in
Avatar of jkb2
jkb2

asked on

Screen Sizing

I have a program that I want to accomodate ALL screen sizes/font sizes and am a little lost. I designed my screens at 640x480 and have a routine that "resizes" everything when the screen resolution changes from the original developed size (640x480).

This seems to work pretty good except when I try to change the font sizes (ie. 800x600 Large Fonts). As you can guess it goes crazy. The main window doesn't size correctly at all. and as a result, the new screen looks crazy!!!

Is there a way to accomodate for screen resolution to include font sizes?

Any help would be much appreciated.
ASKER CERTIFIED SOLUTION
Avatar of ronit051397
ronit051397

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of millerw
millerw

I tried good ol' Lloyds example code and ended up with some really weird results.  Eg my form ended up being really small on the screen and the fonts were really large.  I found that most of his text helps but the font stuff is a bunch of bull.  Here is what I did.  First, DON'T SCALE THE FORM.  That only causes problems.  Leave the form the way it was designed and make it DefaultPosOnly or something like that depending on your needs.  DON'T USE THE DESIGNED POSITION--CAN LEAD TO MAJOR PROBLEMS.  Then put this code in a unit that can be shared by all your forms:

procedure ResolutionResolver (Form: TForm);
begin
     Form.Font.Size := (ScreenWidth div LongInt(Screen.Width)) *
                       Form.Font.Size;
     Form.Invalidate;
end;

(Call this in the Create event of a form and give it Self as its parameter.)

Where ScreenWidth is the same thing as in Lloyd's example.  That will fix the fonts.  EXCEPT UNDER ONE CONDITION!

Here is the condition:  If you have a label or something else and it is not visible (eg behind a panel that is poped up later or on a tab that will come up at the user's choice) the object will NOT RESIZE EVEN WITH AUTOSIZE ON.  To fix this, you must reassign its caption after you run the resolution resolver above so that it will resize.  A better way is to use panels instead of labels when you can.  They will not mess up like this at all.  Well, they might but I always give my panels an alignment (eg top, bottom, left, right, or client).  

Panels are the best, especially if you want fully resizable forms.  You can make the objects move smaller and bigger with your panels if they are given some alignment other than None.  Additionally, if the form is fully resizable, it is not afftected by resolution problems.  TLabels are the worst and using a Tpanel solves this (just set its caption to what ever you want and align it to center, left or right then put your TEdit or whatever at least 4 pizels away from the text in the TPanel).  

If you want an example of a fully resizable form that has no problems with resolution, I can supply you with one and let you see how to design forms so they are all not affected by resolution.  (The form I'm designing now doesn't even use the Resolution resolver function and works on any resolution---having the computer handle all your resolution problems automatically is the best way of doint it).  

The main point to making worry free resolution changing forms is to use TPanel extensively and use its OnResize event to resize any TEdits or TLabels (I recommend never using the TLabel anyway) as needed.  Not a whole lot of code is required.  Lloyd's example is good, and don't get me wrong here---his example got me started on making non-resolution specific forms, but uses alot of code to do the job that the forms can do themselves.  

Additionally all components can be made to have the Align property available to you (eg TEdit normally doesn't have it available) by deriving a new component from it and making the Align property published.  I have example code for this too----really, really simple to do.

Let me know if you want example code and example programs on how to do all this stuff.  It is all simple to do, except when you have designed your froms already and have not done them the right way (I'm going to have to go back and take out the TLabel components on one form to make it non-resolution specific).  

One more thing about TLabel, if you must use one, set its Align property to something other than None.  TPanel will do the same thing as a TLabel, that is why I am starting to move away from using a TLabel at all.

Get back to me if you still need help or want the code and example.

Good Luck,
Scott
Keep it simple when possible!

I use a much simpler method to make my applications
usable with a resolutions and fontsizes. It works fine for all fullscreen applications. 640*480, ..,1600*200, Large fonts
,small fonts, custom fonts, if the design font is not present on target computer, etc.  It just doesn't matter, because
everything needed is adjusted runtime..


This is my method:

I virtually divide the form in e.g. 20 or 40 verticale rows,
and in 5 or 8 horizontal rows (the number doesn't matter,
only depends on the desired layout).

Each screen element (labels, buttons, everything)
then must use exactly 1 or more verticale rows , and 1 or more horizontal columns.

So an element x has four variables defined:
xRowStart, xNumberof Rows, xColummStart, xNumberofColumns

When the application (or the resolution changes) starts,
the applicationt calculates all the needed left, top, width
and height variables for all the screen elements (using
a WinApi call to get e.g. Form.Caption.Height, and
Bordermeasures and beside that only screen.width and
screen.height).

The fontproblem is handled in a similar matter:
before the running program makes a string on the form, a label or whatever visible, I first measure the pixelwidth the string will have (can be done in numerous way, e.g. with a hidden label, with
a canvas property, a WinApi call). I know the pixelwidth
of the screenelement the string must be placed on (see
above). If the string doesnt' fits, I just reduce the fontsize
by one until till it fits (or till it fits on x% if I would want that ). (same goes for the pixelheight) (actuallly I use a smarter and faster algoritme,
but you get the idear.

That's all.
         
Doesn't sound simple to me.  Sounds like alot of "reinventing the wheel."  If you can get a computer to do it ALL BY ITSELF without a single line of code (which is what I was talking about) that is the better way as far as I'm concerned.  But, that is my opinion.  

About the only thing you have to be concerned about with my method, is to make sure all objects are aligned in some way (redefining components so that the Align property is available takes less than 1 min to do).  Additionally, with Delphi 3, they have expanded label with a few extra properties that make it easier and better to use in some cases than a Panel.  

I'm into letting the computer do all that it can do.  Therefore, if the computer can do it all by itself (and you are not restricted in placement by a virtual grid of some kind) then that is the method for me.  

Your method does sound interesting, and I'm always into learning.  If you want to share the code, it would be interesting to see how someone else did it.  But, if your the kind to keep an idea under wraps, then nevermind.

Good luck,
Scott
To millerw/Scott:

My method is simple, maybe by lack of knowlegde of delphi
but the amount of administration isn't that large, and the
clearity is nice. Offcourse there will be a better way to
do this. But this works (in any language).

I don't have a clear cut example without sending your a
complete program, which I won't, but some sample code will give your the idear.

Suppose I have a form with a Tbutton and a TEdit

Var YunitsEdit1: integer = 2;  
//number of vertical units Edit1 uses
      YposEdit1: integer = 4 ;  
//vertical unit where Edit1 starts
      YunitsButton1: integer = 1;
//number of vertical units Button1 uses
      YposButton1: Integer =8;
//vertical unit where Button1 starts.

..same for horizontal stuff

    Xtot: integer; // at full screen = screen.width
    Ytot: integer; // at full screen = screen.height
    Xeff: integer;
 // width effectively to be used
    Yeff: integer;
 // height effectively to be used

    Xstart: integer;
// where the leftmost side effectively starts
    Xend: integer;   // ~ ends
..same for the vertical stuff

xnumberofunits: integer;
// the effective area is divided into ~ parts
..same for the vertical stuff

// before any change to the screen and a startup I call

procedure PreCalcScreenLayout(var depends on your program,
but you can maKe it rather generic)
begin
Ytot:=Screen.Height;
Yeff:=Ytot - getsystemMetrics(SM_CYCAPTION) -
             2* getsystemMetrics(SM_CYBorder)-
             ...(depends on your program, e.g. menu height_;
Yunit:=Yeff div ynumberofunits;

Edit1Top:=trunc(YposEdit1 * yunit);
Edit1Height:= trunc(YunitsEdit1 * yunit);
Edit1width:=.. and so on (or use Tobject arrays)
end;

After PreCalcScreenLayout is GetMaxFontSize is called,
this one determines whether
all the text will fit onto the elements using the values
calculated by PreCalcScreenLayout and a proposed
font size: if not for each element the fontsize is reduced until it does.

So, I can runtime change e.g. numberofyunits to get a more
compressed screen, I can change the fontsize, it doesn't
matter, It will always fit, on any screen.
Maybe more intelligent methods will work too, but I dont'
like testing my programs in every possible screenlayout/resolution and so one.
Glad your happy with your method.  I dislike variables like you are using that only hold a value (even though the optimizer takes care of them if you do no calculations with them).  I personally couldn't do it your way, and enjoy the code.  Sorry to have to admit that.

By the way, how does your method handle form resizing and all?  It looks like your method would require a call to your function in the OnResize event of the form (or a panel thereof).  

Glad you are happy with your method.  To each his own, after all.

Good Luck,
Scott
To Millerw, to answer your question:

A resize by quickres e.g. I handle in this way:

procedure TForm1.WndProc(var Message: TMessage);
begin
inherited WndProc(Message);
If (Message.Msg = WM_DISPLAYCHANGE)
Then begin
     ProgMetric.PreCalcScreenLayout;
     SetScreenLayout;
     end;
end;

ProgMetric is the object that contains all the values
and functions that determine where a screenelement
should be placed. SetscreenLayout mainly only assigns
these values to the screenelements depending on the value of
the corresponding ProgMetric fields.
A resize of the form is handled in a similar fashion.

I got bored using other methods, when I saw my programs sometimes looking loosy on computers with a non-typical Windows setting
and/or resolution, was trying to fix that and having to test over and over again in all possible settingscombinations. That testing costed me more time then setting it up this way.
Furthermore I can not test how my program is going to look in
a e.g. 1400 by 1280 resolution, with Bloody as the systemfont. Now I know in advance. It will fit just fine.