| #E6E6E6 | 【VB 物件】FadeSmart 實現色彩漸層表單 | 作者:吳文成 [[img src=computer/FadeSmart.gif height=357 width=202 align=left]] 我們先來看看 ,由 FadeSmart 物件類別所繪製的三個不同呈現方式的漸層圖,分別是由上到下的色彩漸變、由右上到左下的色彩漸變,以及圓形發散的色彩漸變。 在上一篇,介紹實現動態漸層圓圈的物件 FadeCircle 的時候 ,我同時也介紹了色彩學的幾個要點,尤其是色彩數值解析的理論( RGB 與 HSB ),在這個單元我要先來補充談談,在編程領域,色彩的表示法。 在程式設計的一般表示裡,顏色的紅、綠、藍三分色的數值範圍都在 0 ∼ 255 之間 ,各有 256(=162) 個可能數字。之所以定出這樣的數值範圍是為了要遷就十六進位的表示法 , 於是當 Red=255 的時候 ,我們也可以寫成 Red=FF( F 在十六進位代表 15 ,兩個 F 就表示 15*160+15*161=255 )。有寫網頁經驗的人一定知道,如果要將網頁背景顏色設為白色,那麼語法就是BgColor=#FFFFFF( 請注意有六個 FF , 我們可以將各兩個 FF 視為一個單位, 於是共有三個單位, 分別代表紅、綠、藍三個分色值 ), 在 HTML 網頁語言裡,色彩的表示法是用兩個位元組的十六進位來表示各分色,以剛剛的例子來說,白色就是 Red=FF、Green=FF、Blue=FF 的「組合」, 那麼黃色就是 #FFFF00(即 Red=255、Green=255、Blue=0), 這是網頁語言的表示法 。 在 Visual Basic 裡,黃色表示為 RGB(255,255,0) 的函數值,那這個值到底是多少呢?在微軟的視窗作業環境乃是用一個長整數來代表個別唯一的色彩值,例如黃色就是 255*2560+255*2561+0*2562=65535,顯然當三個分色都是 255 的時候 , 就是最大的色彩值 ,即 RGB(255,255,255)=16777215,這就是白色( 於是,在這樣的數值定義下,所有可能的顏色就有 16,777,216 =2563 個。 請注意,這種數值定義看起來是「客觀」的,但卻也是「人為」的,我們仍然可以定出不同的數值系統,該系統的色彩數可能不只是 2563 個 , 也就是說,即使是公認的數值理論,仍然是「相對」於人的定義系統!哪一天,如果人們可以對色彩做出更精緻的解析,那麼色彩的域度將不止於目前的數值範圍)。 知道了色彩的數值定義,如果給我們一個長整數的色彩值,把它換算成三分色的表示法應該也難不倒我們( 範例裡有算法 ),但是 RGB 轉換成 HSB 就「粉難」, 以後有空談到影像灰階化的演算法的時候 ,我再來談。我們將進入另一個問題,要如何將粉紅色( =RGB(255,128,255) )「 漸層」到天藍色( =RGB(128,255,255) )( 即第一個圖所演示的)呢,究竟是色彩的什麼本質從前者改變到後者?這個答案是頗令人驚訝的,因為改變的本質是純紅、純綠與純藍!當粉紅色漸層到天藍色,其漸次改變的本質其實是純紅色從數值 255 變到 128(負改變)、 純綠色從數值 128 變到 255(正改變)、 純藍色從數值 255 變到 255(即不改變), 所以我在上一篇文章才如此驚嘆地說「色彩的最偉大解析就是十九世紀初的三原色說」。瞭解了色彩漸層的原理,下一個問題是怎麼去(均勻地)分佈兩個色彩之間的系列,例如在寬度 100 (像素)的區域裡,粉紅色漸層到天藍色的各分色都有不同的變化率,我們要算的就是這個變化率,我們稱之為漸層梯度,在這個例子裡,純紅色的漸層梯度就是 (128-255)/100=-1.27( 負梯度), 純綠色的漸層梯度是 (255-128)/100=1.27(正梯度 ), 純藍色的漸層梯度是 (255-255)/100=0(零梯度)。求出梯度是為了比例值或是內插法的計算,算出從什麼位置畫線到什麼位置,然後以什麼顏色畫。 第一個圖與第三個圖的漸層製作方式並不難理解,但是製作「斜向」的均勻漸層就需要花腦筋,例如第二個圖是從由右上均勻漸層到左下,它的內插法計算較為複雜,可能不同的程式設計者會有不同的演算法,我的算法是將整個區域切割成兩個斜向的三角形,它們各自分擔其中一個色彩主要系列(目的為了「均勻」漸層),這樣的規劃(即對於問題點的切割 )會使得問題變得比較簡化與容易程式撰寫,我建議讀者可以先用自己的想法去試著寫演算法 ,然後再比較我的版本 。 FadeCircle 與 FadeSmart 兩個物件 ,所要解決的問題並不同 , 前者需要變異度概念的介入(以增加色彩複雜性,與新色彩的創製),後者著重於梯度概念的運用 , 前者是動態的,後者是靜態的。我一樣將 FadeSmart 物件較為關鍵的部分原始碼,給列舉在下面,倘若你有更好的演算法,希望能夠不吝與我分享: ' 定義色彩的資料型態 Private Type ColorRGB Red As Integer Green As Integer Blue As Integer End Type ' 定義色彩運算的資料型態 Private Type ColorSingle Red As Single Green As Single Blue As Single End Type ' 此物件的繪圖方法,必須指定實現漸層的控制項 ' FadeMode 是色彩漸層在方向分布上的呈現模式 ' FirstColor 是第一個色彩值,為選擇性參數 ' SecondColor 是第二個色彩值,為選擇性參數 Public Sub FadeShow(DestObject As Object, Optional FadeMode As FadeShowMode = -1, Optional FirstColor As FadeColor = -1, Optional SecondColor As FadeColor = -1) On Error GoTo errorLabel ' 賦值給所需的變數 If FadeMode <> -1 Then m_FadeMode = FadeMode If FirstColor <> -1 Then m_FirstColor = FirstColor If SecondColor <> -1 Then m_SecondColor = SecondColor Set toObj = DestObject With toObj Dim c1 As ColorRGB, c2 As ColorRGB ' 定義色彩各分色的漸變梯度 Dim slopeRGB As ColorSingle Dim mainSide As Long, singleSide As Long, i As Long ' 轉換長或寬的對應值(即運用內插法計算,或比例法) Dim transRate As Single, transRate2 As Single Dim Xo As Long, Yo As Long, Xd As Long, Yd As Long, MaxR As Long .ScaleMode = vbPixels .DrawWidth = 1 .AutoRedraw = True .Cls c1 = GetRGB(m_FirstColor) c2 = GetRGB(m_SecondColor) Select Case m_FadeMode Case 1, 2 ' ↓、→ ' 取得決定色彩分布的基底邊 mainSide = .ScaleWidth If m_FadeMode = 1 Then mainSide = .ScaleHeight ' 根據 mainSide,取得色彩的漸變梯度 slopeRGB = getSlope(c1, c2, mainSide) For i = 0 To mainSide ' 設定繪製的前景色彩 setDrawColor c1, slopeRGB, i If m_FadeMode = 1 Then toObj.Line (0, i)-(.ScaleWidth, i) Else toObj.Line (i, 0)-(i, .ScaleHeight) End If Next i Case 3, 4 ' ↘、↙ ' 取得決定色彩分布的基底邊(這裡即最大邊) If .ScaleWidth > .ScaleHeight Then mainSide = .ScaleWidth transRate = 1 transRate2 = .ScaleHeight / .ScaleWidth Else mainSide = .ScaleHeight transRate = .ScaleWidth / .ScaleHeight transRate2 = 1 End If ' 根據 mainSide,取得色彩的漸變梯度 ' mainSide 乘上 2 是為了使長與寬的色彩漸變梯度等價 slopeRGB = getSlope(c1, c2, mainSide * 2) For i = 0 To mainSide * 2 ' 設定繪製的前景色彩 setDrawColor c1, slopeRGB, i If i <= mainSide Then ' 針對某半邊(上方)三角形的色彩繪製 singleSide = i If m_FadeMode = 3 Then toObj.Line (singleSide * transRate, 0)-(0, singleSide * transRate2) Else toObj.Line (.ScaleWidth - singleSide * transRate, 0)-(.ScaleWidth, singleSide * transRate2) End If Else ' 針對另一半邊(下方)三角形的色彩繪製 singleSide = i - mainSide If m_FadeMode = 3 Then toObj.Line (.ScaleWidth, singleSide * transRate2)-(singleSide * transRate, .ScaleHeight) Else toObj.Line (0, singleSide * transRate2)-(.ScaleWidth - singleSide * transRate, .ScaleHeight) End If End If Next i Case 5 ' ◎ ' 取得圓心位於目標控制項的座標 Xo = m_Xpercent * .ScaleWidth / 100 Yo = m_Ypercent * .ScaleHeight / 100 ' 取得繪製圓的最大半徑 If Xo > .ScaleWidth / 2 Then Xd = Xo Else Xd = .ScaleWidth - Xo If Yo > .ScaleHeight / 2 Then Yd = Yo Else Yd = .ScaleHeight - Yo MaxR = Int((Xd ^ 2 + Yd ^ 2) ^ (1 / 2)) ' 根據 MaxR,取得色彩的漸變梯度 slopeRGB = getSlope(c1, c2, MaxR) .DrawWidth = 2 For i = 0 To MaxR ' 設定繪製的前景色彩 setDrawColor c1, slopeRGB, i toObj.Circle (Xo, Yo), i Next i .DrawWidth = 1 Case Else GoTo errorLabel End Select End With Exit Sub errorLabel: Err.Raise 513, , "目的控制項不支援 FadeSmart 的功能" & vbNewLine & "或者,指定了錯誤的屬性值" End Sub ' 取得指定色彩的 Red、Green、Blue 值 Private Function GetRGB(ByVal CrColor As Long) As ColorRGB GetRGB.Red = CrColor And &HFF GetRGB.Green = (CrColor \ &H100) And &HFF GetRGB.Blue = (CrColor \ &H10000) And &HFF End Function ' 取得各分色值在指定基底(spreadBase)下的漸變梯度 Private Function getSlope(c1 As ColorRGB, c2 As ColorRGB, spreadBase As Long) As ColorSingle getSlope.Red = (c2.Red - c1.Red) / spreadBase getSlope.Green = (c2.Green - c1.Green) / spreadBase getSlope.Blue = (c2.Blue - c1.Blue) / spreadBase End Function ' 設定繪製的前景色彩 ' 在指定的漸變梯度與基底下,求出(內差法計算後)的色彩值 Private Sub setDrawColor(c1 As ColorRGB, slopeRGB As ColorSingle, spreadBase As Long) toObj.ForeColor = RGB(slopeRGB.Red * spreadBase + c1.Red, _ slopeRGB.Green * spreadBase + c1.Green, _ slopeRGB.Blue * spreadBase + c1.Blue) End Sub |
2004/10/17 |