VFP 愛用者社區 首頁 VFP 愛用者社區
本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入

thisform.refresh 使得 image control 圖片閃問題

 
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區
上一篇主題 :: 下一篇主題  
發表人 內容
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
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件 參觀發表人的個人網站 MSN Messenger
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 切圖」版本。
回頂端
檢視會員個人資料 發送私人訊息
從之前的文章開始顯示:   
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區 所有的時間均為 台北時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
無法 在這個版面附加檔案
無法 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作