User Tools

Site Tools


Changing a control's colours

by Richard Russell, September 2007

You will normally want dialogue box controls to use their default colour scheme, for reasons of uniformity with other Windows applications, but occasionally you may want to change the foreground and/or background colours for special purposes. There are a number of techniques that can be used to achieve this, for example you can create a coloured Edit Box by using a Rich Edit control or you can create a coloured Static Control by drawing into a suitable bitmap and displaying it in a picture box or you can use a custom graphics control.

This article describes an alternative technique, involving subclassing the dialogue box using the SUBCLASS.BBC library (version 1.3 or later). In some ways it is more flexible than the other methods, since it allows you to change the colours of other controls, not just Text Boxes and Static Controls. To illustrate the effect the program listed below creates this rather garish dialogue box:

Firstly we need to install a couple of libraries and define some constants:

        INSTALL @lib$+"WINLIB2"
        INSTALL @lib$+"SUBCLASS"
        INSTALL @lib$+"NOWAIT"
        LB_ADDSTRING = &180
        WM_CTLCOLORBTN = 309
        WM_CTLCOLORDLG = 310
        WS_GROUP = &20000
        WS_BORDER = &800000

Note that version 1.3 or later of SUBCLASS.BBC is required.

Next we can create the dialogue box template in the usual way:

        dlg% = FN_newdialog("Dialogue box", 20, 20, 160, 128, 8, 560)
        PROC_listbox(dlg%, "", 101, 10, 8, 140, 80, 0)
        PROC_static(dlg%, "Static box", 102, 10, 82, 140, 20, WS_BORDER)
        PROC_pushbutton(dlg%, "OK", 1, 12, 108, 56, 14, WS_GROUP + BS_DEFPUSHBUTTON)
        PROC_pushbutton(dlg%, "Cancel", 2, 92, 108, 56, 14, 0)

So far everything is conventional, but now we sub-class the necessary Windows messages:

        PROC_subclassdlg(dlg%, WM_CTLCOLORLISTBOX, FNctlcolorlistbox())
        PROC_subclassdlg(dlg%, WM_CTLCOLORSTATIC, FNctlcolorstatic())
        PROC_subclassdlg(dlg%, WM_CTLCOLORDLG, FNctlcolorbackgnd())
        PROC_subclassdlg(dlg%, WM_CTLCOLORBTN, FNctlcolorbackgnd())

Note that in this particular case the same function is used for both the CTLCOLORDLG and CTLCOLORBTN messages because in each case all we want to do is change the background colour. If you don't change the background colour of the buttons to match the dialogue box background an ugly border around the buttons will be visible.

Now we can display the dialogue box and initialise any controls that need it:

        SYS "SendDlgItemMessage", !dlg%, 101, LB_ADDSTRING, 0, "Listbox item 0"
        SYS "SendDlgItemMessage", !dlg%, 101, LB_ADDSTRING, 0, "Listbox item 1"
        SYS "SendDlgItemMessage", !dlg%, 101, LB_ADDSTRING, 0, "Listbox item 2"
        SYS "SendDlgItemMessage", !dlg%, 101, LB_ADDSTRING, 0, "Listbox item 3"

Again, this is conventional.

Finally we run our main loop which, for the purposes of the exercise, does nothing useful:

        ON CLOSE PROC_closedialog(dlg%) : QUIT
        ON ERROR PROC_closedialog(dlg%) : SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : QUIT
        ON SYS Click% = @wparam% AND &FFFF:RETURN
        Click% = 0
          click% = 0
          SWAP Click%,click%
        UNTIL click%=1 OR click%=2 OR !dlg%=0

Note that while subclassing is in effect you must avoid statements which may take a long time to execute, such as GET, INKEY, INPUT and WAIT (WAIT should be avoided even if the delay is short). You should also be careful not to use SOUND when the sound queue is already full. You can find suitable replacements for these functions in the NOWAIT library.

We mustn't forget the vital routines that handle the subclassing:

        DEF FNctlcolorbackgnd(M%, W%, L%)
        PRIVATE B%
        IF B%=0 SYS "CreateSolidBrush", &8080FF TO B%
        DEF FNctlcolorlistbox(M%, W%, L%)
        PRIVATE B%
        SYS "SetTextColor", W%, &00FFFF
        SYS "SetBkColor", W%, &336633
        IF B%=0 SYS "CreateSolidBrush", &336633 TO B%
        DEF FNctlcolorstatic(M%, W%, L%)
        PRIVATE B%
        SYS "SetTextColor", W%, &FFFFFF
        SYS "SetBkColor", W%, &663366
        IF B%=0 SYS "CreateSolidBrush", &663366 TO B%

The colours are here specified in the usual Windows hexadecimal “BBGGRR” format. For the listbox and the static control both the foreground and background colours are set. You should normally set the text background colour (“SetBkColor”) to be the same as the control's background colour (“CreateSolidBrush”).

Note that in the above example all controls of a particular type are affected. For example, if the WM_CTLCOLORSTATIC message is processed then all Static Controls will change colour. If you want to change the colour of only a subset of the controls of a given type, or give them different colours, then you can test the control's handle and act accordingly:

        DEF FNctlcolorstatic(M%, W%, L%)
        CASE L% OF
          WHEN hStatic1%:
            PRIVATE B%
            SYS "SetTextColor", W%, &FFFFFF
            SYS "SetBkColor", W%, &663366
            IF B%=0 SYS "CreateSolidBrush", &663366 TO B%

Here hStatic1% is a global variable containing the handle of the particular Static Control whose colour needs to be changed. Because that handle isn't known until after you have shown the dialogue box, you will need to force the static control to redraw itself:

        SYS "GetDlgItem", !dlg%, 102 TO hStatic1%
        SYS "InvalidateRect", hStatic1%, 0, 0

Also, remember to initialise hStatic1% (e.g. to zero) so you don't get a 'No such variable' error when FNctlcolorstatic is called for the first time.

This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
changing_20a_20control_27s_20colours.txt · Last modified: 2018/04/15 18:15 by richardrussell