Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0015: Eine FontListBox mittels einer OwnerDrawn-Listbox realisieren

 von 

Beschreibung

Das Beispiel zeigt, wie einfach sich Erweiterungen der Listbox, wie z.B. eine FontListBox realisieren lassen.

Zu diesem Tipp existieren im Tippupload die folgende(n) Aktualisierung(en):
[VB .NET Tippvorschlag 0030] update zu 0015 - FontListBox

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 1.0, .NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2002, Visual Basic 2003, Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [7,36 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2002/2003
' Option Strict:    An
' Option Explicit:  An
'
' Referenzen: 
'  - System
'  - System.Drawing
'  - System.Windows.Forms
'

' ##############################################################################
' ###################### EnumerationFinishedEventArgs.vb #######################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports System

' <remarks>
'   Stellt Informationen für das Ereignis, das 
'   beim Abschliessen der Enumeration relevant sind,
'   bereit.
' </remarks>
Public Class EnumerationFinishedEventArgs
    Inherits EventArgs

    Private m_blnCancelled As Boolean
    Private m_intValidFontsCount As Integer
    Private m_intInvalidFontsCount As Integer

    ' <summary>
    '   Erstellt eine neue Instanz der Klasse und 
    '   weist ihren Eigenschaften die übergebenen Werte zu.
    ' </summary>
    ' <param name="blnCancelled">Erfolte ein vorzeitiger 
    '   Abbruch des Enumerationsvorgangs?</param>
    ' <param name="intValidFontsCount">Anzahl der erfolgreich 
    '   geladenen Fonts.</param>
    ' <param name="intInvalidFontsCount">Anzahl der nicht 
    '   erfolgreich geladenen Fonts.</param>
    Public Sub New( _
      ByVal blnCancelled As Boolean, _
      ByVal intValidFontsCount As Integer, _
      ByVal intInvalidFontsCount As Integer)
        m_blnCancelled = blnCancelled
        m_intValidFontsCount = intValidFontsCount
        m_intInvalidFontsCount = intInvalidFontsCount
    End Sub

    ' <summary>
    '   Gibt an oder zurück, ob der Enumerationsvorgang 
    '   vorzeitig abgebrochen wurde.
    ' </summary>
    ' <value>Erfolgte ein vorzeitiger Abbruch 
    '   des Enumerationsvorgangs?</value>
    Public Property Cancelled() As Boolean
        Get
            Return m_blnCancelled
        End Get
        Set(ByVal Value As Boolean)
            m_blnCancelled = Value
        End Set
    End Property

    ' <summary>
    '   Gibt an oder gibt zurück, wie viele 
    '   Fonts erfolgreich geladen werden konnten.
    ' </summary>
    ' <value>Anzahl der erfolgreich geladenen Fonts.</value>
    Public Property ValidFontsCount() As Integer
        Get
            Return m_intValidFontsCount
        End Get
        Set(ByVal Value As Integer)
            m_intValidFontsCount = Value
        End Set
    End Property

    ' <summary>
    '   Gibt an oder gibt zurück, wie viele Fonts 
    '   nicht erfolgreich geladen werden konnten.
    ' </summary>
    ' <value>Anzahl der nicht erfolgreich geladenen Fonts.</value>
    Public Property InvalidFontsCount() As Integer
        Get
            Return m_intInvalidFontsCount
        End Get
        Set(ByVal Value As Integer)
            m_intInvalidFontsCount = Value
        End Set
    End Property
End Class
' ##############################################################################
' ############################## FontListBox.vb ################################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports System
Imports System.Drawing
Imports System.Threading
Imports System.Windows.Forms

' <remarks>
'   Erweitert die Standard-ListBox dahingehend, 
'   dass darin alle verfügbaren Schriftarten angezeigt werden.
' </remarks>
Public Class FontListBox
    Inherits ListBox

    ' <summary>
    '   Wird ausgelöst, wenn alle Schriftarten 
    '   in das Steuerelement geladen wurden.
    ' </summary>
    ' <param name="sender">Objekt, das das Ereignis auslöst.</sender>
    ' <param name="e">Mit dem Ereignis verbundene Informationen.</sender>
    Public Event EnumerationFinished( _
      ByVal sender As Object, _
      ByVal e As EnumerationFinishedEventArgs)

    Private m_EnumThread As Thread
    Private m_blnHasFocus As Boolean

    Private m_sngFontSize As Single
    Private m_blnEnumerating As Boolean

    Private m_intValidFontsCount As Integer
    Private m_intInvalidFontsCount As Integer


    Private Sub FontListBox_MeasureItem( _
      ByVal sender As Object, _
      ByVal e As MeasureItemEventArgs) _
      Handles MyBase.MeasureItem

        ' Es gibt eine Auswahl.
        If e.Index >= 0 And e.Index < Me.Items.Count Then
            Dim strItemCaption As String = Me.Items(e.Index).ToString()
            Try

                ' Font setzen und Abmasse ermitteln, 
                ' dann die Grösse des Items bestimmen.
                Dim fntCurrent As Font = _
                  New System.Drawing.Font( _
                    strItemCaption, _
                    m_sngFontSize, _
                    FontStyle.Regular, _
                    GraphicsUnit.Point)
                Dim MySizeF As SizeF = _
                  e.Graphics.MeasureString(strItemCaption, _
                    fntCurrent)

                ' Oben und unten jeweils ein Pixel Abstand.
                e.ItemHeight = CInt(MySizeF.Height) + 2
                e.ItemWidth = CInt(MySizeF.Width)
            Catch

                ' Hier müssen wir nichts machen, da 
                ' implizit die Prozedur verlassen wird.
            End Try
        End If
    End Sub

    Private Sub FontListBox_DrawItem( _
      ByVal sender As Object, _
      ByVal e As DrawItemEventArgs) _
      Handles MyBase.DrawItem

        ' Es gibt eine Auswahl.
        If e.Index >= 0 And e.Index < Me.Items.Count Then
            Dim strItemCaption As String = Me.Items(e.Index).ToString()
            Dim fntCurrent As Font
            Try

                ' Versuchen, den Font zu erstellen.
                fntCurrent = New System.Drawing.Font( _
                  strItemCaption, _
                  Me.FontSize, _
                  FontStyle.Regular, _
                  GraphicsUnit.Point)
            Catch
                Return
            End Try

            ' Das Item ist ausgewählt.
            If (e.State And DrawItemState.Selected) = _
                DrawItemState.Selected Then

                ' Highlight-Rechteck für das Element; dann 
                ' wird ein Fokusrechteck gezeichnet (dies
                ' könnte man so erweitern, dass das Zeichnen 
                ' nur erfolgt, wenn sich Windows im
                ' entsprechenden Modus befindet). Schliesslich 
                ' wird noch der Text gezeichnet.
                e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds)
                If Me.ShowFocusCues And m_blnHasFocus Then
                    ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds)
                End If
                e.Graphics.DrawString(strItemCaption, _
                  fntCurrent, _
                  SystemBrushes.HighlightText, _
                  e.Bounds.Left, _
                  e.Bounds.Top + 1)

            ' Das Item ist nicht ausgewählt.
            Else

                ' Neuzeichnen des Hintergrunds, um alte States 
                ' zu entfernen, anschliessend zeichnen
                ' des Textes im entsprechenden Font.
                e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds)
                e.Graphics.DrawString( _
                  strItemCaption, _
                  fntCurrent, _
                  SystemBrushes.WindowText, _
                  e.Bounds.Left, _
                  e.Bounds.Top + 1)
            End If
        End If
    End Sub

    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
        m_blnHasFocus = False
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
        m_blnHasFocus = True
        Me.Invalidate()
    End Sub

    ' <summary>
    '   Leert die Liste und füllt sie mit den aktuellen Schriften neu.
    ' </summary>
    Public Sub Refill()
        Me.Items.Clear()
        MyBase.OnSelectedIndexChanged(New EventArgs())

        ' Falls gerade enumeriert wird, Enumeration abbrechen.
        If (Not m_EnumThread Is Nothing) AndAlso m_EnumThread.IsAlive Then
            m_EnumThread.Abort()
            m_blnEnumerating = False
        End If

        ' Thread für EnumFonts erstellen und starten.
        m_EnumThread = New Threading.Thread(AddressOf EnumFonts)
        m_EnumThread.Start()
    End Sub

    ' <summary>
    '   Bricht einen laufenden Enumerationsvorgang ab.
    ' </summary>
    Public Sub AbortEnumeration()
        If (Not m_EnumThread Is Nothing) AndAlso m_EnumThread.IsAlive Then
            m_EnumThread.Abort()
            RaiseEvent EnumerationFinished(Me, _
              New EnumerationFinishedEventArgs( _
                True, _
                m_intValidFontsCount, _
                m_intInvalidFontsCount))
            m_blnEnumerating = False
        Else
            Throw New Exception("Es wird nicht enumeriert, " & _
              "daher kann auch nicht abgegrochen werden")
        End If
    End Sub

    ' <summary>
    '   Gibt die Grösse der Schrift an oder gibt diese zurück.
    ' </summary>
    ' <value>Grösse der Schrift, in der die Einträge 
    '   angezeigt werden.</value>
    Public Property FontSize() As Single
        Get
            Return m_sngFontSize
        End Get
        Set(ByVal Value As Single)
            m_sngFontSize = Value
            Refill()
        End Set
    End Property

    ' <summary>
    '   Gibt an, ob gerade eine Enumeration durchgeführt wird.
    ' </summary>
    ' <value>Wird gerade eine Enumeration durchgeführt?</value>
    Public ReadOnly Property Enumerating() As Boolean
        Get
            Return m_blnEnumerating
        End Get
    End Property

    ' <summary>
    '   Enumeriert alle verfügbaren Fonts. Da dies 
    '   etwas mehr Zeit beanspruchen kann, erfolgt die
    '   Ausführung in einem eigenen Thread.
    ' </summary>
    Private Sub EnumFonts()
        m_blnEnumerating = True
        m_intInvalidFontsCount = 0
        m_intValidFontsCount = 0

        ' Alle Fontfamilien durchgehen.
        Dim fntfam As FontFamily
        For Each fntfam In System.Drawing.FontFamily.Families

            ' Font anhand des Namens erstellen.
            Try
                Dim fntCurrent As Font = _
                  New System.Drawing.Font( _
                    fntfam.Name, _
                    m_sngFontSize, _
                    FontStyle.Regular, _
                    GraphicsUnit.Pixel)
                Me.Items.Add(fntfam.Name)
                m_intValidFontsCount += 1
            Catch
                m_intInvalidFontsCount += 1
            End Try
        Next fntfam
        RaiseEvent EnumerationFinished(Me, _
          New EnumerationFinishedEventArgs( _
            False, m_intValidFontsCount, _
            m_intInvalidFontsCount))
        m_blnEnumerating = False
    End Sub
End Class
' ##############################################################################
' ################################ MainForm.vb #################################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports Microsoft.VisualBasic
Imports System.Windows.Forms

' <remarks>
'   Hauptformular der Anwendung.
' </remarks>
Public Class MainForm
    Inherits System.Windows.Forms.Form


    Private Sub btnLoadFonts_Click( _
      ByVal sender As System.Object, _
      ByVal e As System.EventArgs) _
      Handles btnLoadFonts.Click

        ' "Neu Laden".
        If Me.btnLoadFonts.Text = "&Neu laden" Then
            Me.lblStatistics.Text = ""
            Me.btnLoadFonts.Text = "&Stoppen"
            Me.FontListBox1.Refill()

        ' "Stoppen".
        Else
            If Me.FontListBox1.Enumerating Then
                Me.FontListBox1.AbortEnumeration()
            Else
                MessageBox.Show("Die Enumeration läuft nicht " & _
                  "und kann nicht abgebrochen werden!", _
                  Application.ProductName, _
                  MessageBoxButtons.OK, _
                  MessageBoxIcon.Exclamation)
            End If
            Me.btnLoadFonts.Text = "&Neu laden"
        End If
    End Sub

    Private Sub MainForm_Closed( _
      ByVal sender As Object, _
      ByVal e As System.EventArgs) Handles MyBase.Closed

        ' Wenn noch enumeriert wird, dann den
        ' Enumerationsvorgang abbrechen.
        If Me.FontListBox1.Enumerating Then
            Me.FontListBox1.AbortEnumeration()
        End If
    End Sub

    Private Sub txtCurrentFont_TextChanged( _
      ByVal sender As System.Object, _
      ByVal e As System.EventArgs) _
      Handles txtCurrentFont.TextChanged
        Me.FontListBox1.SelectedIndex = _
          Me.FontListBox1.FindString(Me.txtCurrentFont.Text)
    End Sub

    Private Sub FontListBox1_SelectedIndexChanged( _
      ByVal sender As System.Object, _
      ByVal e As System.EventArgs) _
      Handles FontListBox1.SelectedIndexChanged
        If Me.FontListBox1.SelectedItem Is Nothing Then
            Me.lblSelectedFontName.Text = "(keine Auswahl)"
        Else
            Me.lblSelectedFontName.Text = _
              Me.FontListBox1.SelectedItem.ToString()
        End If
    End Sub

    Private Sub FontListBox1_EnumerationFinished( _
      ByVal sender As Object, _
      ByVal e As FontList.EnumerationFinishedEventArgs) _
      Handles FontListBox1.EnumerationFinished
        Me.lblStatistics.Text = _
            "Gültig: " & e.ValidFontsCount.ToString() & _
            ControlChars.NewLine & _
            "Ungültig: " & e.InvalidFontsCount.ToString() & _
            ControlChars.NewLine & _
            "Abgebrochen: " & e.Cancelled.ToString()
        Me.btnLoadFonts.Text = "&Neu laden"
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 2 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von roland_k am 01.02.2007 um 09:32

guten tag , ich wollte das beispiel ausführen dann kommt aber der debugger:

Me.lblStatistics.Text = _
"Gültig: " & e.ValidFontsCount.ToString() & _
ControlChars.NewLine & _
"Ungültig: " & e.InvalidFontsCount.ToString() & _
ControlChars.NewLine & _
"Abgebrochen: " & e.Cancelled.ToString()


und diese fehlermeldung:
Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement lblStatistics erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

wenn ich aber die ...exe im Bin verzeichniss starte funktionierts

ich habe vb2005 express

wie kommts ?? lauft dies nur bei mir nicht ?

danke
roland_k

Kommentar von am 13.03.2005 um 07:06

'UPGRADE_WARNING: Form event MainForm.Unload has a new behavior. Click for more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup2065"'
Private Sub MainForm_Closed(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Closed
If MsgBox("Are you sure you want to close this program and exit?", MsgBoxStyle.OKCancel, "Exit program ?") = MsgBoxResult.OK Then
rsProduct.Close()
rsConnectionDetail.Close()
'UPGRADE_ISSUE: Event parameter Cancel was not upgraded. Click for more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1057"'
Cancel = 0
End
Else
'UPGRADE_ISSUE: Event parameter Cancel was not upgraded. Click for more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1057"'
Cancel = 1
End If

End Sub