Owner Draw

R

Rick

I'm in the process of creating an "owner drawn" list control. Each
item displays a 50 x 50 icon and a brief text description. There is a
scroll bar that's not part of the control, when used, it sets the
scrolltop property of the list, which triggers a repaint. Each icon
is 2-3k each and getting a fairly significant flicker when scrolling.
Is there another method I should be using to implement this, or is it
just a PPC limitation?


Public Class DrawnObjectList
Inherits Windows.Forms.Control

Private m_Objects As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
Private m_ScrollTop As Integer
Private strat As DrawingStrategy

Public Sub New()
Me.strat = New ObjectIconDrawingStrategy()
End Sub

Public Property ScrollTop() As Integer
Get
Return m_ScrollTop
End Get
Set(ByVal value As Integer)
m_ScrollTop = value
' force repaint
Me.Invalidate()
End Set
End Property


''' <summary>
''' List of objects to bind to
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Objects() As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
Get
' If the list hasn't been set, return an empty collection
If m_Objects Is Nothing Then
m_Objects = New
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
End If
Return m_Objects
End Get
Set(ByVal value As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection)
m_Objects = value
End Set
End Property

Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs)
If Objects.Count = 0 Then Exit Sub
Dim itemsPerPage As Integer
Dim FirstIndex As Integer
Dim LastIndex As Integer
Dim obj As MWG.PocketBirds.Model.Database.IdItObject

Me.strat.MaxHeight = Me.Height
Me.strat.MaxWidth = Me.Width

' Number of items that will be in view( or partially )
itemsPerPage = Me.strat.ItemsPerPage

' Index of first item to display
FirstIndex = strat.FirstIndex(Me.m_ScrollTop)

' Index of first item to display
LastIndex = strat.LastIndex(Me.m_ScrollTop)

' Draw all of the items
For i As Integer = FirstIndex To LastIndex
If i > Objects.Count - 1 Then Exit For
obj = Objects(i)

strat.DrawItem(e.Graphics, obj, m_ScrollTop, i)
Next



End Sub
End Class

Public Class ObjectIconDrawingStrategy
Inherits DrawingStrategy

Public Overrides ReadOnly Property ItemsPerPage() As Integer
Get
Return CType(Math.Ceiling(m_MaxHeight / ItemHeight) * 2, Integer) +
2
End Get
End Property

Public Overrides ReadOnly Property FirstIndex(ByVal scroll As
Integer) As Integer
Get
Return CType(Math.Floor(scroll / ItemHeight) * 2, Integer)
End Get
End Property

Public Overrides ReadOnly Property LastIndex(ByVal scroll As Integer)
As Integer
Get
Return FirstIndex(scroll) + ItemsPerPage - 1
End Get
End Property

Public Sub New()
Me.m_ItemHeight = 86
Me.m_ItemWidth = 66
m_Icons = New Hashtable
End Sub

Private m_Icons As Hashtable

Public Overrides Sub DrawItem(ByVal gfx As System.Drawing.Graphics,
ByVal entity As MWG.PocketBirds.Model.Database.IdItEntity, ByVal
scroll As Integer, ByVal index As Integer)
Dim bm As Bitmap
Dim itemRect As Rectangle
Dim brush As New System.Drawing.SolidBrush(Color.Black)
Dim top As Integer

' Get the icon from either cache or file system
If Not m_Icons.ContainsKey("O" + entity.id.ToString()) Then
bm = New Bitmap(Globals.Model.GetBinary("O" + entity.id.ToString(),
True))
m_Icons.Add("O" + entity.id.ToString(), bm)
Else
bm = CType(m_Icons("O" + entity.id.ToString()), Bitmap)
End If


If index Mod 2 = 0 Then ' Even items

top = CType(((index / 2) * Me.m_ItemHeight), Integer) - scroll
' Draw the icon
gfx.DrawImage(bm, 2, top + 2)
' Rectangle for bird name
itemRect = New Rectangle(2, top + 50 + 2, ItemWidth, 9)
' Write bird name
' TODO: Center and wrap string
gfx.DrawString(entity.ToString(), New
System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 5,
FontStyle.Regular), brush, itemRect)

Else ' Odd Items

top = CType((((index - 1) / 2) * Me.m_ItemHeight), Integer) -
scroll
' Draw the icon
gfx.DrawImage(bm, 68, top + 2) ' itemRect, 0, 0, bm.Width,
bm.Height, GraphicsUnit.Pixel, New
System.Drawing.Imaging.ImageAttributes())
' Rectangle for bird name
itemRect = New Rectangle(68, top + 50 + 2, ItemWidth, 9)
' Write bird name
gfx.DrawString(entity.ToString(), New
System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 5,
FontStyle.Regular), brush, itemRect)

End If
End Sub
End Class
 
G

Guest

You should be drawing to a backbuffer then blitting to the screen rather
than doing all drawing right to the screen (double buffering). You're also
creating a lot of stock graphics objects with every OnPaint or PaintItem.
Cache those globally and used the cached copy.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
R

Rick

Ok, so, you say that I should create a bitmap in my onpaint, draw
there, then draw the bitmap the screen?
 
G

Guest

Like all other objects I'd say create it once, in OnPaint clear and draw to
it, then blit it to the target graphics at the end. Depending on what
you're drawing triple-buffering may even be better (though it doesn't seem
like it for this specific case).


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
R

Rick

Well, I took your advise and double buffered, creating a bitmap and
keeping a local copy. I also created a graphics object and kept a
local copy of it as well. I'm still getting flicker. I'm drawing 50
x 50 png images, roughly 2 - 3 in size to the screen along with a
little text.

See the below code to see what I've done. Anymore suggestions? Care
elaborate on the triple buffer thought?

Rick

Public Class DrawnObjectList
Inherits Windows.Forms.Control

Private m_Objects As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
Private m_ScrollTop As Integer
Private strat As DrawingStrategy
Protected buffer As Bitmap
Protected gfx As Graphics
Protected bg As New SolidBrush(Color.White)
Protected screenGfx As Graphics

Public Sub New()


Me.strat = New ObjectIconDrawingStrategy()
buffer = New Bitmap(Me.Width, Me.Height)
gfx = Graphics.FromImage(buffer)
gfx.FillRegion(bg, gfx.Clip)

End Sub

Public Property ScrollTop() As Integer
Get
Return m_ScrollTop
End Get
Set(ByVal value As Integer)
m_ScrollTop = value
' force repaint
Me.Invalidate()
End Set
End Property


''' <summary>
''' List of objects to bind to
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Objects() As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
Get
' If the list hasn't been set, return an empty collection
If m_Objects Is Nothing Then
m_Objects = New
MWG.PocketBirds.Model.Collections.IdItObjectsCollection
End If
Return m_Objects
End Get
Set(ByVal value As
MWG.PocketBirds.Model.Collections.IdItObjectsCollection)
m_Objects = value
End Set
End Property

Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs)
If Objects.Count = 0 Then Exit Sub
Dim itemsPerPage As Integer
Dim FirstIndex As Integer
Dim LastIndex As Integer
Dim obj As MWG.PocketBirds.Model.Database.IdItObject

Me.strat.MaxHeight = Me.Height
Me.strat.MaxWidth = Me.Width

' Clear the buffer with the bg color
gfx.Clear(Color.White)

' Number of items that will be in view( or partially )
itemsPerPage = Me.strat.ItemsPerPage

' Index of first item to display
FirstIndex = strat.FirstIndex(Me.m_ScrollTop)

' Index of first item to display
LastIndex = strat.LastIndex(Me.m_ScrollTop)

' Draw all of the items
For i As Integer = FirstIndex To LastIndex
If i > Objects.Count - 1 Then Exit For
obj = Objects(i)

' Draw item to buffer
strat.DrawItem(gfx, obj, m_ScrollTop, i)
Next

' Draw buffer to screen
e.Graphics.DrawImage(buffer, 0, 0)


End Sub
End Class
 
R

Rick

Ah ha, overriding onpaintbackground did it. The last attempt, I had
disabled deploy in the solution config when I started messing with an
MFC version. I very much appreciate your dilligence.

Rick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top