2013-01-11 10 views
6

Ungefähr hier verlieren. Ich habe seit einer Stunde gegoogelt, um dieses kleine, aber unglaublich erschwerende Problem zu lösen.TabControl flackert, wenn das Tab-Symbol geändert wird

Ich habe eine TabControl auf meinem Formular mit zwei Registerkarten. Jede dieser Registerkarten hat ein 16x16-Symbol und etwas Text. Nichts Verrücktes hier.

Ich muss unter bestimmten Umständen eines der Registerkartensymbole blinken lassen. Also habe ich zwei Bilder erstellt, light_on.png und light_off.png und fügte sie zu ImageList von TabControl. Ich stelle einen Hintergrund-Timer ein, der zwischen den beiden Bildern hin- und herwechselt, um ein blinkendes Symbol zu simulieren. Funktioniert gut.

Es verursacht jedoch, alle Registerkartenheader neu zu zeichnen, wodurch sie flackern.

Die TabControl unterstützt keine Doppelpufferung, egal was Sie versuchen.

ich gefunden habe, die Menschen haben einen gewissen Erfolg Zähmung Flimmern mit diesem Code:

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 

das funktioniert, wie in, ist es nicht flackern ... aber die Symbole ändern sich auch optisch nicht mehr, es sei denn Der Mauszeiger bewegt sich über etwas, das ein Neuzeichnen verursacht.

Hat jemand alternative Lösungen oder Tricks, die funktionieren könnten? Dies ist eigentlich ein wesentliches Merkmal der Software.

Skeleton-Code:

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 
+0

... Ich könnte WAAY hier sein, aber was ist mit einem animierten Gif und dann müssen Sie sich keine Sorgen machen? –

+0

Die TabControl kann nicht doppelt gepuffert werden, Sie müssen also wahrscheinlich mit dieser Einschränkung leben oder Ihre blinkenden Glühbirnen so gestalten, dass sie irgendwo anders auf dem Bildschirm blinken. – LarsTech

+0

@JohnBustos Ich habe versucht, ein animiertes gif, funktioniert nicht (nicht animieren). Das ist die Art von Vorschlag, nach der ich gesucht habe, danke. – user1003916

Antwort

3

Dies ist eine schnelle Hack (es gibt mehrere Dinge, die Zwicken brauchen, aber es ist ein Anfang), um die Darstellung der Bilder von Hand zu tun.

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 

diese Schritte zum Einrichten Folgen Sie der Steuerung:

  1. Zu allererst eine ImageList Steuerung an den MyTabControl zuweisen und sie mit Bildern füllen.
  2. Als nächstes rufen Sie SetImages Methode, um zu definieren, welche Bilder auf jeder Registerkarte angezeigt werden sollen.

    MyTabControl1.SetImages (TabPage1, New List (Of String) Von { "icon.gif", "icon2.gif"}) MyTabControl1.SetImages (TabPage2, New List (Of String) Von { "myImage1.gif “,‚myImage2.gif‘})

Hinweis, dass der zweite Parameter der SetImages Methode ist eine Liste von Schlüsseln, die angeblich zur existiert auf dem ImageList. Die Steuerung wird den Rest erledigen ...

+0

Toller Beitrag, danke. – user1003916

Verwandte Themen