none
FillRectangle - DrawRectangle clearing itself out.

    Question

  • Hi, I hope I am in the correct forum for this question.

    I am working in vb.net - Visual Studio 2010 - Version 10.0.40219.1 SP1 Rel.

    I have a listbox that is loaded with data at runtime via an sqlconnection, this works fine.

    The connection returns concantenated fields, this work fine.  When I select an item in the list box I want the DrawItem routine to change the background color (e.Graphics.FillRectangle), text color (e.Graphics.DrawString) and draw a red outline around the selected item (e.Graphics.DrawRectangle).  This almost works.

    When I click on the tem in the listbox, the background color is changed, the text color is changed and the outline of the rectangle is drawn, then....it all goes back to black text on  a white background.  I have stops in so I can see it do all this, it does flash on the screen quickly.

    My code is pretty basic, and I see nothing different from other code found on forums.  I cannot find any issues where the item is basically reset-cleared.  I have no code that clears the rectangle.

    An odd behaviour that I found was if entered numbers in the FillRectangle instead of rect the background color of the rectangle would change and not clear out.

    e.Graphics.FillRectangle(Brushes.Gold, rect)  - clears out

    e.Graphics.FillRectangle(Brushes.Gold, 0, 78, 310, 13) - rectangle fills

    If I set the x, y, width and height with rect.x, rect.y, rect.width, rect.height the rectangle still clears out.

    If I set the e.bounds or rect coordinates to an integer then use that to set the x, y, width and height the rectangle still clears out.

    This is the first time I have worked with doing anything like this on listbox, any help you can give me will be greatly appreciated.

    Dale,

    I have my code posted below.

    Private Sub listbox_DrawItem(sender As Object, e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox.DrawItem
            ListBox.DrawMode = DrawMode.OwnerDrawFixed
            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                Dim rect As System.Drawing.Rectangle = New Rectangle
                rect = e.Bounds
                e.Graphics.FillRectangle(Brushes.Gold, rect)
                e.Graphics.DrawString(ListBox.Items(e.Index).ToString(), e.Font, Brushes.DarkRed, rect.X, rect.Y)
                e.Graphics.DrawRectangle(Pens.Firebrick, rect.X, rect.Y, rect.Width, rect.Height)
                e.DrawFocusRectangle()
            End If
        End Sub


    • Edited by Dale Jay Tuesday, July 10, 2012 8:50 PM
    Tuesday, July 10, 2012 8:49 PM

Answers

  • Let's look if this fixes your problems:

    • Remove Application.DoEvents. The thread already has a message loop.
    • Graphics.Save is a function. If you ignore the return value, it's useless.
    • Exit Sub in the loop makes the loop useless.
    • Why do you write a loop? DrawItem is meant to draw one item.
    • Exit Sub before End Sub is not necessary
    • Why do you draw the Items of "listboxUnitcode" in "listbox"? You should better derive a listbox from the Listbox class and override OnDrawItem.



    Armin


    • Edited by Armin Zingler Thursday, July 19, 2012 3:09 PM
    • Marked as answer by Dale Jay Thursday, July 19, 2012 4:48 PM
    Thursday, July 19, 2012 3:09 PM

All replies

  • You have to set the DrawMode one time when you instantiate the control.  You must have done that or DrawItem wouldn't be called at all.  Remove the local DrawMode and try it.
    Tuesday, July 10, 2012 9:10 PM
  • Is that all the code? When you owner draw the listbox, you have to draw all the items. Your DrawItem routine above looks like it is only drawing items when they are selected and doing nothing with the items that are not selected. You need to draw both cases, selected and not selected. You also don't need to set the DrawMode each time, you just set it at design time in the listbox properties window. If that isn't set, the DrawItem event never fires.

    Matt Kleinwaks - MSMVP MSDN Forums Moderator - www.zerosandtheone.com

    Tuesday, July 10, 2012 9:11 PM
    Moderator
  • Thank you JohnWein and Kleinma,  I was off a few days so I am just getting back to this problem.

    On the DrawMode.OwnerDrawFixed I do have it set in the properties of the listbox,  I commented that out of the code so that it was not executed every time the code ran, and that did not change the behaviour of the listbox.

    Kleinma, I see what your saying about re-drawing all the non-selected items in the listbox.  I will have to think how to approach that as this is all new to me.

    This is the scope of the listbox, the user can select one item or multiple items to build a code string behind the scenes.  When they select an item it will be highlighted in the listbox and added to a code string.  The user will be able to select an item and possibly de-select it whick will remove it from the code string.

    All the highlighting does it show the user what they have already selected, that is why I was only dealing with the selected items in my code.

    So re-drawing all the selected and non-selected items each time is something I will have to think how to do, I made it this far.

    Dale,

    Monday, July 16, 2012 2:45 PM
  • Hi everyone, I have made progress on this issue, though now there is a new problem as always.  In working with the DrawItem routine I was trying to use the e.index to figure out what was selected and what was not.

    The fix was to use the listbox.selectedindex to find the selected items, then if the item was selected to use the e.graphics to fill and draw.  I will post my code, it does work.  When I load the box all of the fields are loaded and I can scroll up and down.  Then I can select items in the box and the background and text change color which is exactly what I wanted.

    Now the next problem......

    I have the items that are visible in the box, say 20 items, I select 5 and then either go to scroll up or down, when I scroll no more items appear (which were visible before when I scolled before I selected any items).  Now the items that were visible and selected are now not visible if they are scrolled out of the listbox window.

    The items are still there, if I just click on a now blank listbox the item is now visible as the background and text color have been changed by the code.

    I think it is a visiblity/refresh issue (that  does not change anything when I try it).  So I am not sure what to look at next.

    Any ideas will be greatly appreciated.  Dale,

    Private Sub listbox_DrawItem(sender As Object, e As System.Windows.Forms.DrawItemEventArgs) Handles listbox.DrawItem Dim rect As System.Drawing.Rectangle = New Rectangle rect = e.Bounds Dim x As Integer For x = listbox.SelectedIndex - 1 To 0 Step -1 e.Graphics.FillRectangle(Brushes.YellowGreen, rect.X, rect.Y, rect.Width, rect.Height)

    e.Graphics.DrawString(listboxUnitcode.Items(e.Index).ToString(), e.Font, Brushes.DarkRed, rect.X, rect.Y) System.Windows.Forms.Application.DoEvents() e.Graphics.Save() Exit Sub Next x e.Graphics.FillRectangle(Brushes.White, rect.X, rect.Y, rect.Width, rect.Height) e.Graphics.DrawString(listboxUnitcode.Items(e.Index).ToString(), e.Font, Brushes.Black, rect.X, rect.Y) System.Windows.Forms.Application.DoEvents() e.Graphics.Save() Exit Sub End Sub


    Thursday, July 19, 2012 1:46 PM
  • Look at some DrawItem examples.  Try to explain your reasoning for each statement you include in your application.  Unless you are paid by the line, there is no reason for adding random statements thoughout your code.
    • Edited by JohnWein Thursday, July 19, 2012 2:09 PM
    Thursday, July 19, 2012 2:06 PM
  • Hi John,

    I am not sure about what you are referring to, the code looks pretty straightforward as to other examples I have looked at.  The draw item is being fired of, I am getting the bounds of the rectangle, if it is the selected item then set the background color and text one way, if not set it another.

    There is only 16 lines of code (17 if you count the end if), so I don't really see any random - extraneous code in there.

    Like I said it is working, I do not see why the listbox is not displaying the items when scrolled.

    The above code is all there is to manipulating the listbox. 

    Thursday, July 19, 2012 2:48 PM
  • Hi John,

    I am not sure about what you are referring to, the code looks pretty straightforward as to other examples I have looked at.  The draw item is being fired of, I am getting the bounds of the rectangle, if it is the selected item then set the background color and text one way, if not set it another.

    There is only 16 lines of code (17 if you count the end if), so I don't really see any random - extraneous code in there.

    Like I said it is working, I do not see why the listbox is not displaying the items when scrolled.

    The above code is all there is to manipulating the listbox. 

    What does Application.DoEvents do?  What is the purpose of including it in your code?  What does e.Graphics.Save do?  What is the purpose of including it in your code?  What does "For x = listbox.SelectedIndex - 1 To 0 Step -1" do in your code?  What is the purpose of including it in your code?
    Thursday, July 19, 2012 3:06 PM
  • Let's look if this fixes your problems:

    • Remove Application.DoEvents. The thread already has a message loop.
    • Graphics.Save is a function. If you ignore the return value, it's useless.
    • Exit Sub in the loop makes the loop useless.
    • Why do you write a loop? DrawItem is meant to draw one item.
    • Exit Sub before End Sub is not necessary
    • Why do you draw the Items of "listboxUnitcode" in "listbox"? You should better derive a listbox from the Listbox class and override OnDrawItem.



    Armin


    • Edited by Armin Zingler Thursday, July 19, 2012 3:09 PM
    • Marked as answer by Dale Jay Thursday, July 19, 2012 4:48 PM
    Thursday, July 19, 2012 3:09 PM
  • Thanks for the reply, this is my first time doing this type of manipulation on a listbox, so some of the code is an attempt to get it functioning.

    Here is what I did:

    I removed the DoEvents, Graphics.Save and the Exit Sub.

    I had the For - Next in there as I thought it needed to go through all the items that were selected.  I have removed that part of the code.

    ListboxUnitCode is Listbox, when I was cleaning out all the commented code for posting I missed that one.

    How I thought DrawItem is operating is that it is drawing all the items each time time a selection is made on the listbox, or if the listbox is scrolled, so it is not doing as I thought.

    For the who knows how many times I re-wrote the code and it is now working correctly.

    The selected items are staying selected and all the items are visible when scrolling.

    So the main issue was getting a grasp on how DrawItem functions and going through the coding process to understand how it works.

    I have a next step on this application that will involve DrawItem and setting the colors of the selected items based on left and right mouse clicks.  I will see how I get with that now that I see how DrawItem functions.

    Private Sub listbox_DrawItem(sender As Object, e As System.Windows.Forms.DrawItemEventArgs) Handles listbox.DrawItem Dim rect As System.Drawing.Rectangle = New Rectangle rect = e.Bounds If Not (e.State And DrawItemState.Selected) = 0 Then e.Graphics.FillRectangle(Brushes.YellowGreen, e.Bounds) e.DrawFocusRectangle() Else e.Graphics.FillRectangle(Brushes.White, e.Bounds) End If e.Graphics.DrawString(listbox.Items(e.Index).ToString(), e.Font, Brushes.Black, rect.X, rect.Y)

    end sub


    Thursday, July 19, 2012 4:48 PM
  • Glad it's working now. A last comment: you don't need to assign a new rectangle to rect as it's overwritten anyway in the next line.  You would not even need it without the next line because Rectangle is a value type.

    Armin

    Thursday, July 19, 2012 4:54 PM
  • Thank you Armin for your help, I took out assigning a new rectangle.  I see what you are saying about it.  Part of coding is doing it out of habit, but it if can be done cleaner that is better.
    Thursday, July 19, 2012 6:07 PM