这里要忘记了。我一直在谷歌搜索一小时试图解决这个小问题,但令人难以置信的加剧了问题。
我的表单上有TabControl
,有两个标签。每个选项卡都有一个16x16图标和一些文本。没有什么可疯狂的。
在某些情况下,我需要让其中一个标签图标闪烁。因此,我创建了两个图像和,并将它们添加到ImageList
使用的TabControl
。我设置了一个后台计时器,可以在两个图像之间切换以模拟闪烁的图标。工作良好。
然而,它导致所有标签标题重绘,这使它们闪烁。
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
答案 0 :(得分: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
按照以下步骤设置控件:
ImageList
控件分配给MyTabControl
,并用图片填充。接下来,调用SetImages
方法来定义应在每个标签上显示哪些图像。
MyTabControl1.SetImages(TabPage1,New List(Of String)From {“icon.gif”,“icon2.gif”}) MyTabControl1.SetImages(TabPage2,新列表(字符串)来自{“myImage1.gif”,“myImage2.gif”})
请注意SetImages
方法的第二个参数是应该存在于ImageList
上的键列表。
控制将完成其余的工作......