PDA

View Full Version : Gradient window background is not working properly



kcvinu
17-04-2021, 03:24
Hi all,
I am trying to implement a gradient background color in tWindow class. Here is the the function for it.


Function tWindow.SetGradientBackColor(Byval c1 As Long, Byval c2 As Long)
Me.mGradientBkGnd = true
Me.mIsBkChanged = True
Me.mGradiClrOne = c1 '// This is Long
Me.mGradiClrTwo = c2 '// This is also Long
if me.mIsCreated Then Win_InvalidateRect(Me.mHandle, 0, true)
End function

And the user can call this function like this.


win.SetGradientBackColor(0xFFCCCC, 0x6656FF)

When the user calls this function, we will end up in WM_ERASEBKGND message. And in that message, I tried this function.


Function tWindow.CreateGreadientBrush(Byval hDc As Dword)
Dim tc1 As tRgb(me.mGradiClrOne) '// tRgb is my UDT. I will show the elements.
Dim tc2 As tRgb(me.mGradiClrTwo)
Dim rct As RECT
Win_getclientrect(me.mHandle, rct)
Dim gBrush As Dword = 0
Dim memHdc As Dword = Win_CreateCompatibleDC(hDc)
Dim hBmp As Dword = Win_CreateCompatibleBitmap(hDc, rct.nRight, rct.nBottom)
Dim loopEnd As Long = rct.nBottom
Win_SelectObject(memHdc, hBmp)

For i as Long = 0 to loopEnd - 1
Dim tRct As Rect

Dim red as Long
Dim green As Long
Dim blue As Long

red = tc1.Red + (i * ((tc2.Red - tc1.Red) / loopEnd))
green = tc1.Green + ( i * (( tc2.Green - tc1.Green) / loopEnd))
blue = tc1.Blue + ( i * ((tc2.Blue - tc1.Blue) / loopEnd))

gBrush = CreateSolidBrush(Rgb(red, green, blue))

tRct.nLeft = 0
tRct.nTop = i
tRct.nRight = rct.nRight - rct.nLeft
tRct.nBottom = i + 1

Win_fillrect(memHdc, tRct, gBrush)
Win_deleteobject(gBrush)
Next

Dim Pattern As Dword = Win_CreatePatternBrush(hBmp)

Win_deletedc(memHdc)
Win_deleteobject(gBrush)
Win_deleteobject(hBmp)

Win_fillrect(hDc, rct, Pattern)
Win_deleteobject(Pattern)
End Function


This is tRgb UDT.


Type tRgb
Red As Long
Green As Long
Blue As Long

Function _Create(iVal As Long)
Me.Red = iVal >> 16
Me.Green = (Andb(iVal, 65280)) >> 8
Me.Blue = Andb(iVal, 255)
End function

Function PrintRgb()
Printl(Me.Red, ", ", Me.Green, ", ", Me.Blue)
End function
End Type

And the end result is attached here. Please check and guide me.

ReneMiner
17-04-2021, 17:36
Hi all,
...


When the user calls this function, we will end up in WM_ERASEBKGND message. And in that message, I tried this function.


Function tWindow.CreateGreadientBrush(Byval hDc As Dword)


....
CreateGreadientBrush

really a gread...y brush? is it a typo - same in your script? are you sure it is called? Are you using Call_IfExists? or call by function?GetPtr?
I would spell it Gradient. thats the first a saw. the other thing i see, it is doing the gradient somehow but not as intended because you use the wrong type to store colors and positions,
colors as rgb in range of bytes only. the desktops is multiple times that big in pixels
. you need fractures of bytes to display it. trying to store 255 / 1000 in a long integer is like using a grenade to peel off a banana.

try to use NO INTEGERS, exchange LONG and replace it with NUMBER

there is that rect,
width is right - left and
heigth is bottom - top since bottom is the bigger number and we want to have an absolute / positive number not negative.
lets assume an average screen 16:9 or 16:10 or just 4:3 width perhaps 1200 more ore less, height 750 , somewhere a taskbar...its not for being exact but to check in what ranges the numbers are.
loopEnd were 768 maybe. and we can to make it look good go from very bright to very dark in 768 steps
and also you go from orange to blue/ thats 9nce across the spectrum as these are opposing colors, orange i full red, half green, zero blue
start with RGB 255,127,0 and go to purple blue 63, 0, 255
the red will chANGE 192 IN Height STEPS from 255 to 63 that were to subtract 192/Height every iteration, an integer to use here will not word precise enough - thinBasic offers high precision numbers - completely free, you might use these., don't be shy. Really, at no extra cost you get as many Numbers as you need. As you want... grab a few, its always good to have some numbers in storage.
;)
mentioning it:
also the storages must be a numbers where you keep colors ore the amount that schall change with every iteration
so i suggest you look i did not completely fix everything up for yoou to use but i messed it up and captured and abused your
VARIABLES, I GAVE THEM OTHER NAMES and forced them to do something completely different or even commented some of them...
I did not use the provided fat brush nor the bucket to poor the color onto a thin line that has no space to deal with such amounts of paint
' the big brush and a bucket are not tools for me to draw a fine line
' i use like



Declare Function FineLine Lib "gdi32.dll" Alias "Rectangle"( byval hDc As Dword, Byval L as Long, ByVal Y as Long, ByVal R as Long Byval H As Long




Function tWindow.Gradient()
Dim tc1 As tRgb(me.mGradiClrOne) '// tRgb is my UDT. I will show the elements.
' these 2 udts contain colors to start and end?
Dim tc2 As tRgb(me.mGradiClrTwo) 'tc1 what is now and tc2 what shall be final?

' clean out a bit here...
Dim rct As RECT
Win_getclientrect(me.mHandle, rct)
':::::::Dim gBrush As Dword = 0

Dim Me_Hdc As Dword = Win_CreateCompatibleDC(hDc)
' i will draw onto the windows surface...
dim lHeight as Long at varptr(rct.nBottom) ' i capture this
Dim lRight as Long at Varptr(rct.nRight) ' also my hostage now
dim lLeft As Long at Varptr(rct.nLeft) ' got all i need froom this...


' avoid missing pixels at left or right
lLeft -= 1
lRight +=2

' instead of creating additional variables i create shortcuts to the already existing

' Dim hBmp As Dword = Win_CreateCompatibleBitmap(hDc, rct.nRight, rct.nBottom)
' Dim loopEnd As Long = rct.nBottom
' Win_SelectObject(memHdc, hBmp)
'
' For i as Long = 0 to loopEnd - 1
' Dim tRct As Rect
' Long can not be. The screen might be 750 pixels high. colors are only bytes from 0 to 255
' but integer can not show nor memorize the result of 255 / 750
' for a gradient it should be smooth so we must use fractures of bytes.
' Numbers are great and very precise


' haha, i captured them, now they are mine:
Dim red as Long = 1
Dim green As Long = 2
Dim blue As Long = 3
number current(3)
current()= array assign tc1.red, tc1.green, tc1.blue
number change(3)
' what we want minus what we already have is to achieve in the count of lHeight steps
change(red) = (tc2.red - current(red) )/ lHeight
change(green) = (tc2.green - current(green) /lHeight
change(blue) = tc2.blue - current(blue) / lHeight

while lHeight
' no need to count for to next if we have the count already in lHeight

'//// gBrush = CreateSolidBrush(Rgb(red, green, blue)) ////

' i use a thinpencil instead of Bob Ross' 2-inch-wide-brush :)

sendmessage me.handle, %META_SETTEXTCOLOR | %DS_SETFOREGROUND,
0, RGB( current(red), current(green), current(blue) )
' this to change the current foreground color on a dialog.
' somehow thinBsic did not grab one when the foreground-colors
' were available for anyone and for free. now dialogs in thinbasic wait for the next
' outlet of paint to receive their forecolor adjustment..

' does not know %Meta_SetTextColor? = 0x0200
' | %DS_SetForeGround? = 0x0209
' -----------------------------------
' ... use this as message: 0x0409
' ========

if FineLine( Me_hDC, lLeft, lHeight, lRight, lHeight ) then nop

' now add what is needed per step to reach the destination Color

current(red) += change(red)
current(green) += change(green)
current(blue) += change(blue)

decr lHeight
' 1 step less to go
wend



end function

if that will do?

kcvinu
17-04-2021, 19:45
@ReneMiner,

First of all thank you for the reply. Well, CreateGreadientBrush was a typo. Usually, I do copy & paste for function names. I corrected it to "Gradient". I was about to change the code as per your suggestions but, suddenly a thought came into my mind. I have this same code working in Nim programming laguage. And the only only difference is, Nim is a strictly typed language and I can use cast function to convert data types. So, after a rethink, I decided to inspect the values of tRct RECT. In order to do that, I wrote a function like this.


Function printRt(ByVal rt as twRect)
'printl(StrFormat$("left : {1}, top : {2}, right : {3}, bottom : {4}", rt.nLeft, rt.nTop, rt.nRight, rt.nBottom)) '// You see this line commented ?
End Function


And I called this function, right after I fill the RECT values. When I run this program, it shocked me and gave this result. (Please see the attached image)

It's so strange that i can't believe my eyes. Then for an experiment, I commented out the print statement in that function. Then also the code works good and gave the perfect result. How can I explain this behaviour.
See, this the code looks like now.


tRct.tLeft = 0
tRct.tTop = i
tRct.tRight = rct.nRight - rct.nLeft
tRct.tBottom = i + 1

printRt(tRct ) '// Dummy function goes here.

Win_fillrect(memHdc, tRct, gBrush)
Win_deleteobject(gBrush)

ReneMiner
17-04-2021, 23:07
begin controlid


the printing on top messed it up?
what would happen if you print it and use redraw/refresh?
as in Callback



callback function tWindow_OnSizing() As Long'-------------------------------------------------------------------
static cW as Long
static cH as Long
dialog get client cbhndl to cw, cH


'cw-=20
Dialog set Timer cbhndl , 0x1001
, 200
' use of a timer to redraw the window content after resizing the
'window to prevent the content from flickering and restores
' fractured layout-appearance. just let 200ms pass by so its secured the
' user has stopped his resizing action.
function = true ' pass back" true" if the callback is handled so the os is
informed that a recepient was found for this message and it can stop searching
a another destination for it.
'-------------------------------------------------------------------
End Function
'###############################################O
CallBack Function tWindow_OnTimer() As Long


long W, H
'-------------------------------------------------------------------
if cbctl =0x1001 then
dialog get size cbhndl to w, h
dialog set size cbhndl, w + 1, h ' tiny movements horizontal
dialog set size cbhndl, w, h + 1 ' & vertical to make the
dialog set size cbhndl, w, h ' controls looking good again
dialog Redraw cbhndl
dialog kill timer cbhndl, 0x1001

timer disables itself and wakes up again if anyone resizes the wincow,
EndIf




was that the name of your window? "tWindow?" it were bit confusing if you use an udt+aructure withot to dimension is as a variable.
but maybe it has a meaning.


prefix lowercase in front of uppercase have mostly a meaning in a CamelCase-Environment
(t is mainly used to mark somthing as and udt, a /type name or types, c commonly used to mark the strucutres, prototypes of classes, u indicates a union, o marks objects,p mostly pointer, h handles handled by handless handlings handlers
e events that just eccur / no one knows why......0
-----------------------------------------------------------------------------------
btw. thinbasic has built in a function,
dialog set Gradient hDlg, directional_setting, startcolor, endcolor

kcvinu
18-04-2021, 08:40
@ReneMiner


the printing on top messed it up?


Yes, obviously. That's why I comment out that line.But still it is working fine. That's strange.



was that the name of your window? "tWindow?

tWindow is a type. Here is the typical usage.


Dim win As tWindow
With Win
.SetText("Thin Window")
.SetPosition(400, 50)
'.SetSize(650, 300)
.OnMouseDown = "WindowMouseDown" '// Name of the event handler function.
End With
win.MakeWindow() '// Here is the actual window creation happens.
win.Display()




btw. thinbasic has built in a function,
dialog set Gradient hDlg, directional_setting, startcolor, endcolor

Let me check this function with my tWindow.