dcsimg
Results 1 to 10 of 10

Thread: Colored Command Button

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Colored Command Button

    In a continuing effort to produce a better command button, I offer the attached. The original was adapted from Derp's Glossy Button post:
    http://www.vbforums.com/showthread.p...Command-Button

    The first step in improving the product was to reduce the amount of coding required. Instead of repeating each individual pixel code, I needed to load the base pixels into memory and use loops to paint them. The other alternative was to load the necessary bitmaps and use BitBlt. But that still meant looping through the bitmaps to change the color, so I opted for the first alternative.

    In order to accomplish this, I standardized the corners using a 16 x 11 Long array and removed the near white border that the original code created. I also modified the code to use Long variables instead of Doubles or Singles, as Longs are more efficient. There are however a few exceptions that required greater accuracy.

    I also found a better algorithm to apply different Hues to the button. The information and a good explanation of color application was found here:
    http://www.tannerhelland.com/3643/gr...algorithm-vb6/
    in a link called "How to Colorize an Image (in VB6)". Although these pages provided a decent explanation of the principles of color and the code to change the color, it did not provide an explanation of the principles of the math used. If anyone can direct me to such an explanation, it would be appreciated.

    The individual pixel colors were loaded into a 15 x 45 array using an included program called Colors.vbp, and saved into a file called Color.bin. The first time Button.exe creates a button, the file is loaded and read into memory as a Long array. The different Hues are applied to the vbBlue data to allow the buttons to change color. VbWhite is used to create the Gray color, and does this by changing the Saturation value (S1) to zero. I currently use vbGreen as the default color, vbCyan as the Mouse Over color, and vbMagenta as the Got Focus color. Got Focus has precedence over Mouse Over. Any valid Hue can be used, but the results are unpredictable and may require further error checking. Sticking to the standard VB colors is your best bet (vbWhite, vbBlue, vbGreen, vbRed, vbYellow, vbCyan, vbMagenta).

    There were several interesting quirks that I ran into. If the array element is zero, the present code ignores it. But if you remove that check, the pixel will be displayed black. Also notable was that pixels outside the area reserved for the button would not display. The window background would take precedence. You can verify this by commenting out the rounded corner code in "DrawButton" and removing the check for zero code in "DrawMACButton".

    The "DrawMacOSXColored" routine was used to develop "Colors.vbp". It is inefficient and not needed, but I left it intact in case you want to play with the base coloring (Blue). It is much easier to do it there and transfer the results to the data file later. This project was very time consuming, and reminded me once again why I don't particularly care to mess with graphics.

    What would be nice to add to this button would be a "Font" property, but I will leave that for another day.

    J.A. Coutts
    MACButton.zip updated 11/28/2019
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by couttsj; Nov 28th, 2019 at 06:57 PM.

  2. #2

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Re: Colored Command Button

    The Font property has bee added. It took me a while to get this working. The first problem was that every time I went to change the Font property, I would get an error message that it wasn't supported. It wasn't until I realized that it uses "Property Set" instead of "Property Let".
    Code:
    Private WithEvents Nfont As StdFont
    
    Public Property Get Font() As StdFont
        Set Font = Nfont
    End Property
    
    Public Property Set Font(ByVal mnewFont As StdFont)
        With Nfont
           .Bold = mnewFont.Bold
           .Italic = mnewFont.Italic
           .Name = mnewFont.Name
           .Size = mnewFont.Size
        End With
        PropertyChanged "Font"
    End Property
    
    Private Sub Nfont_FontChanged(ByVal PropertyName As String)
        Set UserControl.Font = Nfont
        Refresh
    End Sub
    
    Private Sub UserControl_Initialize()
        Set Nfont = New StdFont
    End Sub
    The next problem was that it would not remember any changes I made to the Font property. I tried many different things and finally got it to work by accident. What I failed to realize was that "StdFont" is specific to VB6/VBA.
    Code:
    Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
        Set Font = PropBag.ReadProperty("Font", Ambient.Font)
    End Sub
    
    Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
        Call PropBag.WriteProperty("Font", Nfont)
    End Sub
    I also added 3 color properties (ColorNormal, ColorHot, & ColorFocus). These are entered and saved as Long values for simplicity, so the easiest way to enter them is as Hex values.
    vbWhite = &H0
    vbRed = &HFF
    vbGreen = &HFF00
    vbBlue = &HFF0000
    vbYellow &HFFFF
    vbMagenta = &HFF00FF
    vbCyan = &HFFFF00

    J.A. Coutts

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,530

    Re: Colored Command Button

    In your Set Font method, why do you transfer the properties instead of simply: Set nFont = mnewFont ?

    Tip: When a property is an object, you can allow both Let & Set so the user can assign the property with/without using the Set keyword. It goes a little like this:

    Code:
    Public Property Let Font(mnewFont As StdFont)
        Set Me.Font = mnewFont 
    End Property
    Public Property Set Font(mnewFont As StdFont)
        If Not mnewFont Is Nothing Then
            Set UserControl.Font = mnewFont
            Set tFont = mnewFont  ' if this doesn't trigger your font change event, redraw button
            PropertyChanged "Font"
        End If
    End Property
    Public Property Get Font() As StdFont
        Set Font = tFont
    End Property
    FYI. Typically a control is assigned the container's Font when the control is first created, not some default font set during Initialize.
    Code:
    Private Sub UserControl_InitProperties()
        Set nFont = Ambient.Font
    End Sub
    Edited: You can offer your color properties a different way also, allowing user to choose from a list. Sample shown just FYI
    Code:
    Public Property Get ColorNormal() As ColorConstants
       ... return the color
    End Property
    Public Property Let ColorNormal(ByVal newColor As ColorConstants)
       ... set color to variable & draw button
    End Property
    Just food for thought. I am not a big ally for calling property methods when reading propertybag items when those actions result in drawing actions. Why? Typically, several different properties result in drawing when those properties change, each triggering a call to the controls "Draw" method. It is better, IMO, to set the variables from the propertybag and then after all are set, call the "Draw" method.
    Code:
    Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
        Set NFont = PropBag.ReadProperty("Font", Ambient.Font)
        ... set your color variables
        ... read the rest of your properties
        ... and when done with that, then call your "draw" function; Refresh in this case
    End Sub
    Private Sub UserControl_InitProperties()
        Set NFont = Ambient.Font
        ... initialize your color variables & any other UC variables
        ... and when done with that, then call your "draw" function; Refresh in this case
    End Sub
    Last edited by LaVolpe; Nov 24th, 2019 at 04:18 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Re: Colored Command Button

    Quote Originally Posted by LaVolpe View Post
    In your Set Font method, why do you transfer the properties instead of simply: Set nFont = mnewFont ?
    I kinda wondered about that too, but that's what Microsoft advised here:
    https://docs.microsoft.com/en-us/pre...ectedfrom=MSDN

    According to Microsoft: "Notice that this code uses With to set each property of the StdFont object individually: Simply assigning mnewFont to mFont would only change the default Name property."

    When I tried what you suggested, it failed to recover the saved Font properties.

    J.A. Coutts

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,709

    Re: Colored Command Button

    Yeah, it can be tricky when you have default properties.

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,530

    Re: Colored Command Button

    Quote Originally Posted by couttsj View Post
    I kinda wondered about that too, but that's what Microsoft advised here:
    https://docs.microsoft.com/en-us/pre...ectedfrom=MSDN

    When I tried what you suggested, it failed to recover the saved Font properties.

    J.A. Coutts
    I think that article is misleading. Notice there isn't any sample code regarding saving/retrieving saved font. I have never had any issues if done in the "proper" way. I think that article was trying to suggest that simply changing the font or a font property doesn't trigger painting... Ok, but we can handle it just fine

    - Call Refresh (or paint routine) before exiting Set Font
    Note: MSDN article was changing font properties in Set Font which triggers the FontChanged event. In their example, 4 properties set, up to 4 redraws of the control. I'd prefer no properties individually set, 1 redraw.
    Note: Their example is flawed any way. How? Notice they are checking 4 properties. If none of those properties change, then no FontChanged event occurs. If all 4 changed, then 4 FontChanged events occur. What happens if your only change was to make it underlined? No FontChanged event because they didn't include that check, nor for strikethrough. Even worse, those properties are not preserved in the updated font. Just a bad example overall IMO.

    - Call Refresh (or paint routine) when FontChanged event triggers.
    Note: FontChanged only triggers during runtime when user does something like UserControlXYZ.Font.Bold = True. It doesn't trigger just by setting the Font property, which is why you want to call Refresh before exiting that property.

    1. Whenever assigning a new font, two steps needed. If you Debug.Print NFont or UserControl.Font properties, they will correctly show Bold, Italic, Size, etc
    Code:
    Dim WithEvents NFont As StdFont
    
    Public Property Set Font(newFont As StdFont)
        Set NFont = newFont
        Set UserControl.Font = NFont
        PropertyChanged "Font"
        ... refresh/repaint as needed; this removes requirement to force FontChanged events
    End Property
    2. When Saving the Font...
    Code:
    Private Sub UserControl_WriteProperties(Propbag As PropertyBag)
        PropBag.WriteProperty "Font", NFont ' or usercontrol.font; doesn't matter
    End Sub
    3. When Retrieving font, two steps needed. If you Debug.Print NFont or UserControl.Font properties, they will correctly show Bold, Italic, Size, etc
    Code:
    Private Sub UserControl.ReadProperties(PropBag As PropertyBag)
        Set NFont = PropBag.ReadProperty("Font", Ambient.Font)
        Set UserControl.Font = NFont
    End Sub
    4. Starting brand new control
    Code:
    Private Sub UserControl_InitProperties()
        Set NFont = Ambient.Font
        Set UserControl.Font = NFont
    End Sub
    5. Only action needed in FontChanged is to redraw
    Code:
    Private Sub Nfont_FontChanged(ByVal PropertyName As String)
        Refresh ' or call your paint routine
    End Sub
    6. Notice I am not setting any font during Initialize

    Using the above outline and Debug.Print font properties during UserControl.Paint for verification, I think you'll find no problems at all. It doesn't matter whether the font is set at design time via property page or at run time
    Last edited by LaVolpe; Nov 25th, 2019 at 05:28 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Re: Colored Command Button

    LaVolpe;

    Thank you for the detailed explanation. Using a Debug.Print statement, my original code shows 3 trips to the FontChanged routine complete with the associated refresh (Why there is only 3, I have no idea). Implementing all of your code works just fine and shows no trips to the FontChanged routine, which suggests that it is not needed at all.

    Am I wrong in coming to this conclusion? Also, the Refresh in the Property Set Font routine was indeed necessary.

    J.A. Coutts

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,530

    Re: Colored Command Button

    Quote Originally Posted by couttsj View Post
    Implementing all of your code works just fine and shows no trips to the FontChanged routine, which suggests that it is not needed at all.

    Am I wrong in coming to this conclusion? Also, the Refresh in the Property Set Font routine was indeed necessary.
    Setting the individual font properties is not needed if you Refresh before exiting Set Font property. The FontChanged event is still desirable should the user simply change a single font attribute @ runtime, i.e.
    Code:
    UserControl1.Font.Bold = Not UserControl1.Font.Bold ' toggling value would trigger FontChanged
    P.S. The reason you didn't have 4 trips was because the event should only fire when an attribute changes value. For example, if the Bold attribute remained the same, it shouldn't trigger a change event after .Bold was set
    Last edited by LaVolpe; Nov 26th, 2019 at 07:12 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Re: Colored Command Button

    This latest version includes the changes to the Font property suggested by LaVolpe, as well as moving the pixel colors to a Resource file. Using the Resource file eliminates the necessity of coupling the User Control to the Colors.bin file, and presumably is a little faster (not verified).

    J.A. Coutts

  10. #10

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    783

    Re: Colored Command Button

    And finally an ActiveX control. There are advantages and disadvantages to using such a control. The advantage is that it reduces the size of your new project, but the disadvantage is that you must distribute and register the OCX.

    After compiling, it should be moved to a common directory such as \Windows\System32\ (\Windows\SysWOW64\ for 64 bit), and then added to your Project Components.

    There is also a short Test program included. The TypeLib key for your Button.OCX will be different than the one included in the test sample.

    J.A. Coutts
    Attached Images Attached Images  
    Attached Files Attached Files

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width