How to change the back color of a control at runtime ?

New to FreeBASIC? Post your questions here.
kcvinu
Posts: 232
Joined: Oct 07, 2015 16:44
Location: Keralam, India

Re: How to change the back color of a control at runtime ?

Post by kcvinu »

Here is the three types of button i have created.
1 - flat color button
2 - gradient button
3 - normal button.
Image here - https://drive.google.com/file/d/1sJmWZH ... sp=sharing
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: How to change the back color of a control at runtime ?

Post by jj2007 »

I know, it works fine. Your buttons look nice.

Even SetBkMode(hDC, TRANSPARENT) works, so a button with a coloured background is possible. What doesn't work for me are the SetBkColor(hDC, Rgb(...)) and SetTextColor(hDC, Rgb(...)) calls. Same for SetDCBrushColor(hDC, Rgb(0, 255, 0)). Bad luck...
kcvinu
Posts: 232
Joined: Oct 07, 2015 16:44
Location: Keralam, India

Re: How to change the back color of a control at runtime ?

Post by kcvinu »

@jj2007,

Code: Select all

 SetBkMode(lp.hdc, TRANSPARENT) 
    SetTextColor(lp.hdc, RGB(102, 255, 51) )

This is not working in my case. I want to change the button forecolor. But no way. What to do ? Any idea ?
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: How to change the back color of a control at runtime ?

Post by Josep Roca »

Te button must be owner draw. Then you can process the WM_CTLCOLORBTN message.

The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors. However, only owner-drawn buttons respond to the parent window processing this message.

See: https://docs.microsoft.com/en-us/window ... tlcolorbtn

BTW you insist in using RGB when you must use BGR. I already explained it in an earlier post in this thread.

I ended witing my own button control.
Code: https://github.com/JoseRoca/WinFBX/blob ... Button.inc
Documentation: https://github.com/JoseRoca/WinFBX/blob ... 20Class.md

Paul Squire's WinFBE IDE uses this control in its visual designer.
PaulSquires
Posts: 1002
Joined: Jul 14, 2005 23:41

Re: How to change the back color of a control at runtime ?

Post by PaulSquires »

Josep Roca wrote:Te button must be owner draw. Then you can process the WM_CTLCOLORBTN message.
Paul Squire's WinFBE IDE uses this control in its visual designer.
Yes, and I did so because of my experience with my other visual designers and users always wanting to be able to change colors of the default standard Windows button. Using Jose's custom button control made it much easier to satisfy those user needs at the slight price of increasing the program size because the button source code gets compiled into the final program's exe whereas using the standard Window's control it is already baked into the operating system.
kcvinu
Posts: 232
Joined: Oct 07, 2015 16:44
Location: Keralam, India

Re: How to change the back color of a control at runtime ?

Post by kcvinu »

@Josep Roca
I've found the answer myself. We can change the Back color and fore color with NM_CUSTOMDRAW. To change the back color, we can use the same approach which I said above comment.
To change the fore color, Just use three functions.
SetBkMode
SetTextColor
DrawText

And then return CDRF_NOTIFYPOSTPAINT.
If you returned any other values, the color won't change.
So there is no need to use BS_OWNERDRAW style.
Sorry for using RGB again. Since, I copied my Nim code to this forum. In Nim, RGB is just RGB.

Your Button class is amazing. I am using sub classing but you create a new window class for creating button. Is there any special advantages in using special class ?
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: How to change the back color of a control at runtime ?

Post by jj2007 »

kcvinu wrote:And then return CDRF_NOTIFYPOSTPAINT.
Sounds good! At which dwDrawStage do you return it? Can you post the code?
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: How to change the back color of a control at runtime ?

Post by Josep Roca »

I have used CDRF_* values previously, mainly with ListViews, but wasn't aware that buttons did support CDRF_NOTIFYPOSTPAINT. Apparently it was introduced in Windows Vista and you must use a manifest.

> Your Button class is amazing. I am using sub classing but you create a new window class for creating button. Is there any special advantages in using special class ?

It gives you control about everything. It was an exercise to build controls from scratch that I did in XP times. Subclassing can be used to modify the behaviour of existing controls (I did subclass the Edit control to create a masked edit control), but not to create a new control. As it was an exercise, I did choose the button control because it was the easier one.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: How to change the back color of a control at runtime ?

Post by jj2007 »

I hesitate to go for a full ownerdraw button because some styles, like the BS_COMMANDLINK button in the middle, would need complex treatment. The left button, for example, uses DrawText, and it was tricky to center it properly, despite the use of DT_CALCRECT.

It would also imply a check for the styles applied by the coder. For the time being, I can change the background colour. @kcvinu: How did you change the foreground colour? By drawing the text yourself?
Image
kcvinu
Posts: 232
Joined: Oct 07, 2015 16:44
Location: Keralam, India

Re: How to change the back color of a control at runtime ?

Post by kcvinu »

@ jj2007
The button with an icon is superb. However, this is my Nim code to change the button text color.

Code: Select all

proc setTxtColor(lp : LPNMCUSTOMDRAW, txt : string) : UINT =
    
    let txtFlag : UINT = DT_SINGLELINE or DT_VCENTER or DT_CENTER or DT_HIDEPREFIX
    SetBkMode(lp.hdc, TRANSPARENT)
    SetTextColor(lp.hdc, tColor.toColorRef())
    var tLen  = txt.len.toi32
    DrawText(lp.hdc, txt, tLen, lp.rc, txtFlag)
    result = CDRF_NOTIFYPOSTPAINT 
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: How to change the back color of a control at runtime ?

Post by jj2007 »

Thanks, kcvinu. So it is what I suspected: a complete ownerdraw. I had tested that version already, and discarded it because, as written earlier, it becomes complex with certain buttons. I will have a look at Joseph's version...

P.S.: If I add a BS_COMMANDLINK style to the pXpButton3 button in Josep Roca's example, it doesn't change at all.

Compliments to Josep, you put an incredible amount of work into Afx! CXpButton.inc alone is 1600+ lines, and there are so many inc files...
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: How to change the back color of a control at runtime ?

Post by Josep Roca »

Thanks for the compliments.

> P.S.: If I add a BS_COMMANDLINK style to the pXpButton3 button in Josep Roca's example, it doesn't change at all.

This control was not intended as a replacement of the Windows button control. I first wrote it with PowerBasic many years ago, in XP times (hence the "Xp" in its name), as a way of using icons with styled buttons (currently, Windows supports it using an image list and a manifest). Then I translated it to FreeBasic as a training exercise to learn how to make custom controls using a class... and some time ago, Paul suggested to make some chnages to allow for coloured buttons, that seem to be in high demand lately... :)
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to change the back color of a control at runtime ?

Post by dodicat »

For fun, an alternative;

Code: Select all


#include "windows.bi"
#include "file.bi"
Declare Sub tree(x1 As Single,y1 As Single,size As Single,angle As Single,depth As Single,colb As Uinteger<32>=0,colL As Uinteger<32>=0,im As Any Ptr=0)
Declare Sub finish()
Dim Shared As Single spread=25,scale=.76      
Dim Shared As Any Ptr i(1 To 4)
Dim Shared szBitmap(Lbound(i) To Ubound(i)) As String 
Dim Shared As Point p(1 To 4)
Dim As MSG msg
Dim Shared As HWND hWnd, edit(Lbound(i) To Ubound(i))
Dim Shared hbitmap(1 To 4) As handle
hWnd = CreateWindowEx( 0, "#32770", "Bitmap Button Test",WS_OVERLAPPEDWINDOW Or WS_VISIBLE , 100, 0, 620, 320, 0, 0, 0, 0 )

Sub makebitmap(x As Single,z As Long=0)
    Dim As Long w,h
    w=150 
    h=150
    Screenres w,h,32,,-1 'create a temp [hidden] screen
    Width w\8,h\16
    For n As Long=Lbound(i) To Ubound(i)
        If z=0 Then
            i(n)=Imagecreate(w,h,Rgb(55+x,255,255-50*n))
            tree(70,100,70,90+(Rnd*25-Rnd*25),12,Rgb(200,100,0),Rgb(0,100,0),i(n))
            Draw String i(n),(10,10),"Hello",0
            Bsave ("small"+Str(n)+".bmp",i(n))
            szbitmap(n)="small"+Str(n)+".bmp"
            Imagedestroy i(n):i(n)=0
        Else
            i(z)=Imagecreate(w,h,Rgb(Rnd*x,Rnd*x,Rnd*x))
            tree(70,100,70,90+(Rnd*25-Rnd*25),12,Rgb(200,100,0),Rgb(0,100,0),i(z))
            Draw String i(z),(10,10),"Hello",0
            Bsave ("small"+Str(z)+".bmp",i(z))
            szbitmap(z)="small"+Str(z)+".bmp"
            Imagedestroy i(z):i(z)=0
        End If
    Next n
    Screen 0  'return to console
    Dim As Integer k,y=0,start
    For n As Long=Lbound(i) To Ubound(i)
        k+=1
        If (k) Mod 5=0 Then y+=h:k=1
        p(n)=Type((k-1)*150+w/2,y+h/2)
        If edit(n)=0 Then edit(n) = CreateWindowEx( 0, "BUTTON", "" , WS_VISIBLE Or WS_CHILD Or ANSI_CHARSET Or BS_PUSHBUTTON Or BS_BITMAP, (k-1)*150 , y+50 , w , h , hWnd, 0, 0, 0 )
    Next n
    
    For n As Long=Lbound(i) To Ubound(i)
        deleteobject(hbitmap(n))
        hBitmap(n) = LoadImage(0, szBitmap(n), IMAGE_BITMAP, w, h,  LR_LOADFROMFILE )
        If hbitmap(n) Then SendMessage(edit(n), BM_SETIMAGE, IMAGE_BITMAP, Cast(LPARAM, hbitmap(n)))
    Next n
End Sub

makebitmap(Rnd*50)

#macro switch(i,r)
Case edit(i)
    Select Case msg.message  
    Case WM_LBUTTONDOWN
        makebitmap(r,i)
    End Select
    #endmacro
    
    While GetMessage( @msg, 0, 0, 0 )
        
        TranslateMessage( @msg )
        DispatchMessage( @msg )
        
        Select Case msg.hwnd
        Case hWnd
            Select Case msg.message
            Case 273 : PostQuitMessage(0)
            End Select
            switch(1,255)
            switch(2,255)
            switch(3,255)
            switch(4,255)
        End Select
        
        
    Wend
    
    Sub Tree(x1 As Single,y1 As Single,size As Single,angle As Single,depth As Single,colb As Uinteger<32>=0,colL As Uinteger<32>=0,im As Any Ptr=0)
        #define incircle(cx,cy,radius,x,y) (cx-x)*(cx-x) +(cy-y)*(cy-y)<= radius*radius
        Var x2=x1-.25*size*Cos(angle*.01745329)
        Var y2=y1-.25*size*Sin(angle*.01745329)
        Static As Integer<32> count,fx,fy,sz,z
        If count=0 Then  fx=x1:fy=y1:sz=size:z=2^(depth+1)-1
        Line im,(x1,y1)-(x2,y2),colb
        If count=0 Then  fx=x2:fy=y2:sz=size
        count=count+1
        If count>z Then count=0
        If incircle(fx,fy,(.45*sz),x2,y2)=0 Then Circle im,(x2,y2),.01*sz,colL 
        If depth>0 Then
            Tree(x2, y2, size * Scale, angle - Spread, depth - 1,colB,colL,im)
            Tree(x2, y2, size * Scale, angle + Spread, depth - 1,colB,colL,im)
        End If
    End Sub
    
    
    Sub finish Destructor
        For n As Long=Lbound(i) To Ubound(i)
            deleteobject(hbitmap(n))
            If i(n) Then Imagedestroy(i(n)):i(n)=0
            Kill "small"+Str(n)+".bmp"
            Print "destroying ";n 
            print iif(fileexists("small"+Str(n)+".bmp"),"Delete bitmaps manually","OK")
            if fileexists("small"+Str(n)+".bmp") then sleep 1000
        Next
      
        End Sub
 
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: How to change the back color of a control at runtime ?

Post by jj2007 »

Lovely, dodicat! I couldn't resist ;-)
Image
Post Reply