JaedenRuiner
Well-known member
- Joined
- Aug 13, 2007
- Messages
- 340
- Programming Experience
- 10+
Well, i'm completely editing this post because well, i've figured out how to do quite a bit of what I want by just overriding the entire Paint methods and doing it my way from scratch.
If you set the UserPaint style to the control, the OnPaint/OnPaintBackground events fire, which means the background is drawn but I have to draw the bar. Not much of a issue, i've done the 2 Label progress bar hack before, so drawing the continuous bar shouldn't be an issue.
But then I went to work on my Marquee animation. I got it working so even in design time I could actually see it functioning, (though I will probably take that out later).
So I figured I'd Run the application, (which makes a call to the form with the component and sets it initially in Marquee mode.
Now, in order to get the "cycling" write, I'd either have to call the marque step function from within my form, (similarly to how one would have to set the continuous "progress value" and I really didn't want to do that, so I decided to handle the motion internally...with a Timer.
When running the application though (for it works find in design mode) as soon as the marquee starts and the timer triggers the "step" function (my personal step not the built in one) I get a thread access violation error from the Forms Assembly when I try to set the ProgressBar.Value property. I'm not creating any threads so this is a built in .net thing. What's going on and what would be the recommended course of action to clear this up?
thanks
If you set the UserPaint style to the control, the OnPaint/OnPaintBackground events fire, which means the background is drawn but I have to draw the bar. Not much of a issue, i've done the 2 Label progress bar hack before, so drawing the continuous bar shouldn't be an issue.
But then I went to work on my Marquee animation. I got it working so even in design time I could actually see it functioning, (though I will probably take that out later).
So I figured I'd Run the application, (which makes a call to the form with the component and sets it initially in Marquee mode.
Now, in order to get the "cycling" write, I'd either have to call the marque step function from within my form, (similarly to how one would have to set the continuous "progress value" and I really didn't want to do that, so I decided to handle the motion internally...with a Timer.
When running the application though (for it works find in design mode) as soon as the marquee starts and the timer triggers the "step" function (my personal step not the built in one) I get a thread access violation error from the Forms Assembly when I try to set the ProgressBar.Value property. I'm not creating any threads so this is a built in .net thing. What's going on and what would be the recommended course of action to clear this up?
thanks
VB.NET:
Public Class FlufProgBar
Inherits System.Windows.Forms.ProgressBar
Private Shared MarqueeChars() As Char = {"/", "-", "\", "|"}
Private WithEvents _tmr As New Timers.Timer()
Private _alpha As Byte = 192
Private _mqwidth As Integer
Private _showtext As Boolean = True
Private _mcI As Integer = 0
Private _mcDir As Integer = 1
Private _mqDir As Integer = 1
Private _br As New SolidBrush(Color.White)
Private _tcol As System.Drawing.Color
Private _msize As System.Drawing.SizeF
Private _mqpos As System.Drawing.RectangleF
<EditorBrowsable(EditorBrowsableState.Always), Browsable(True)> _
Public Overrides Property Font() As System.Drawing.Font
Get
Return MyBase.Font
End Get
Set(ByVal value As System.Drawing.Font)
MyBase.Font = value
End Set
End Property
<Browsable(True)> _
Public Property ShowText() As Boolean
Get
Return _showtext
End Get
Set(ByVal value As Boolean)
_showtext = value
Me.Invalidate()
End Set
End Property
<Browsable(True)> _
Public Property TextColor() As Color
Get
Return _tcol
End Get
Set(ByVal value As Color)
_tcol = Color.FromArgb(_alpha, value.R, value.G, value.B)
Me.Invalidate()
End Set
End Property
<Browsable(True)> _
Public Property TextAlpha() As Byte
Get
Return _alpha
End Get
Set(ByVal value As Byte)
_alpha = value
TextColor = _tcol
End Set
End Property
<Browsable(False)> _
Public Property MarqueeSize() As System.Drawing.SizeF
Get
Return _msize
End Get
Set(ByVal value As System.Drawing.SizeF)
_msize = value
Me.Invalidate()
End Set
End Property
<Browsable(True)> _
Public Property MarqueeWidth() As Integer
Get
Return _mqwidth
End Get
Set(ByVal value As Integer)
_mqwidth = value
_msize.Width = CSng(_mqwidth * Me.ClientRectangle.Width) / Me.Maximum
Me.Invalidate()
End Set
End Property
<Browsable(True)> _
Public Property MarqueeOn() As Boolean
Get
Return _tmr.Enabled
End Get
Set(ByVal value As Boolean)
If (Me.Style = System.Windows.Forms.ProgressBarStyle.Marquee) AndAlso (_tmr.Enabled <> value) Then
_tmr.Enabled = value
End If
End Set
End Property
'Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
' MyBase.OnHandleCreated(e)
' dc = Graphics.FromHwnd(Me.Handle)
'End Sub
'Protected Overrides Sub OnHandleDestroyed(ByVal e As System.EventArgs)
' dc.Dispose()
' MyBase.OnHandleDestroyed(e)
'End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Select Case Me.Style
Case ProgressBarStyle.Blocks
Case ProgressBarStyle.Continuous
PaintContinuous(e)
Case ProgressBarStyle.Marquee
PaintMarquee(e)
End Select
MyBase.OnPaint(e)
End Sub
Public Shadows Property MarqueeAnimationSpeed() As Integer
Get
Return MyBase.MarqueeAnimationSpeed
End Get
Set(ByVal value As Integer)
MyBase.MarqueeAnimationSpeed = value
_tmr.Interval = value
End Set
End Property
Private Sub PaintContinuous(ByVal e As PaintEventArgs)
Dim rc As RectangleF = New RectangleF(e.ClipRectangle.Location, _
New SizeF(CSng(e.ClipRectangle.Width * Me.Value / Me.Maximum), e.ClipRectangle.Height))
Dim r2 As New Region(rc)
_br.Color = ForeColor
e.Graphics.FillRectangle(_br, rc)
If _showtext Then
Dim r1 As New Region(e.ClipRectangle)
PaintText(e, (Me.Value * 100 \ Me.Maximum).ToString & "%", r1, r2)
r1.Dispose()
End If
r2.Dispose()
End Sub
Private Sub PaintMarquee(ByVal e As PaintEventArgs)
Dim rc As RectangleF = e.ClipRectangle
Dim pos As Single = CSng(Value * rc.Width / Me.Maximum)
Dim comp As Single = _msize.Width - CSng(Value * _msize.Width / Me.Maximum)
_mqpos.Size = _msize
_mqpos.X = pos - comp
_br.Color = ForeColor
e.Graphics.FillRectangle(_br, _mqpos)
If _showtext Then
Dim r1 As New Region(rc)
Dim r2 As New Region(_mqpos)
PaintText(e, MarqueeChars(_mcI), r1, r2)
r1.Dispose()
r2.Dispose()
End If
End Sub
Private Sub DoMarqueeStep()
Value += (Me.Step * _mqDir)
If (Value >= Maximum OrElse Value <= 0) Then
_mqDir *= -1
_mcDir *= -1
End If
_mcI += _mcDir
If (_mcI < 0 OrElse _mcI > 3) Then
_mcI = IIf(_mcDir = 1, 0, 3)
End If
End Sub
Private Sub PaintText(ByVal e As PaintEventArgs, ByVal text As String, ByVal r1 As Region, ByVal r2 As Region)
If _showtext Then
Dim rc As RectangleF = e.ClipRectangle
Dim sz As System.Drawing.SizeF = e.Graphics.MeasureString(text, Me.Font)
Dim pt As New System.Drawing.PointF((rc.Width - sz.Width) / 2, (rc.Height - sz.Height) / 2)
_br.Color = _tcol
e.Graphics.Clip = r1
e.Graphics.DrawString(text, Me.Font, _br, pt)
_br.Color = Color.FromArgb(_alpha, BackColor.R, BackColor.G, BackColor.B)
r1.Exclude(r2)
e.Graphics.Clip = r2
e.Graphics.DrawString(text, Me.Font, _br, pt)
End If
End Sub
Public Sub New()
MyBase.New()
SetStyle(ControlStyles.UserPaint, True)
TextColor = Me.ForeColor
MarqueeWidth = 15
_mqpos = New RectangleF(Me.ClientRectangle.Location, _msize)
_tmr.Enabled = False
_tmr.Interval = Me.MarqueeAnimationSpeed
End Sub
Private Sub _tmr_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _tmr.Elapsed
DoMarqueeStep()
'Invalidate()
End Sub
End Class
Last edited: