| #E6E6E6 | 【VB 物件】TextScroll 實現文字走馬燈 | 作者:吳文成 在上一篇文章 , 介紹了實現圖片循環捲動的物件 PictureScroll, 接著要來談談文字循環捲動(即文字走馬燈)的問題,以及由我所撰寫的物件 文字捲動與圖片捲動一樣,在視覺效果上其原理是簡單的,以來回捲動的走馬燈為例,我們將整個文字視為一個物件,當正在移動的文字物件右端「碰」到區域右邊界的時候,文字物件的移動方向就反過來,然後以同樣的方式,再偵測文字物件的左端是否「碰到」區域左邊界──這樣的構思流程是實體觀點的類比式描述,但是當我們想要將它寫成數位式的邏輯程序,也就是,當我們想要將類比式的描述「翻譯成」數位式的語法的時候,我們會需要考慮更多複雜的情況。例如怎麼翻譯「碰到」的數位意義?在實體觀點,「碰到」就是兩個物體邊界在某個時間點,最接近之後無法再交錯的情況,這個描述已經預設了最基本的剛體概念,但是在數位世界最基本的概念卻是數字與邏輯( and、or、>、<、= 等等), 也就是說,我們必須要用後面這些概念來翻譯什麼是「碰到」。然而在此之前 ,我們要先界定什麼是文字物件,才能夠談移動中的文字物件「碰到」區域邊界的情況。所謂物件就是集合若干資料、屬性與方法的單位個體。 編程語言可以選擇性地,只賦予某物件特定的內容與組成元素,例如對於上述的文字物件(假設叫做 Text),在所有可能的屬性裡,我們只需要知道它的長度(Text.TotalWidth)與目前相對於區域的位置(Text.Left)就可以來定義「碰到」的數位意義,當 Text.Left + Text.TotalWidth >= 區域右邊界,這就是文字物件右端與區域右邊界「重合」的數位分析,在固定時間間隔的檢測下,我們可以知道何時數值已經「重合」,然後再將文字物件的移動變化率乘上 (-1) 以表示反向移動。看到這兩段,我好像在談一個很奇怪的話題,對於熟練的程式設計者來說,上述技巧根本是基本功,但是我希望把焦點擺到「翻譯問題」上,翻譯問題可以存在於實體世界與邏輯世界、類比觀點與數位觀點、甚至也存在於兩套不同的數位編程裡,這類問題的尖銳性在人工生命與人工智慧的領域更為明顯,並非所有的( 互相)翻譯都是可能的,即使它們是可譯的,這種翻譯不代表是等價的。 在我撰寫的 TextScroll 物件類別 ,考慮了稍微複雜的走馬燈樣式, 與[[img src=computer/TextScroll1.gif height=59 width=202 align=left]]上面的前兩個範例不同,如左圖所示,當文字「穿過」邊界的時候,消失的文字部分應該要出現在另外一邊才對 , TextScroll 物件[[img src=computer/TextScroll2.gif height=59 width=202 align=left]]考慮了這樣的呈現方式 ! TextScroll 也允許使用者設定文字捲動區域的留白空間(百分比 , X_MarginPercent 與 Y_MarginPercent 屬[[img src=computer/TextScroll3.gif height=59 width=202 align=left]]性),同時能夠設定背景圖片(當然,背景圖片不會跟著文字一起捲動)。在文字捲動(ScrollMode)方面 , 我並沒有提供向上與向下捲動的模式,有興趣的人可以增加不同的捲動模式。此物件使用了幾個不常用的 Window API : CreateRectRgnIndirect 與 SelectClipRgn 等等,前者的作用在於創建一個指定的矩形區域,而後者的作用在於將這個矩形區域設定為某控件設備的新的剪裁區,使得所有的繪製作業都只在這個剪裁[[img src=computer/TextScroll4.gif height=59 width=202 align=left]]區發生。這些函數的運用能夠實現留白空間 ,並且使得指定區域內的文字繪製得到適當的裁剪(即剪裁區之外的文字將被「裁」掉 不見),如左圖所示。我將較為關鍵的部分原始碼,給列舉在下面,你可以下載範例原始碼,自己測試或新加入功能。 ' 計算字型與文字捲動區域的大小,繪出文字 Private Sub CalculateMetrics() On Error Resume Next Dim tmp As Long With textBox ' 指定文字捲動區域 cliprc.Left = .ScaleWidth * m_X_MarginPercent / 200 cliprc.Right = .ScaleWidth - cliprc.Left cliprc.Top = .ScaleHeight * m_Y_MarginPercent / 200 cliprc.Bottom = .ScaleHeight - cliprc.Top If cliprc.Top < 1 Then cliprc.Top = 1 If cliprc.Left < 1 Then cliprc.Left = 1 tmp = .ScaleWidth - 1 If cliprc.Right > tmp Then cliprc.Right = tmp tmp = .ScaleHeight - 1 If cliprc.Bottom > tmp Then cliprc.Bottom = tmp ' 依據捲動區域,計算字型的大小與總長度 Set .Font = m_Font tmp = cliprc.Bottom - cliprc.Top - 4 If tmp < 4 Then .FontSize = 4 Else .FontSize = tmp End With If textRgn > 0 Then DeleteObject textRgn ' 建立文字捲動區域,並繪出文字 textRgn = CreateRectRgnIndirect(cliprc) resetScroll End Sub Private Sub tmrScroll_Timer() If textWidth = 0 Then Exit Sub With textBox .Refresh .Cls .AutoRedraw = False ' 選定文字捲動區域物件 ' 這使得任何繪製不超出此區域 SelectClipRgn .hDC, textRgn RedrawText True ' 取消原本選定的文字捲動區域物件 SelectClipRgn .hDC, 0 End With End Sub Private Sub RedrawText(Optional isInScroll As Boolean) Dim drawrc As RECT, cliprcWidth As Long, tmp As Long With textBox .Cls drawrc = cliprc cliprcWidth = cliprc.Right - cliprc.Left Select Case m_ScrollMode Case 向右單向捲動 drawrc.Left = cliprc.Left + offsetX drawText .hDC, m_Text, -1, drawrc, textAlign tmp = drawrc.Left + textWidth - drawrc.Right If tmp > 0 Then drawrc.Left = cliprc.Left - textWidth + tmp drawText .hDC, m_Text, -1, drawrc, textAlign End If If isInScroll Then offsetX = offsetX + m_ScrollStep If offsetX >= cliprcWidth Then offsetX = 0 Case 向左單向捲動 drawrc.Left = cliprc.Left + offsetX drawText .hDC, m_Text, -1, drawrc, textAlign If offsetX < 0 Then drawrc.Left = cliprc.Right + offsetX drawText .hDC, m_Text, -1, drawrc, textAlign End If If isInScroll Then offsetX = offsetX - m_ScrollStep If offsetX <= -textWidth Then offsetX = cliprcWidth - textWidth Case 來回捲動 drawrc.Left = cliprc.Left + offsetX drawText .hDC, m_Text, -1, drawrc, textAlign If isInScroll Then offsetX = offsetX + (m_ScrollStep * oscMode) If drawrc.Left + textWidth >= cliprc.Right Then oscMode = -1 If offsetX <= 0 Then oscMode = 1 Case Else Err.Raise 513, , "指定了錯誤的屬性值" End Select End With End Sub |
2004/10/09 |