 |
VFP 愛用者社區 本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
|
上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
foxy

註冊時間: 2007-08-16 文章: 260 來自: 泰國
第 1 樓
|
發表於: 星期四 八月 21, 2025 5:33 am 文章主題: thisform.refresh 使得 image control 圖片閃問題 |
|
|
小弟正在測試 _ssclasses.vcx 的 ssbutton. ssbutton 是container, 包含兩個 image control 供顯示兩個圖片,還有其他 control, 這兩個 image control 會重疊 (是否有關係?).
在一個 form 上 約有15個 ssbutton, 當 thisform.refresh 的時候, 所有的那 15 個都不停閃爍, 像是在發抖.
小弟用 thisform.lockscreen=.T. 不能成功. 但是 lockWindowUpdate 好像可以.
請問有甚麼辦法? _________________ 進銷存+生產製造+會計+員工薪資+CRM+POS零售+餐廳手機app+電商手機app+電商網站,物流系統. 正/簡體中文,英,日,泰,緬甸文. MS SQL Server + 前台 VFP + PHP 網站 + Flutter 手機 App, 都共享 MS SQL Server的資料. www.foxacc.com LINE: mike-lm |
|
回頂端 |
|
 |
CPS0204
註冊時間: 2014-08-24 文章: 480
第 2 樓
|
發表於: 星期二 九月 16, 2025 3:32 pm 文章主題: |
|
|
以下是gpt 回答:
你遇到的是「重疊 Image 控制項 + 大量 Refresh」造成的重繪風暴。`ThisForm.LockScreen=.T.` 在這種情況常常擋不住(因為 VFP 在 Refresh 裡仍會對每個子控制項送 WM\_PAINT),所以你會看到 15 個 ssbutton 一起抖、閃。
下面給你一套「由根本到權宜」的處理順序,照 1→2→3 做,通常就能把閃爍壓到幾乎看不見。
---
# 1) 從源頭減少重繪:改成「單一 Image 切換圖」而不是「兩個重疊 Image」
`ssbutton` 之所以重繪頻繁,多半是它用兩個重疊的 Image 來模擬 Normal/Down/Hot 狀態(滑鼠移入就把上圖 Visible=.T. 之類)。重疊子控制項在 Refresh 時會互相覆蓋、反覆失效(invalidate),造成閃爍。
最省事的改法是維持 Container 架構,但把 2 個 Image 換成 **1 個 Image**,用 `PictureVal` 在滑鼠事件間 **切換位元組圖**,而不是兩個控制項互相蓋:
```foxpro
* 假設:ssbutton 是 Container,裡面只放一個 Image 名叫 img
* 在 Init 時把兩張圖載入到記憶體,之後都用 PictureVal 切換
PROCEDURE Init
THIS.AddObject("img","Image")
THIS.img.Stretch = 2 && Isometric
* 把圖檔讀到變數(或集中快取,見第 4 點)
THIS.AddProperty("cPicNormal","")
THIS.AddProperty("cPicHot","")
THIS.cPicNormal = FILETOSTR(FULLPATH("normal.png"))
THIS.cPicHot = FILETOSTR(FULLPATH("hot.png"))
THIS.img.PictureVal = THIS.cPicNormal
ENDPROC
PROCEDURE MouseEnter
THIS.img.PictureVal = THIS.cPicHot
ENDPROC
PROCEDURE MouseLeave
THIS.img.PictureVal = THIS.cPicNormal
ENDPROC
PROCEDURE MouseDown
* 如果還有第三張 down 圖,也同理
ENDPROC
```
重點:**不用兩個 Image**,就少了一倍的子視窗重繪與 Z-order 來回切換,閃爍會大幅下降。
---
# 2) 需要批次更新時,用「WM\_SETREDRAW」凍結重繪(比 LockWindowUpdate 溫和很多)
`LockWindowUpdate()` 是「全域鎖」且副作用大,除非萬不得已不建議。而 `WM_SETREDRAW` 是每個視窗各自的「暫停/恢復重繪」開關,安全穩定得多。建議包成兩個小方法:
```foxpro
#DEFINE WM_SETREDRAW 0x000B
DECLARE INTEGER SendMessage IN user32.DLL ;
INTEGER hWnd, INTEGER Msg, INTEGER wParam, INTEGER lParam
PROCEDURE FreezePaint
* 停止這個表單(含子控制項)的重繪
SendMessage(THISFORM.HWnd, WM_SETREDRAW, 0, 0)
ENDPROC
PROCEDURE ThawPaint
* 恢復重繪並一次性重畫
SendMessage(THISFORM.HWnd, WM_SETREDRAW, 1, 0)
THISFORM.Refresh() && 或 THISFORM.InvalidateRect(),VFP 沒此方法就用 Refresh
ENDPROC
```
使用方式(舉例你原本會在某段程式做多次變更與 `Thisform.Refresh`):
```foxpro
THISFORM.FreezePaint()
TRY
* 一次把 15 個按鈕的屬性改好(不要在中途 Refresh)
* ...你的更新邏輯...
CATCH
* error handling
FINALLY
THISFORM.ThawPaint()
ENDTRY
```
> 小提醒:把多個 `Thisform.Refresh()` 集中到最後一次,差很多。
---
# 3) 關閉視覺樣式(Themes)以減少額外的 GDI 重繪
VFP 9 的 Form/部分控制項有 `Themes` 屬性。視覺樣式 ON 時,Windows 額外畫陰影、漸層,重繪更吃力。對「圖形按鈕」這種自畫 UI,通常把 Themes 關掉更穩:
```foxpro
THISFORM.Themes = .F.
* 若 _SCREEN.Themes 存在也可關:_SCREEN.Themes = .F.
```
---
# 4) 圖片快取與 PictureVal:避免 I/O 與字串指派造成的閃爍
* 圖片不要每次事件都從檔案路徑載;**在應用層集中快取**至記憶體(字串二進位)後,再分配給每個 ssbutton 的 `PictureVal`。
* 你可以做個全域快取物件(或放在 `_Screen`),例如:
```foxpro
* 啟動時先建一次
_SCREEN.AddProperty("oImgCache", CREATEOBJECT("EMPTY"))
ADDPROPERTY(_SCREEN.oImgCache, "normal", FILETOSTR(FULLPATH("normal.png")))
ADDPROPERTY(_SCREEN.oImgCache, "hot", FILETOSTR(FULLPATH("hot.png")))
* ssbutton.Init 裡直接:
THIS.cPicNormal = _SCREEN.oImgCache.normal
THIS.cPicHot = _SCREEN.oImgCache.hot
```
* 指派 `Image.PictureVal` 比 `Picture="xxx.png"` 更穩且快(避免路徑解析與磁碟 I/O)。
---
# 5) 減少 Refresh 的觸發頻率與範圍
* 盡量不要用 `Thisform.Refresh()` 當成「万能重畫鍵」。改用:
* 只更新有改變的控制項(例如某個 `ssbutton.Refresh()`)。
* 如果只是換圖,**不需要 Refresh**,直接改 `PictureVal` 即會重繪該 Image。
* 若一定要全表單 Refresh,務必搭配第 2 點的 `FreezePaint/ThawPaint` 包起來。
---
# 6) 其他小訣竅(有需要再用)
* 對於覆蓋在一起的控制項,**把底層容器/Shape 設為 Opaque(BackStyle=1)**,減少底層「穿透重畫」。
* 若使用 Timer 造成頻繁 Refresh,調大 Interval 或改成事件驅動。
* 如果 ssbutton 還有其他子控制項(Label、Shape)參與動畫,考慮直接在一張 Image 上畫好圖(製圖),讓控制項數量最小化。
---
## 結論(推薦順序)
1. **把 2 個重疊 Image 改為 1 個 Image + `PictureVal` 切換**(最有效)。
2. **批次更新時用 `WM_SETREDRAW`(`FreezePaint/ThawPaint`)** 包起來。
3. **關掉 `Themes`**、集中 **圖檔快取**、避免頻繁 `Thisform.Refresh()`。
照這樣改,通常 15 顆 ssbutton 的「發抖/閃爍」會直接消失或降到幾乎看不到。如果你願意貼出 ssbutton 的定義(哪些事件切換可見度)、或是提供簡化 PRG/VCX,我可以幫你直接改成「單一 Image 切圖」版本。 |
|
回頂端 |
|
 |
|
|
您 無法 在這個版面發表文章 您 無法 在這個版面回覆文章 您 無法 在這個版面編輯文章 您 無法 在這個版面刪除文章 您 無法 在這個版面進行投票 您 無法 在這個版面附加檔案 您 無法 在這個版面下載檔案
|
|