none
請問C#的控制項透明(空)的問題 RRS feed

  • 問題

  • 各位前輩大家好 , 我是最近碰C#的新手 , 最近遇到了這樣一個的問題
    其實最主要的是想做一個非矩形的控制項 , 雖然看過MSDN中有教如何做一個非矩形的Button
    不過實際測試了一下發現 , 其實是在一個矩形的控制項中畫出一個圓 , 但是問題還是在於 , 那個圓是畫在矩形控制項內,
    當我拖拉這個圓到另一個控制項上面的時後 , 會發生矩形的直角出現在另一個控制項上(即使已經將圓控制項的BackColor設定為Transparent)
    然而
    http://social.msdn.microsoft.com/Forums/zh-TW/233/thread/71637a76-be24-4b8a-83b3-fc1e6a8e1a2c/
    這位大大雖然說他用SetStyle(ControlStyles.UserPaint, false)可以達成目的,
    但我試了一下還是不行

    而Eric Tsai大大曾經在http://social.msdn.microsoft.com/forums/zh-TW/233/thread/e27fdbac-266c-4e68-a864-8104a35719d3/
    內提過
    利用PictureBox的方式製作出非矩形的控制項
    這個方法我有試出來 , 自己處理了一下相關滑鼠事件後 , 的確可以做到非矩形的控制項
    但另一個問題還是沒解決 , 那就是今天我把這個非矩形控制項拖拉到另一個控制項上面的時候
    PictureBox透空的部份依然會蓋到另一個控制項上 , 雖然號稱透空 , 不過卻是透空到Parent去.....而不是看到底下的控制項
    http://programfan.com/club/showpost.asp?id=12683<----這邊也是有人提到這樣的問題

    而且對PictureBox寫事件的時候有注意到 , 雖然PictureBox載進來的是有透空的圖形 , 但是我是對PictureBox寫事件
    所以我在透空的部位不管是Click,或是Move,PictureBox的確會被觸發,從頭到尾一直都是矩形的控制項(雖然看起來是非矩形的控制項)

    可是我總覺得應該可以很簡單的辦到才對 , 這問題困擾了我好久 , 請問各位前輩們這該怎麼處理呢??

    2009年5月12日 上午 11:14

解答

  • 多數的範例會把 CreateRegion 寫在 OnPaint 事件的複寫內,我的做法是另外寫,在 OnTextChanged 、OnFontChanged 等事件呼叫 CreateRegion ,這樣在 OnPaint 只要呼叫 FillRegion 即可,例如:

    Private Sub CreateRegion()
    	Dim grfx As Graphics = Me.CreateGraphics
    
    	Dim myGraphicsPath As New System.Drawing.Drawing2D.GraphicsPath(System.Drawing.Drawing2D.FillMode.Winding)
    	Dim origin As PointF = New PointF(0, 0)
    	Dim format As StringFormat = StringFormat.GenericDefault
    	myGraphicsPath.AddString(Text, Font.FontFamily, Font.Style, Font.SizeInPoints * (grfx.DpiX / 72), origin, format)
    	Me.Region = New Region(myGraphicsPath)
    
    	origin = Nothing
    	grfx.Dispose()
    	GC.Collect()
    End Sub
    
    更多的範例可以到 codeproject 去搜尋。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Lolota Lee 2009年5月20日 上午 09:28
    2009年5月13日 上午 06:21

所有回覆

  • 假設有PictureBox做出的控制項A
    與另一個其它的控制項B
    若A放到B上
    可設定
    A.Parent=B;

    http://www.dotblogs.com.tw/larrynung/
    2009年5月12日 上午 11:34
  • 假設有PictureBox做出的控制項A
    與另一個其它的控制項B
    若A放到B上
    可設定
    A.Parent=B;

    http://www.dotblogs.com.tw/larrynung/


    謝謝大大....你指的這篇我之前有看過,不過由於是透空到 Parent 上,所以當 Label_A (有透空的控制項)移動到 Label_B 時 , Label_B 依然沒有辦法完整無缺

    後來我仔細的想想 , 應該是控制項在透空時 , 程式是將Parent的 BackgroundImage 繪到透空的部份 , 所以當我拖拉 Label_A 時自然是以為透空部份是被"挖"空了
    但是如果拖拉到另一個控制項時就搞笑了 , 因為是"假挖空" , 所以在Label_B上面的部份Label_A , 自然出現的是Parent的BackgroundImage , 假挖空手法---->失敗
    不曉得這推論對不對....

    後來我試了一下大大說的設定Parent的方法.... , 如果沒有重疊到之前 , Parent先不變 , 如果開始重疊時就把Parent設定給B ,整個離開之後再還原原本的Parent
    結果發現這招幾乎可行! 可是就只有一點點小問題....如下(圖畫得不好,請見諒):
    那就是這個畫著 H 字母且有去背圖形的 Label 移動到畫著 T 字母這個 Label (這個就可以不必去背)的時候

              ---------------             ---------------------
             |       I_I       |           |            T            |
             |____I_I____|           |_______|_______|    


    當我Label_H.Top  < Label_T.Top 時 , 由於Label_H的Parent是設定為Label_T , 所以如果我Label_H尚未整個離開Label_T時 , 會發生Label_H的上半部消失了
    其實我猜想因為Parent是Label_T ,不在Label_T的範圍部份當然不會出現圖形

    一直到 Label_H.Top +Label_H.Height < Label_T.Top 時 , 也就是完全離開 Label_T 時 , 我把Parent還原回去,圖才又完整呈現
     
    所以小小的問題發生在.....
    如果我有控制項A與控制項B
    A放到B上時且A完全在B上的時候
    A.Parent = B是可以做到透空 , 完全拿出B之後再設定回原本的Parent => Perfect !

    但是如果A不完全在B上的時候
    那麼就會出現A有部份圖形被裁切掉了(因為有部份不在B範圍內,自然看不到部份圖)
    這問題卻暫時想不出怎麼解決....
    如果把這問題解決了,應該就可以達到一開始提問的問題了....
    我再來試試看.....

    2009年5月13日 上午 03:40
  • ...
    所以既有討論透過 FillRegion 去裁文字的方式,你根本沒看過。

    以此為關鍵字在各大原始碼網站就有一堆範例跟寫好的元件。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年5月13日 上午 05:38
  • ...
    所以既有討論透過 FillRegion 去裁文字的方式,你根本沒看過。

    以此為關鍵字在各大原始碼網站就有一堆範例跟寫好的元件。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務

    謝謝您的指教 , 只不過我用FullRegion的方法還沒有試出來,
    有心得或結論的話我會再提的
    2009年5月13日 上午 05:51
  • 多數的範例會把 CreateRegion 寫在 OnPaint 事件的複寫內,我的做法是另外寫,在 OnTextChanged 、OnFontChanged 等事件呼叫 CreateRegion ,這樣在 OnPaint 只要呼叫 FillRegion 即可,例如:

    Private Sub CreateRegion()
    	Dim grfx As Graphics = Me.CreateGraphics
    
    	Dim myGraphicsPath As New System.Drawing.Drawing2D.GraphicsPath(System.Drawing.Drawing2D.FillMode.Winding)
    	Dim origin As PointF = New PointF(0, 0)
    	Dim format As StringFormat = StringFormat.GenericDefault
    	myGraphicsPath.AddString(Text, Font.FontFamily, Font.Style, Font.SizeInPoints * (grfx.DpiX / 72), origin, format)
    	Me.Region = New Region(myGraphicsPath)
    
    	origin = Nothing
    	grfx.Dispose()
    	GC.Collect()
    End Sub
    
    更多的範例可以到 codeproject 去搜尋。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Lolota Lee 2009年5月20日 上午 09:28
    2009年5月13日 上午 06:21
  • 感謝前輩的指導,經過幾個小時的測試
    用FillRegion的方式的確已經做到非矩形的控制項
    而且沒有角落空白的問題,如心冷熱情熄大的code中所提的
    已經將做法全寫出來了
    最後只要CreateRegion後,在OnPaint地方FillRegion就好
    我也自己成功的試做出一個五邊形控制項,
    的確是我要的樣式.........

    接下來我想試一下載入去背圖形的部份 , 因為如果說今天的控制項是長得像運動飲料舒跑那個人形時
    那個圖形我....我不會畫.....
    所以應該是用載圖的方式把PNG檔讀進來,但是接下來該怎麼做我試了一陣子還沒試出來,不過我想應該也是朝FillRegion的方向去處理吧????

    各位前輩如果有什麼意見還請不吝賜教
    • 已編輯 jhjiang 2009年5月13日 上午 11:21 錯字導致語意錯誤
    2009年5月13日 上午 11:19
  • 我自己沒玩過圖檔的。
    在 codeproject 那邊看到的範例是搜尋指定透空的顏色,把沒透空的點位點掉,你可以去搜尋看看。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年5月13日 下午 01:25