Owner-Draw ListBox problems

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • dan heskett

    #1

    Owner-Draw ListBox problems

    I am owner-drawing a listbox, in an attempt to create a nice list with some
    custom "fields" and text layout.

    Essentially it works, but I must be missing something big, conceptually,
    because I get all kinds of screen artifacts and weirdness.

    My general goal is: list item with a few areas for text, every other item
    shaded a light color for readability, font color changes with selection. The
    listbox is populated with custom structurs loaded with data. Here is my
    prototype code so far:

    Private Sub lstAccounts_Dra wItem(ByVal sender As Object, ByVal e As
    System.Windows. Forms.DrawItemE ventArgs) Handles lstAccounts.Dra wItem'

    ' Set fonts and colors
    Dim cLine As New System.Drawing. Pen(System.Draw ing.SystemColor s.ControlDark)
    Dim fLarge As New Font("Verdana", 12, FontStyle.Bold, GraphicsUnit.Pi xel)
    Dim fNorm As New Font("Verdana", 10, FontStyle.Regul ar, GraphicsUnit.Pi xel)
    Dim fMed As New Font("Verdana", 11, FontStyle.Regul ar, GraphicsUnit.Pi xel)
    Dim bNorm As System.Drawing. Brush

    ' Make Variable Defaults
    Dim mX As Single = e.Bounds.Width
    Dim mT As Single = e.Bounds.Top
    Dim mY As Single = e.Bounds.Height
    Dim m75 As Single = mX * 0.75
    Dim m50 As Single = mX * 0.5
    Dim objA As Account
    Dim objS As System.Drawing. SizeF

    ' Get Object
    objA = lstAccounts.Ite ms(e.Index)

    ' Draw background
    e.DrawBackgroun d()
    e.DrawFocusRect angle()

    ' Assign Pen Color
    If (e.State = DrawItemState.S elected) Or (e.State = DrawItemState.S elected +
    DrawItemState.F ocus) Then
    bNorm = System.Drawing. Brushes.White
    Else
    bNorm = System.Drawing. Brushes.Black
    End If

    ' Draw Background if not selected and odd
    If e.Index Mod 2 = 1 Then
    If (e.State <> DrawItemState.S elected) And (e.State <>
    DrawItemState.S elected + DrawItemState.F ocus) Then
    e.Graphics.Fill Rectangle(Syste m.Drawing.Syste mBrushes.Contro lLight,
    0, mT, mX, mT + mY)
    End If
    End If

    ' Draw Bottom Line
    e.Graphics.Draw Line(cLine, 0, mT + mY, mX, mT + mY)

    ' Draw 75% Line, 50% line
    e.Graphics.Draw Line(cLine, m75, mT, m75, mT + mY)
    e.Graphics.Draw Line(cLine, m50, mT, m50, mT + mY)
    e.Graphics.Draw Line(cLine, m50, mT + (mY / 2), m75, mT + (mY / 2))

    ' Draw Name of Item, Description
    e.Graphics.Draw String(objA.Acc ount_Name, fLarge, bNorm, 5, mT + 5)
    e.Graphics.Draw String(objA.Acc ount_Memo, fNorm, bNorm, 5, mT + 20)

    ' Draw Balance Information (right aligned)
    objS = e.Graphics.Meas ureString(objA. Account_Balance .ToString("$0.0 0"), fMed)
    e.Graphics.Draw String(objA.Acc ount_Balance.To String("$0.00") , fMed, bNorm,
    mX - objS.Width - 5, mT + 15)

    End Sub

    Like I said, this code essentially works. Start it up, add some items to
    the list box, it shows correctly. However, if you resize the form, or give
    focus, or remove focus, or generally interact with it the rendering goes
    bannas. What am I missing? Anyone out there with more experience than me?
    (Read: any experience in this regard!)

    Many thanks!
  • Larry Lard

    #2
    Re: Owner-Draw ListBox problems


    dan heskett wrote:[color=blue]
    > I am owner-drawing a listbox, in an attempt to create a nice list with some
    > custom "fields" and text layout.
    >
    > Essentially it works, but I must be missing something big, conceptually,
    > because I get all kinds of screen artifacts and weirdness.
    >
    > My general goal is: list item with a few areas for text, every other item
    > shaded a light color for readability, font color changes with selection. The
    > listbox is populated with custom structurs loaded with data. Here is my
    > prototype code so far:[/color]

    [code snipped. code is all fine IMO, except that you run without Option
    Strict On, but that's not important right now. Also, all DrawItem
    should have

    If e.Index = -1 Then Exit Sub

    at the start, because you DO get called by empty listboxes. Anyway]
    [color=blue]
    > Like I said, this code essentially works. Start it up, add some items to
    > the list box, it shows correctly. However, if you resize the form, or give
    > focus, or remove focus, or generally interact with it the rendering goes
    > bannas. What am I missing? Anyone out there with more experience than me?
    > (Read: any experience in this regard!)[/color]

    An interesting problem. I have implemented owner drawn listboxes in the
    past, and found things largely went as planned in DrawItem. So I set
    about creating a minimal example of your problem. This is what I came
    up with:

    Create a Windows Forms app, drop a list box and a button on the form,
    anchor the listbox to all four sides of the form (so that we can induce
    it to redraw by resizing the form). Set the listbox DrawMode to
    OwnerDrawFixed. Then here's some code:

    Private Sub Button1_Click(B yVal sender As System.Object, ByVal e As
    System.EventArg s) Handles Button1.Click
    With ListBox1.Items
    .Clear()
    .Add("apple apple apple apple apple apple apple apple apple
    ")
    .Add("banana banana banana banana banana banana banana
    banana banana ")
    .Add("grape grape grape grape grape grape grape grape grape
    ")
    End With
    End Sub

    Private Sub ListBox1_DrawIt em(ByVal sender As Object, ByVal e As
    System.Windows. Forms.DrawItemE ventArgs) Handles ListBox1.DrawIt em
    With e
    If .Index = -1 Then Exit Sub

    .DrawBackground ()

    .Graphics.DrawS tring(ListBox1. Items(.Index).T oString,
    Me.Font, Brushes.Black, _
    New PointF(.Bounds. Left, .Bounds.Top)) ' Line XXX

    .DrawFocusRecta ngle()
    End With
    End Sub


    Now, in this example as it stands, all the DrawItem does is duplicate
    the behaviour of a normal listbox. When you resize the form, everything
    WORKS.

    Now, change Line XXX to

    New PointF(.Bounds. Right - 10, .Bounds.Top)) ' Line XXX-2

    We are now asking that each listbox item gets drawn starting 10 pixels
    from the right hand edge of the list box (This means of course we don't
    get to see much text, but this is just an example).

    Now try it. On my machine, as I drag the form wider, *only the first
    item in the listbox (apple...) gets redrawn correctly* - the second and
    third lines show severe graphics redraw issues.

    Trying .Right\2 gives similar results. However, something like .Left+10
    is *fine*.

    So where does that leave us? I call bug, but that isn't immediately
    useful. The key seems to be:

    ****
    When owner-drawing, make all your drawn stuff 'anchored' to the TOP
    LEFT of e.Bounds
    ****

    Thoughts and experiments from others welcome!

    --
    Larry Lard
    Replies to group please

    Comment

    • dan heskett

      #3
      Re: Owner-Draw ListBox problems

      Larry,

      Thanks for your help! I notice all kinds of odd behaviour, but I figured
      out my original problem by accident.

      For one thing, I need to invalidate the control on refresh to cause the
      existing items to be redrawn.

      Second thing, I was using the Top + Height as the parameter for where to
      draw my bottom line on the item. The problem is that this position is
      actually the first pixel of the *next* item, so item #1 is drawn, and it's
      good, but when item #2 is drawn it overwrites the line drawn on the previous
      item.

      Thanks for your help!

      Comment

      Working...