6

ここで気が狂いそうです。私はこの小さな問題を解決しようと 1 時間グーグルで検索してきましたが、信じられないほど深刻な問題です。

フォームにTabControl2 つのタブがある。これらの各タブには、16x16 のアイコンといくつかのテキストがあります。ここではクレイジーなことは何も起こっていません。

特定の状況下で、タブ アイコンの 1 つを点滅させる必要があります。そこで、2 つのイメージを作成light_on.pngし、それらを で使用される にlight_off.png追加しました。アイコンの点滅をシミュレートするために、2 つの画像を切り替えるバックグラウンド タイマーを設定しました。正常に動作します。ImageListTabControl

ただし、すべてのタブ ヘッダーが再描画され、ちらつきます。

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
4

1 に答える 1

3

これは、手動で画像を描画するための簡単なハックです (微調整が必​​要なことがいくつかありますが、これが開始点です)。

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"})

このメソッドの 2 番目のパラメータは、SetImagesに存在するはずのキーのリストであることに注意してくださいImageList。コントロールは残りを行います...

于 2013-01-12T08:17:59.157 に答える