簡體   English   中英

更改選項卡圖標時TabControl閃爍

[英]TabControl flickering when changing the tab's icon

我要在這里失去理智。 我一直在谷歌搜索一小時試圖解決這個小問題,但令人難以置信的加重問題。

我的表單上有一個帶有兩個選項卡的TabControl 每個選項卡都有一個16x16圖標和一些文本。 這里沒什么可瘋狂的。

在某些情況下,我需要讓其中一個標簽圖標閃爍。 所以我創建了兩個圖像, light_on.png light_off.png 並將它們添加到TabControl使用的ImageList 我設置了一個后台計時器,可以在兩個圖像之間切換以模擬閃爍的圖標。 工作良好。

但是,它導致所有標簽標題重繪,這使它們閃爍。

無論您嘗試做什么, TabControl都不支持雙緩沖。

我發現人們使用這段代碼有一些成功馴服閃爍:

    Protected Overrides ReadOnly Property CreateParams() As CreateParams 
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or &H2000000
            Return cp
        End Get
    End Property

這有效,因為它不會閃爍......但除非鼠標光標懸停在導致重繪的內容之上,否則圖標也不會在視覺上發生變化。

有沒有人有任何可行的替代解決方案或技巧? 這實際上是該軟件非常重要的功能。

骨架代碼:

Public Class Form1
    Dim BlinkTimer As Windows.Forms.Timer
    Dim BlinkToggler As Boolean = False

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        InitBlinker()
    End Sub

    Private Sub InitBlinker()
        BlinkTimer = New Windows.Forms.Timer
        AddHandler BlinkTimer.Tick, AddressOf Blinker_Tick
        With BlinkTimer
            .Enabled = True
            .Interval = 250
        End With
        StartBlinker()
    End Sub
    Public Sub StartBlinker()
        SomeTabPage.ImageKey = "light_off.png"
        BlinkToggler = False
        BlinkTimer.Start()
    End Sub
    Public Sub StopBlinker()
        SomeTabPage.ImageKey = "light_off.png"
        BlinkToggler = False
        BlinkTimer.Stop()
    End Sub
    Private Sub Blinker_Tick()
        If BlinkToggler Then
            SomeTabPage.ImageKey = "light_on.png"
        Else
            SomeTabPage.ImageKey = "light_off.png"
        End If
        BlinkToggler = Not BlinkToggler
    End Sub

End Class

這是一個快速入侵(有幾件事需要調整,但這是一個開始)手工繪制圖像。

Imports System.Threading

Public Class MyTabControl
    Inherits TabControl

    Private tabsImages As New Concurrent.ConcurrentDictionary(Of TabPage, List(Of String))
    Private tabsImagesKeys As New Concurrent.ConcurrentDictionary(Of TabPage, String)

    Private cycleImagesThread As Thread

    Private mInterval As Integer = 500

    Public Sub New()
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)

        Me.DrawMode = TabDrawMode.OwnerDrawFixed

        cycleImagesThread = New Thread(AddressOf CycleImagesLoop)
        cycleImagesThread.Start()
    End Sub

    Protected Overrides Sub OnHandleCreated(e As EventArgs)
        If Me.FindForm IsNot Nothing Then AddHandler CType(Me.FindForm, Form).FormClosing, Sub() cycleImagesThread.Abort()
        MyBase.OnHandleCreated(e)
    End Sub

    Private Sub CycleImagesLoop()
        Do
            Thread.Sleep(mInterval)

            If tabsImagesKeys.Count > 0 Then
                For Each tabImageKey In tabsImagesKeys
                    Dim index = tabsImages(tabImageKey.Key).IndexOf(tabImageKey.Value)
                    index += 1
                    index = index Mod tabsImages(tabImageKey.Key).Count
                    tabsImagesKeys(tabImageKey.Key) = tabsImages(tabImageKey.Key)(index)
                Next

                Me.Invalidate()
            End If
        Loop
    End Sub

    Public Property Interval As Integer
        Get
            Return mInterval
        End Get
        Set(value As Integer)
            mInterval = value
        End Set
    End Property

    Public Sub SetImages(tabPage As TabPage, images As List(Of String))
        If tabsImages.ContainsKey(tabPage) Then
            tabsImages(tabPage) = images
        Else
            tabsImages.TryAdd(tabPage, images)
        End If
        tabsImagesKeys(tabPage) = images.First()
    End Sub

    Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
        Dim g As Graphics = e.Graphics
        Dim r As Rectangle = e.Bounds
        Dim tab As TabPage = Me.TabPages(e.Index)
        Dim tabImage As Image

        Using b = New SolidBrush(IIf(e.State = DrawItemState.Selected, Color.White, Color.FromKnownColor(KnownColor.Control)))
            g.FillRectangle(b, r)
        End Using

        If tabsImagesKeys.Count > 0 OrElse Me.ImageList IsNot Nothing Then
            If tabsImagesKeys.ContainsKey(tab) Then
                tabImage = Me.ImageList.Images(tabsImagesKeys(tab))
                g.DrawImageUnscaled(tabImage, r.X + 4, r.Y + (r.Height - tabImage.Height) / 2)
            End If
            r.X += Me.ImageList.ImageSize.Width + 4
        End If

        Using b = New SolidBrush(tab.ForeColor)
            Dim textSize = g.MeasureString(tab.Text, tab.Font)
            g.DrawString(tab.Text, tab.Font, b, r.X, r.Y + (r.Height - textSize.Height) / 2)
        End Using

        MyBase.OnDrawItem(e)
    End Sub
End Class

請按照以下步驟設置控件:

  1. 首先,將一個ImageList控件分配給MyTabControl並用圖像填充它。
  2. 接下來,調用SetImages方法來定義應在每個選項卡上顯示的圖像。

    MyTabControl1.SetImages(TabPage1,New List(Of String)From {“icon.gif”,“icon2.gif”})MyTabControl1.SetImages(TabPage2,New List(Of String)From {“myImage1.gif”,“myImage2。 GIF“})

請注意, SetImages方法的第二個參數是應該存在於ImageList上的鍵列表。 控制將完成剩下的工作......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM