Paint It (Almost) Black

In a previous post, I showed an ugly form. Ugly, because it looked awful when I ran the form with the Windows High Contrast Theme.

With the High Contrast Theme, normal black text appears yellow. Which is no problem at all when the text is drawn on a black background. But in my form, the text was drawn over a white shape control, and looked like this (the red arrows point to the yellow text):

Yellow text on a white background

Normal black text turns yellow in High Contrast #1 Theme.

So now I have a form that is unreadable in High Contrast. What I want to do is force Windows to draw the text black (since it is drawn over the white background).

 

There’s An Easy Fix For That!

This is simple to do. I set the ForeColor of the labels that I want to appear as black to RGB(2,2,2). This color change from RGB(0,0,0) is imperceptible to the human eye (it still looks black), but Windows sees it as an absolute color. And since I have changed it to something other than the default, Windows will display the label in my “near-black” color (since it is not the “Default”).

After my session at Southwest Fox, a couple of people said they do the same thing I do to force a label to be black, but they use RGB(1,1,1). Not sure why I picked 2,2,2 – but they’re both “black” to the naked eye — and either setting works fine.

Here’s an example of an instance of my “near-black” label on a form (the top label ForeColor is RGB(0,0,0) – the Default), while the label inside the white shape has a ForeColor of RGB(2,2,2) – or, as I like to call it, “forced black”:

Two labels, two different ForeColors, same effect.

Two labels, two different ForeColors, same effect.

And the same form, this time running in Windows High Contrast Theme:

The "near-black" label stays black

The “near-black” label stays black.

Later in the series, we’ll look at creating sub-classes for different controls. This one I’ll call the lblForceBlack control, subclassed from a base Label class.

Respecting The User’s Font Settings

Updated December 16, 2013: Source code from this post is available here.

All versions of Windows have a “system font”, which is used for menus, title bars, messageboxes, etc.

The Windows XP system font (except for a couple of Windows Classic themes) is Tahoma.

The system font for Windows Vista, Windows 7, and Windows 8 is Segoe UI.

I’ve seen apps which use a variety of fonts within the application. Some may use Arial for labels, but Courier New (or some other font) for all data-bound controls. I’ve seen arguments online about the pros and cons of using multiple fonts. For myself, though, I just don’t like seeing a mix-and-match approach to fonts in an app. The app menu and form captions will have the Windows system font, and the form itself may have two or three different fonts. This is simply too much for my old eyes (and slow brain) to take in.

This is, of course, a personal preference. I’m not making any “right” or “wrong” statements here — just sharing my opinion.

Since I want my apps to have a level of consistency and a professional Windows look and feel, I like for my forms and form objects to use the same font that Windows is using.

In an effort to “define the lowest common denominator”, I’ve decided to use Tahoma exclusively in Windows XP, and Segoe UI in Windows Vista and later.

In Doug’s Windows 7 session, he showed how he added code in the Init event of classes to change the font to Segoe UI if the user is running Windows Vista or later. I do the opposite: I check the OS and change the font to Tahoma if the user is running a pre-Vista version of Windows. This is again a personal preference; since I do my development work in Windows 7, I like to see the Segoe UI font while I’m doing my dev work.

Doug has posted a LOT of his whitepapers, articles and sample code on his web site. Comments about Segoe and Windows 7 can be found in this whitepaper.

It was mentioned during one of my sessions that if I am working on a team, and any members of the team are using Windows XP (or earlier), I’d want to develop in Tahoma exclusively and follow Doug’s method of switching to Segoe UI at runtime. An excellent suggestion!

 

Does The User Want Large Fonts?

I now have a way of ensuring my apps use one particular font. Now we need to see if the user has told Windows that she would like to use large fonts. I try to determine if the user wants to use large fonts for one simple reason: if the user wants large fonts, she usually has a reason (large monitor with high resolution, personal comfort, or perhaps she has a disability and needs to use large fonts). This way, my app can resize the forms and form controls automatically, to match the users needs.

With a couple of Windows API calls, I know right away if the user has selected large fonts in Windows. I’ve used the code listed below in the past for determining the font size setting, slightly modified from an article Doug Hennig wrote several years ago:

LOCAL liHDC, liPixelsPerInchX, ;
      liPixelsPerInchY, lnFontFactor

DECLARE INTEGER GetDC IN Win32API ;
   INTEGER iHDC

DECLARE INTEGER GetDeviceCaps IN WIN32API ;
   INTEGER iHDC, INTEGER iIndex

#DEFINE cnLOG_PIXELS_X 88
#DEFINE cnLOG_PIXELS_Y 90

liHDC = GetDC(ThisForm.HWnd)
liPixelsPerInchX = GetDeviceCaps(liHDC, cnLOG_PIXELS_X)
liPixelsPerInchY = GetDeviceCaps(liHDC, cnLOG_PIXELS_Y)

IF liPixelsPerInchX <= 96
   ** The user has selected "normal" font size
   lnFontFactor = 1
ELSE
   ** The user wants to use large fonts. The
   ** calculation will determine how large
   ** (by percentage) the fonts should be.
   lnFontFactor = 1 + ((liPixelsPerInchX - 96)/96)
ENDIF

MESSAGEBOX("The DPI 'font factor' is: " + ; 
           ALLTRIM(TRANSFORM(lnFontFactor)),0,"Font Factor")

This code simply calls Windows and says, “Hey Windows, what’s the current DPI setting?” and displays the percentage I should bump up my visual controls by in order to match the users settings.When I run the code in Windows XP, with DPI set to the “normal” 96dpi, I get the following:

Font Factor for 96dpi in Windows XP

Font Factor for 96dpi in Windows XP

A “font factor” of 1 means I don’t need to do any resizing of any forms or form objects.

Setting the DPI in Windows XP to 120dpi results in this:

Font Factor for 120dpi in Windows XP

Font Factor for 120dpi in Windows XP

A “Font Factor” of 1.25 means the user wants to see things larger than the “normal” 96dpi, so I need to resize all of my visual controls in the app to be 25% larger.

For good measure, here’s the result when the DPI is set to 144dpi:

Font Factor for 144dpi in Windows XP

Font Factor for 144dpi in Windows XP

In this case, I’ll want to resize all of the visual controls by increasing their size by 50%.

So now it’s just a matter of resizing all controls on my form by multiplying the design time font size by the “font factor”.

Of course, I’ll also need to resize the forms height and width by the same percentage, and “move” each control accordingly.

I’ll be adding a class (cusResizer) for this series which automatically performs the calculations and resizing of forms and form objects. It will be available for download soon.

And, we’re done!

Well, not quite yet.

The code above works fine in XP.

But, how does it do in Vista and Windows 7 & 8?

That depends

 

 

 

Respecting The User’s Color Settings

Before we talk about color settings, it’s important to know upfront where Visual FoxPro gets the default values for forms and form objects.

Have you ever wondered where the VFP IDE comes up with its default colors for forms (and other objects)? They come right from the Windows API.

According to the VFP Help File: “The color settings, or Themes, of the operating system set the default color settings for the BackColor and ForeColor properties.”

This explains why, on my machine, when I create a new form in Windows 7 the properties sheet contains the following (BackColor = 240,240,240):

Default form BackColor on my Windows 7 machine

The default BackColor for a new form on my Windows 7 machine is 240,240,240

The BackColor property depends completely on the current color scheme (theme) I’m using in Windows at design time. If I am set to Windows Classic in Windows 7, the BackColor is different. If I decide to punish myself and create a new form while the High Contrast (Black) theme is running, the default BackColor will be 0,0,0.

When I open this form in Windows XP, I get a different BackColor:

Default form BackColor on my Windows XP machine

The default BackColor of a new form in XP (depends on your theme)

What this means is if I do not change the BackColor of a new form, even if I created the form in Windows 7 with an Aero theme, my form BackColor will match whatever theme I’m using in other versions of Windows (and Windows themes) at design time and runtime – without me having to do anything!

In short, “Your Default BackColor = the Windows API System Color”.

This is pretty powerful stuff. In Windows 7, I’ve created the form pictured below. I left the BackColor property as the Default. When I run it in Windows 7, I see this:

Same BackColor as my default

Just as I expected. The exact same BackColor as the default in my design environment.

When I run the same form on Windows XP (with the Windows XP Blue Theme), I get this:

A bit different

It’s different, but the same

It’s different, but it’s exactly what Windows wants the BackColor to be, based on the theme.

When I change the XP theme to Windows Classic Spruce, I get this:

Perfect!

Perfect! And I didn’t have to change a thing!

And once again, the BackColor matches the Windows theme at runtime. All without a single property change or a single line of code!

I wonder what happens when I make a change to the BackColor?

I flip back to my Windows 7 dev machine, change the BackColor to 192,192,192, save and run the form – and here’s what I see:

Big deal. It's exactly what I told it to be, right?

Big deal. It’s exactly what I told it to be, right?

And running the same form on XP (again with the Blue Theme):

Same BackColor as Windows 7, because I told it to change

Same BackColor as Windows 7, because I told it to change

Whew! I’ve set my form BackColor to 192,192,192, and it looks relatively the same on my Windows 7 and Windows XP. So, I’m done, right?

Not quite. I changed my theme in Windows XP back to “Spruce”:

That's different. REAL different. And, dare I say it? Ugly!

That’s different. REAL different. And, dare I say it? Ugly!

OK, I don’t like that. So, I’ll just jump back into VFP and change the color back to what Windows 7 said the default should be: 240,240,240.

Let’s see it in Windows 7:

And we're back to the default! Or, are we?

And we’re back to the default! Or, are we?

So far, so good. Let’s see how it looks in Windows XP “Spruce”:

What happened? I changed it back to the default!

What happened? I changed it back to the default!

I expected my form BackColor to pick up the Windows theme again. But, it didn’t. Let’s take a look at the property sheet:

Hmm... It's the Default, but it's not the "Default"

Hmm… It’s the Default, but it’s not the “Default”

When a property is shown in Bold in the VFP Properties window, it’s not the Default – even if the value is the same as the Default value you expected.

So, how can we get it back to the way it was originally? Reset to Default. Right-click the property in the Properties window, and select “Reset to Default” from the context menu:

Fixed. Finally!

Fixed. Finally!

 

So, what’s the big tip for forms and form objects?

Don’t touch the default values for “color” properties if you want your forms (and form objects) to be consistent with Windows themes.

If you do change them, then later decide to go back to the “Default”, make sure you “Reset to Default”!

Just in case you need more evidence of just how ugly the form is when the BackColor is not set to the Default (i.e. Windows System Color), here’s the same form in High Contrast with the BackColor set to 192,192,192:

At least the label and the button used the correct colors.

At least the label and the button used the correct colors.

After a “Reset to Default”, the form looks like this:

Whew, that's better!

Whew, that’s better!

As you can see from the previous images, the BackColor, ForeColor (in fact, all of the color properties) are tied to the Windows System Colors at runtime – but only if their values are set to their Default properties!

Respecting User’s Windows Settings

I know, you’ve probably heard this a million times before in books, articles, and other conference sessions. I’ve said it, preached it, and tried to practice it, but I often find myself short on respecting Windows settings (remember the high contrast theme?).

This tip is exactly what I was talking about in the “quick note about this session.”

I’ve always taken great pride in my UI design (right or wrong, and many times I’ve been wrong), and I had planned for this session to show you something pretty. But as I worked on the session (and re-worked it again, several times) I found that some things I built that looked pretty to me could be very ugly to others.

During the working and re-working, I found myself going back to the Microsoft UX Guide many times.

The Microsoft UX Guide for Vista and Windows 7 contains the following statements about user settings (on page 621-622):

  • Accessibility and the system font, sizes, and colors
    The guidelines for making text accessible to users with disabilities or impairments can be boiled down to one simple rule: Respect the user’s settings by always using the system font, sizes, and colors.
  • If you do only one thing…
    Respect the user’s settings by always using the system font, sizes, and colors.

During the course of preparing this session, the guideline above went from being an afterthought to a driving principle.