Guest Vax Posted June 28, 2002 Posted June 28, 2002 I'm trying to figure out how the hell to make a derived class from the ListBox that will allow me to make a ListBox with individual fonts and colors for each list item. This is quite far afield from my normal programming stuff, and I am getting a little frustrated. I also saw this OwnerDraw thing. Never played with it, don't know the code to make this work. Maybe this is the simple solution? Can anyone give me a code snippet to show me how to use this? I'd appreciate it. Quote
*Gurus* divil Posted June 28, 2002 *Gurus* Posted June 28, 2002 Look in the .NET forum at the URL I posted yesterday. If you search that page for "listbox", I'm fairly sure I saw a link to a tutorial on ownerdrawing in the .NET framework. Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
Guest Vax Posted June 28, 2002 Posted June 28, 2002 (edited) Hmmm.... I've got the code here, but I feel like an idiot. I have no idea how to implement this crap. The code tries to explain itself, but with no visual reference, I can't figure out what I need to do to modify this to my purposes. Hell, I don't even know where to put this code in my project. It looks like a class module, but I'm looking to make a static control. More help, please! Code follows: '------------------------------------------------------------------------------ '/ <copyright from='1997' to='2001' company='Microsoft Corporation'> '/ Copyright (c) Microsoft Corporation. All Rights Reserved. '/ '/ This source code is intended only as a supplement to Microsoft '/ Development Tools and/or on-line documentation. See these other '/ materials for detailed information regarding Microsoft code samples. '/ '/ </copyright> '------------------------------------------------------------------------------ Imports System Imports System.ComponentModel Imports System.Drawing Imports System.Drawing.Drawing2D Imports System.Drawing.Text Imports System.Reflection Imports System.Windows.Forms Namespace Microsoft.Samples.WinForms.Vb.OwnerDrawListBox 'This sample control demonstrates various properties and 'methods for the ListBox control. Public Class OwnerDrawListBox Inherits System.Windows.Forms.Form 'Used to paint the list box Private listBoxBrushes() As Brush Private listBoxHeights() As Integer = {50, 25, 33, 15} Private sansSerifFontFamily As FontFamily 'Public Constructor Public Sub New() MyBase.New() sansSerifFontFamily = new FontFamily (GenericFontFamilies.SansSerif) ' This call is required for support of the Windows Forms Form Designer. InitializeComponent() OwnerDrawListBox = Me 'Set up the brushes we are going to use 'Load the image to be used for the background from the exe's resource fork Dim backgroundImage As Image = New Bitmap([Assembly].GetExecutingAssembly().GetManifestResourceStream("colorbars.jpg")) 'Now create the brush we are going to use to paint the background Dim backgroundBrush As Brush = New TextureBrush(backgroundImage) Dim r As Rectangle r = New Rectangle(0, 0, listBox1.Width, 100) Dim lb As New LinearGradientBrush(r, Color.Red, Color.Yellow, LinearGradientMode.Horizontal) listBoxBrushes = New Brush() {backgroundBrush, Brushes.LemonChiffon, lb, Brushes.PeachPuff} End Sub 'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub #Region " Windows Form Designer generated code " 'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer Private WithEvents listBox1 As System.Windows.Forms.ListBox Private WithEvents OwnerDrawListBox As System.Windows.Forms.Form 'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container() Me.listBox1 = New System.Windows.Forms.ListBox() Me.listBox1.ColumnWidth = 144 Me.listBox1.ForeColor = SystemColors.WindowText Me.listBox1.IntegralHeight = False Me.listBox1.Items.AddRange(New Object() {"First", "Second", "Third", "Fourth"}) Me.listBox1.Location = New System.Drawing.Point(8, 24) Me.listBox1.Size = New System.Drawing.Size(232, 200) Me.listBox1.TabIndex = 0 [b]AddHandler Me.listBox1.DrawItem, AddressOf Me.listBox1_DrawItem AddHandler Me.listBox1.MeasureItem, AddressOf Me.listBox1_MeasureItem Me.listBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable[/b] Me.AutoScale = False Me.ClientSize = New System.Drawing.Size(248, 248) Me.Font = New System.Drawing.Font(sansSerifFontFamily, 12) Me.Text = "ListBox" Me.Controls.AddRange(New System.Windows.Forms.Control() {listbox1}) End Sub #End Region [b]Private Sub listBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Dim brush As Brush Dim selected As Boolean Dim displayText As String ' The following method should generally be called before drawing. ' It is actually superfluous here, since the subsequent drawing ' will completely cover the area of interest. e.DrawBackground() 'The system provides the context 'into which the owner custom-draws the required graphics. 'The context into which to draw is e.graphics. 'The index of the item to be painted is e.Index. 'The painting should be done into the area described by e.Bounds. brush = listBoxBrushes(e.Index) e.Graphics.FillRectangle(brush, e.Bounds) e.Graphics.DrawRectangle(SystemPens.WindowText, e.Bounds) If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then selected = True Else selected = False End If displayText = "ITEM #" & e.Index If (selected) Then displayText &= " SELECTED" End If e.Graphics.DrawString(displayText, Me.Font, Brushes.Black, e.Bounds.X, e.Bounds.Y) e.DrawFocusRectangle() End Sub[/b] [b]'Return the height of the item to be drawn Private Sub listBox1_MeasureItem(ByVal sender As Object, ByVal e As MeasureItemEventArgs) Dim displayText As String Dim stringSize As SizeF 'Work out what the text will be displayText = "ITEM #" & e.Index 'Get width & height of string stringSize = e.Graphics.MeasureString(displayText, Me.Font) 'Account for top margin stringSize.Height += 6 If listBoxHeights(e.Index) > stringSize.Height Then 'Now set height to taller of default and text height e.ItemHeight = listBoxHeights(e.Index) Else e.ItemHeight = CInt(stringSize.Height) End If End Sub[/b] ' The main entry point for the application. Public Shared Sub Main() System.Threading.Thread.CurrentThread.ApartmentState = System.Threading.ApartmentState.STA Application.Run(New OwnerDrawListBox()) End Sub End Class End Namespace Edited June 28, 2002 by Derek Stone Quote
*Gurus* Derek Stone Posted June 28, 2002 *Gurus* Posted June 28, 2002 I've placed the parts that you should be concerned with in bold (above). You can ignore all the other "garbage" they've thrown in there. Good Luck -CL Quote Posting Guidelines
NicoVB Posted June 29, 2002 Posted June 29, 2002 Very useful this code!!! I will make a ownerdrawn listbox like an XP menu!! Quote Visit http://www.nico.gotdns.com Now ONLINE!
NicoVB Posted June 29, 2002 Posted June 29, 2002 I'm making a custom listbox control by inheriting and then overriding the onDrawItem method. But how do you also change the properties from an item of the listbox??? Quote Visit http://www.nico.gotdns.com Now ONLINE!
Guest TheIrishCoder Posted June 30, 2002 Posted June 30, 2002 When you overide the onDrawItem you are overiding the listboxes code for drawing an item so your code should draw the item as you want it to look. You are not overiding how the whole control looks just an individual item. Understanding how the whole thing works is important. The first important thing is setting the ListBox's DrawMode. In the code posted here it is set to OwnerDrawVariable which means you will write the code to draw the controls elements and they can vary in size. You can also use OwnerDrawFixed which means you will write the code to draw each element but their size will be the same in all cases. Next up you write code in the onMeasureItem event to decide the size of the element. You can omit code from this event to accept the default size. When overiding this code the main reasons will be to set it's size according to the text you will use for example. It provides a MeasureItemEventArgs object which can be used to get the graphics object, the index of the item being drawn and the item height and width. The code in the example here is stringSize = e.Graphics.MeasureString(displayText, Me.Font) which calculates the size in pixels of the text. The code then sets the itemheight and itemwidth accordingly. You often use this code to set the item size so that an icon/bitmap you intend to draw will fit. The next event is the DrawItem event. The code example here can be confusing as it deals with the 2 important events in the wrong order. In the drawitem event you use the graphics object passed by the DrawItemEventArgs, e.Grpahics (any GDI+ drawing requires a graphics object), and then draw whatever you want within the bounds of the DrawItemEventArgs object - e.bounds. Quote
NicoVB Posted June 30, 2002 Posted June 30, 2002 But I want that each item from the listbox has the property for example 'Icon' so the OnDrawItem Sub can use that property from the item to draw the icon near the Item Quote Visit http://www.nico.gotdns.com Now ONLINE!
Guest TheIrishCoder Posted June 30, 2002 Posted June 30, 2002 If you're inheriting the listbox then add an icon property and overide the Add method to take a seond parameter i.e. an icon. and set the icon property to this. Then when drawing just reference Me.IconProperty to get the icon. Quote
NicoVB Posted June 30, 2002 Posted June 30, 2002 But I mean more icons. So every item can have a different icon. If you have a property icon of the listbox, that's only one icon for whole the listbox!!! Quote Visit http://www.nico.gotdns.com Now ONLINE!
*Gurus* divil Posted June 30, 2002 *Gurus* Posted June 30, 2002 Just think about it. You'll have to have your own collection of ListItems instead of the default and override the Add method just like TheIrishCoder suggested. It's up to you to write the code to support it. Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
NicoVB Posted June 30, 2002 Posted June 30, 2002 yeah, but that's very difficult I think, because you can't inherit from a 'ListItem Class'. Quote Visit http://www.nico.gotdns.com Now ONLINE!
NicoVB Posted June 30, 2002 Posted June 30, 2002 Or maybe I can add an IconList(just like an ImageList). And then draw every icon in the onDrawItem sub. But as which type of property has i to declare that property?? Arraylist, .... or what else?? Quote Visit http://www.nico.gotdns.com Now ONLINE!
*Gurus* divil Posted July 1, 2002 *Gurus* Posted July 1, 2002 Just make your own Add, Remove and whatever else methods, and do it however you like. You could use a Collection, Array, SortedList, it's your listbox so you decide how you want to manage the items. Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
NicoVB Posted July 1, 2002 Posted July 1, 2002 I'm developping my control, but now I have the following problem: I have a few color properties. In the Set statement of the properties i have: Invalidate() to redraw each item. If I change at runtime a color property, the listbox redraws all the items. But not at designtime!!! What now? Quote Visit http://www.nico.gotdns.com Now ONLINE!
*Gurus* divil Posted July 1, 2002 *Gurus* Posted July 1, 2002 http://www.c-sharpcorner.com/Code/2002/May/OwnerDrawListBoxWithIcons.asp Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
Guest Vax Posted July 2, 2002 Posted July 2, 2002 debuggers wanted... if anyone wants to try and figure out what I'm doing wrong on this one, I'd appreciate it. I've built my derived control based out of an online magazine I stumbled onto, tried to make a few changes to streamline it et al, but naturally I screwed it up. I'm pretty sure I messed it up in the actual drawing arguments and function calls, but anyone who is particularly bored is welcome to tear apart what I have and tell me what I need to do to make it work. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.