Úvod
ListBox je veľmi často používaný kontrol vo všetkých aplikáciách. Používa sa hlavne na výber konkrétnej položky zo sady položiek. V štandardnom ListBoxe mi chýbala možnosť zmeniť si farbu označenej položky, jej font a farbu rámiku ktorý ju obteká. Tento artikel ukazuje ako vytvoriť vlastný user kontrol, ktorý nám hore uvedené vlastnosti bude ponúkať.
Background
Náš novy usercontrol bude založený na triede štandardného listboxu.
Triedu ktorá dedí jeho vlastnosti som nazval ColorListBoxEx.
Public Class ColorListBoxEx : Inherits System.Windows.Forms.ListBox
Naša nová trieda obsahuje všetky vlastnosti štandardného listboxu plus nove vlastnosti ktoré som pridal.
· Farba rámiku označenej položky
Public Property ColorBorder() As Color
· Farba textu označenej položky
Public Property FontColor() As Color
· Index stĺpčeka v ktorom je uložený text na zobrazenie
Public Property TextCol() As Byte
· Font označenej položky
Public Property FontText() As Font
· Dĺžka farebnej zmeny rámiku označenej položky na osi x
Public Property SmoothWidth() As Single
Každý public properties je vnútri triedy zastúpený lokálnou premennou, ktorá nadobúda jeho stav.
Private myColor As Color 'Color of select border
Private myFont As Font = New Font("Arial", 8, FontStyle.Bold) 'Font of text in select border
Private myFontBrushColor As Drawing.Brush = System.Drawing.Brushes.White 'Color of text in select border
Private myFontColor As Color = Color.White 'Color of text in select border
Private myTextCol As Byte = 0 'When you have more columns -> this column is source for text
Private mySmoothWidth As Single = 0 'Smooth width
Náš novy listbox zachytáva príznak na prekreslenie dvomi spôsobmi :
Čaka na vyvolanie eventu SelectedIndexChanged z materskej triedy.
Protected Sub ColorListBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.SelectedIndexChanged
NewDraw()
End Sub
Prekrýva funkciu WndProc a zachytáva správy ktoré Windows posiela nášmu kontrolu.
Protected Overrides Sub WndProc(ByRef msg As System.Windows.Forms.Message)
MyBase.WndProc(msg)
Select Case msg.Msg
'&H115 - WM_VSCROLL
'&HF - WM_PAINT
'&H360 - WM_AFXFIRST
'&H203 - WM_LBUTTONDBLCLK
'&H20A - WM_MOUSEWHEEL
Case &H115, &HF, &H360, &H203, &H20A
NewDraw()
End Select
End Sub
&H115, &HF, &H360, &H203, &H20A – sú čísla sprav.
Cely zoznam môžete nájsť napr. Internetovej adrese : klik
Kresliť si budem sám
Aby sme mohli niečo do ListBoxu rozumne kresliť, musíme mu nejako povedať, že chceme aby sa prestal automaticky prekresľovať. Na to nám výborné poslúži jeho vlastnosť DrawMode, ktorú v metóde InitializeComponent nastavíme nasledujúcim riadkom
Me.DrawMode = DrawMode.OwnerDrawVariable
A ide sa kresliť
Keď zachytíme event alebo správu, že je potrebne ListBox prekresliť zavolá sa srdce nášho nového kontrolu metóda NewDraw. Ako to funguje?
Prekresľovanie kontrolu si rozdelíme na dve časti. Najprv sa vykreslia riadky, ktoré nie sú označené a v druhej časti vykreslime označené riadky a to s pekným dúhovaným rámikom. Na začiatok si teda vytvoríme v pamäti duhovaný rámik. V premennej p2 si uchováme okrajové súradnice výfarbeného obdĺžnika, ktorý bude obtekať okraj vyznačenej položky a nasledujúcim riadkom už vytvoríme nový štetec.
Dim p1, p2 As System.Drawing.PointF
p1.X = 0 : p1.Y = 0 'Starting points of rectangle
p2.X = mySmoothWidth : p2.Y = MyClass.ItemHeight 'Finish points of rectangle
brushStandard = New System.Drawing.Drawing2D.LinearGradientBrush(p1, p2, myColor, MyClass.BackColor)
Nasleduje cyklus ktorý prebehne všetky položky kontrolu od začiatku po koniec
For i As Integer = 0 To MyBase.Items.Count - 1
Tento blok kódu nerobí nič iné len skontroluje či sa jedna v danom kroku cyklu o selectovanú položku alebo nie. Podľa toho potom nastaví premennú isSelectedItem
For j As Integer = 0 To MyBase.SelectedIndices.Count - 1
If TypeOf (MyClass.Items.Item(0)) Is String Then
If MyBase.Items(i) = MyBase.Items(MyBase.SelectedIndices(j)) Then isSelectedItem = True
Else
If TypeOf (MyClass.Items.Item(0).item(myTextCol)) Is String Then
If MyBase.Items.Item(i).item(myTextCol) = MyBase.Items.Item(MyBase.SelectedIndices(j)).item(myTextCol) Then isSelectedItem = True
End If
End If
Next
A konečne vykreslenie pozadia itemov a napísanie textu
If Not isSelectedItem Then
MyClass.CreateGraphics.FillRectangle(brushBackground, GetItemRectangle(i))
If TypeOf (MyClass.Items.Item(0)) Is String Then
drawText = MyClass.Items.Item(i)
Else
If TypeOf (MyClass.Items.Item(0).item(myTextCol)) Is String Then
drawText = MyClass.Items.Item(i).item(myTextCol)
Else
drawText = String.Empty
End If
End If
MyClass.CreateGraphics.DrawString(drawText, baseFont, baseFontBrushColor, 0, MyBase.GetItemRectangle(i).Y)
End If
Vykreslenie farebného rámiku
'NewPaint(this draw selected item)
'1. I get positions of selected items to str(i).mySelect and I get indexs selected items to str(i).myIndex
For i As Integer = 0 To MyClass.SelectedIndices.Count - 1
ReDim Preserve str(i)
str(i).mySelect = MyClass.GetItemRectangle(MyClass.SelectedIndices.Item(i))
str(i).myIndex = MyClass.SelectedIndices.Item(i)
Next
If Not IsNothing(str) Then
For i As Integer = 0 To UBound(str)
'2. I draw rectangle to selected items positions
MyClass.CreateGraphics.FillRectangle(brushStandard, 0, str(i).mySelect.Y, MyClass.Width, MyClass.ItemHeight)
'3. I draw text to new rectangles
If TypeOf (MyClass.Items.Item(0)) Is String Then
drawText = MyClass.Items.Item(str(i).myIndex)
Else
If TypeOf (MyClass.Items.Item(0).item(myTextCol)) Is String Then
drawText = MyClass.Items.Item(str(i).myIndex).item(myTextCol)
Else
drawText = String.Empty
End If
End If
MyClass.CreateGraphics.DrawString(drawText, myFont, myFontBrushColor, 0, str(i).mySelect.Y)
Next
End If
V prvom bode si uložíme pozíciu štvorčeka označenej položky do premennej mySelect štruktúry str a pridáme si tam rovno aj index tejto položky do premennej myIndex. V druhom bode vykreslíme obdĺžnik na miesto selectovanej položky a v tretom na toto miesto vypíšeme text.
Nakoniec ešte uvoľníme alokovanú pamäť a nový kontrol je na svete.
brushStandard.Dispose()
Záver
Dúfam, že tento príklad pomohol sa zorientovať začínajúcim programátorom a naznačil cestu ako vytvárať vlastné usercontroly. Všetky konštruktívne opravy, postrehy, návrhy a otázky sú vítané.
Celý zdrojový súbor si môžete stiahnuť tu :