Scaling your form independent of screen resolution
Don't you hate it when you go to great lengths to design your forms just so, and then see it on a radically different screen resolution and it looks terrible? Would you like to be able to easily set your forms to resize themselves based on screen resolution? If so, then this code is for you.
Note that this isn't the first code to make this claim, but hopefully it will be the last. Many don't seem to realize how involved this task really is, and so offer solutions that aren't very robust.
I'll admit right now that I haven't added support for every possible control; so many have their own quirks. But I am happy to add support for specific controls you need added.
Note that this code is extremely involved. I'll explain in detail how it works in the following posts. For now, just some basic instructions and the code.
For each form you want to be resolution-independent, simply add the following line of code to the Form_Load() event:
FormLayout Me
There are many additional tweaks you can do, but that's all you really need to get started. Everything is handled by the one (very long) function. Here's a module that contains the main function, plus several more useful routines if you want to get serious about making your forms truly resolution-independent.
Last edited by Ellis Dee; May 29th, 2008 at 10:45 PM.
Every attempt at this that I've seen takes what I consider to be a flawed approach. They start with the premise that the ratio of the change in resolution can be applied directly to the forms and controls. This simplistic approach will yield subpar results because fonts don't scale in a uniform manner.
For example, text in Verdana 10 is 240 twips high, and text in Verdana 11 is 270 twips high. While the font size increased by 10%, the screen space used to display it increased by 12.5%. Thus, I consider any solution based on screen ratios to be fundamentally flawed.
My solution uses fonts as the fundamental sizing ratio. The idea is to start by deciding how many lines of text you want to fit on the screen, regardless of screen resolution. It doesn't matter if your form doesn't fill the whole screen; the concept of "lines on a screen" is merely a theoretical approach. The function starts by figuring out (through a laborious looping process) what the maximum font size is that will still fit the desired number of lines on the screen. This is the target font size.
Let's look at Verdana 10 on a 1024x768 resolution for an example. As previously noted, Verdana 10 is 240 twips high, or 16 pixels. 768 / 16 is 48, so if you designed your application in 1024x768 resolution, and you used Verdana 10, then you're designing for 48 lines on a screen.
Once the target font size has been identified, the function looks at the form's font size. If it's already set to the target size, nothing needs to be done and it skips doing anything. If the sizes are different, the function first calculates the resizing ratio based on the difference between the text size of the two fonts, and then kicks into high gear.
This is where things get complicated.
Last edited by Ellis Dee; May 22nd, 2008 at 09:33 PM.
Several controls present unique challenges. The function currently handles the following:
Listbox: Listboxes will only resize in vertical increments that display entire rows; if you try to resize a listbox a few pixels smaller, it will snap down an entire row. Multiple generic resizings will quickly shrink a listbox down to nothing. So what we first need to do is identify how many lines of text the listbox originally displayed. Then we need to identify how much "extra space" is used by its borders. Once we know that, it's a simple matter to resize it based on NumberOfLines * TextHeight + ExtraSpace.
Combobox: Comboboxes cannot be resized vertically; their height is determined by the font size. This isn't much of a challenge, except for the fact that it's fairly common to have textboxes and comboboxes on the same form. Many programmers try to keep them the same height for a nice unified look, but autoresizing routines tend to break this symmetry. So this solution will size the height of textboxes equal to the height of comboboxes if (and only if) there is at least one combobox on the form.
Textbox: Even the lowly textbox can add complexity if it is set to multiline.
Optionbutton, Checkbox: These are possibly the most irritating controls to deal with, because they contain graphics elements that don't change size when the font grows or shrinks..
SSTab The SSTab control is annoying for resizing routines because of the way it handles tabs. Instead of having actual tab objects, it simply moves controls from hidden tabs 75000 twips left.
Line: Lines don't have height and width properties, so they have to be handled separately.
Last edited by Ellis Dee; May 22nd, 2008 at 07:29 PM.
One issue is quite simple but often overlooked. Regardless of font sizing or screen resolution, the form's titlebar never changes size. Let's say your form is 100 pixels high with a 10 pixel titlebar, and you want to size the form 25% larger. If you simply up the form to 125 pixels, you've actually increased the height by 27.8%, not 25%. That's because the usable space of the form was increased from 90 pixels to 115, not 100 to 125. You have to resize the usable region, not the entire form.
You really want it to end up 122 pixels, not 125. This may not seem like much of a difference, but it's not subtle when you see it in practice. Generally speaking, the bottom-most section of the form will seem out of proportion and awkward if you base the resizing on the form coordinates instead of the scale coordinates. In the picture below, the blank space under the row of command buttons is intended to be the same height as the space between them and the frame above.
No matter how robust an automated routine is, there are still quirks that need to be handled on a form-by-form basis if you want a polished look. Look at the following form to see an example of several problematic issues that arise when you try to automate resizing:
This screen was designed in 1024x768 using Verdana 12. It was resized using the posted function and displayed in 800x600 resolution. Ignoring the previous-century color scheme, consider what exactly has to happen to resize this screen:
Resizing option buttons is a tricky affair. The graphical portion never changes size regardless of font, so that has to be taken into account. If you ignore that, then shrinking an option button can and will chop off some of the caption text. (Same idea as the form's titlebar issue described above.)
The "Rows" label is left-aligned to be directly under the caption of the option buttons. Note that it's off by one pixel; this is as close as I can seem to get it. Any help on this would be appreciated.
The "Rows" label has an etched appearance when disabled. This is achieved by using two label controls. One has normal text and transparent background. The second one has white text, and is placed behind the first one offset by one pixel below and to the right. This one pixel offset must never change, regardless of the font size.
The bottom of the text in the "Rows" label perfectly aligns with the bottom of the text in the "Rows" textbox.
The UpDown control interferes with resizing its buddy control, so it needs to be un-buddied before sizing, then the textbox needs to be wide enough to hold both its expected text and the buddy control. Only then can the UpDown be "buddied" to it.
The graphical command button shouldn't be resized at all.
The label describing the graphical command button should be centered vertically next to the command button.
The utility function uses Advanced Features to handle unique cases. In order to engage the advanced features, you have to use the control's .Tag property. Unfortunately, if you are already using the .Tag property for something else, this presents a conflict.
The first major hurdle in implementing advanced features is that the function needs to know which controls "belong" to each other. For example, which label goes with which textbox. In order to avoid making the programmer set Tag properties for every control, the TabIndex property is used. When the function iterates through all the controls on a form, it does so in TabIndex order, so be sure you have set the TabIndex properly. (Which you should always do regardless.)
Last edited by Ellis Dee; May 23rd, 2008 at 06:59 PM.
The following .Tag codes are currently recognized:
Fixed
The control will not be resized, but it will be repositioned. This is useful for images, or any control that uses a graphic instead of text. (eg: Graphical-style Command Button)
Multiline
Some controls (Label, OptionButton, TextBox) are autosized based on the font width and/or height instead of absolute ratio. This can cause problems for multi-line controls that use word wrap. Use the Multiline tag to skip the font-based resizing and just use absolute resizing.
Left
If the previous control is an OptionButton or CheckBox, align with its caption left instead of the control's left. This lets you align "subitems."
Right
Position this control to the right of the previous control on the same line. If the control is a TextBox and the previous control is a Label, this setting will line them up vertically.
Label
If the previous control is a Label, this setting will move the label down slightly to align the text bottom.
Etched
Signifies an Etched label, which simulates the etched effect on disabled controls like checkboxes. To use this effect, set the main label's background to transparent, add a new label with the same caption, set its ForeColor to white, set its ZOrder behind the main label (send to back), and set its Tag property to Etched. Be sure the etched label is immediately after the main label in TabIndex order.
Last edited by Ellis Dee; May 23rd, 2008 at 07:02 PM.
Even without the very long comments that go with the function, the function is too long to fit in a single post. So here are the comments that preface it, plus the first part of the function -- basically just declaration and initialization:
vb Code:
' FormLayout()
' Resize a form and all its controls based on screen resolution.
' All controls are resized in TabIndex order. Advanced positioning lets you
' position a control based on the previous (in TabIndex order) control's
' newly resized coordinates. Set any control's Tag property to one of the
' following (without the quotes) to engage advanced positioning.
' "Fixed"
' The control will not be resized, but it will be repositioned.
' "Multiline"
' Some controls (Label, OptionButton, TextBox) are autosized
' based on the font width and/or height instead of the overall ratio,
' causing problems for multi-line controls that use word wrap. Use
' this to skip the font-based resizing and just use generic resizing.
' "Left"
' If the previous control is an OptionButton or CheckBox, align with
' its caption left. This lets you align "subitems".
' "Right"
' Position this control to the right of the previous control on the
' same line. If the control is a TextBox and the previous control is a
' Label, this setting will line them up vertically as well.
' "Label"
' If the previous control is a Label, this setting will move the label down
' slightly to align the text bottom.
' "Etched"
' Signifies an Etched label, which simulates the etched effect on
' disabled controls like checkboxes. To use this effect, set the main
' label's background to transparent, add a new label with the same
' caption, set its ForeColor to white, set its ZOrder behind the main
' label (send to back), and set its Tag property to Etched. Be sure
' the etched label is immediately after the main label in TabOrder.
' Parameters:
' pfrm
' The form to be resized.
' psngFontSize can be either:
' - The new font size for the form and all its controls. Font sizes can
' be multiples of 0.25.
' - A negative value (eg: -46) to calculate the new font size based on how
' many lines of text can fit on a full screen in the current resolution.
Re: Scaling your form independent of screen resolution
Wow, looks like you spent a good deal of time on this, not just the bas module but also your posts explaining it. A working example (with a form) would probably help beginners.
Re: Scaling your form independent of screen resolution
Originally Posted by Edgemeal
Getting a Variable not defined: glngHeight
Public Function GetFontSize,
@ line, If glngHeight <> 0 Then lngHeight = glngHeight
Oops, my bad. You can just delete that line; it shouldn't be in there.
It's a public variable used for debugging purposes only. That line allows you to see how it will look in other screen resolutions by setting it to the height in pixels of the resolution you want to test.
So if you set it to 768, it'll resize as if it's in 1024x768 resolution, 1024 will give you the results for 1280x1024, etc...
Re: Scaling your form independent of screen resolution
Try putting FormLayout Me in the Form_Load() event and see how it looks. You can play around with the font size by specifying the (negative) number of lines to fit on the screen. The default is 46. Meaning the following two lines are identical:
FormLayout Me
FormLayout Me, -46
If you specify a positive number it will use the number itself for the font size, which isn't what you want. Instead, use a negative number to specify the number of lines to fit on a screen:
FormLayout Me, -44 ' a little bigger
FormLayout Me, -48 ' a little smaller
Re: Scaling your form independent of screen resolution
I cannot find the difference when I used the method. Have a look at the attached zip file, I used my own function, the form is supposed to have been design in 800x600 resolution and it will scale to that size when it is used in larger resolutions. I supposed that is how your method should work?
Regards,
™
As a gesture of gratitude please consider rating helpful posts. c",)
Re: Scaling your form independent of screen resolution
The problem is that MS Sans Serif doesn't scale very well. If you look at its valid sizes, there is a much smaller range than there is with other more robust fonts. I prefer Verdana myself.
The problem (when using MS Sans Serif) is in the font scaling section, which is at the end of the first code box upthread. This section of code is:
Code:
Do
psngFontSize = .FontSize
' Font sizes have erratic increments; identify the next size up
.FontSize = .FontSize + 0.25
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.5
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.75
If psngFontSize = .FontSize Then .FontSize = .FontSize + 1
If psngFontSize = .FontSize Then Exit Do
Loop Until lngScreenHeight \ .TextHeight(Spacer) < lngLines
The problem is that it never adds more than 1 at a time, and if that doesn't register a change the function aborts and does nothing. Since the jump from 8 (8.25) to 10 (9.75) is more than 1, nothing ever happens. The fix is to add a couple more lines to that loop like so:
Code:
Do
psngFontSize = .FontSize
' Font sizes have erratic increments; identify the next size up
.FontSize = .FontSize + 0.25
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.5
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.75
If psngFontSize = .FontSize Then .FontSize = .FontSize + 1
If psngFontSize = .FontSize Then .FontSize = .FontSize + 1.5If psngFontSize = .FontSize Then .FontSize = .FontSize + 2If psngFontSize = .FontSize Then .FontSize = .FontSize + 3
If psngFontSize = .FontSize Then Exit Do
Loop Until lngScreenHeight \ .TextHeight(Spacer) < lngLines
This should probably be in there always, but I'm comfortable not updating the original code because IMO using a sparsely-sized font like MS Sans Serif is contraindicated when designing scalable forms.
Re: Scaling your form independent of screen resolution
i'm sorry i don't understand this..
what do you mean ellis?
do you mean my app which i made on my 1280x960 screen resolution will look ugly on other screen resolution?
i test my app on my brother's laptop which the screen resolution is 1366x768, and everything looks fine..
Re: Scaling your form independent of screen resolution
Those are basically the same resolutions. How does it look on 800x600?
If you use MS Sans Serif, there are very few different sizes you can use, meaning when you switch to radically different resolutions it won't look very good. A more scalable font like Verdana or Tahoma would be better.
Re: Scaling your form independent of screen resolution
I know this thread is dead and sorry for bothering you all but could someone please help or preferably post a working example of this code, because I try integrating the code 'FormLayout Me' in each form and it simply does not affect the form.