在Combobox中显示True Type字体图像而不是名称

时间:2016-12-31 12:08:15

标签: vb.net

此链接上@Plutonix的参考答案 3D array loop and get the first dimension value

我正在修改的课程在组合框上显示TTF图像

Public Class FontItem
    Public Property TTImageFile As Image
    Public Property TTFile As String
    Public Property TTBoldFile As String
    Public Property Name As String
    Public Sub New(i as Image, f As String, b As String, n As String)
        TTImageFile = i
        TTFile = f
        TTBoldFile = b
        Name = n
    End Sub

    Public Overrides Function ToString() As String
        Return Name
    End Function
End Class

以这种方式使用此代码

    Dim myFonts As New List(Of FontItem)

    Dim data = {{My.Resources.arial, "Arial", "arial.ttf", "arialbd.ttf"},
        {My.Resources.courier, "Courier New", "cour.ttf", "courbd.ttf"},
        {My.Resources.verdana, "Verdana", "verdana.ttf", "verdanab.ttf"}}

    For n As Int32 = 0 To data.GetUpperBound(0)
        myFonts.Add(New FontItem(data(n, 0), data(n, 1), data(n, 2), data(n, 3)))
    Next

    AvialableFontsCombobox.DataSource = myFonts.ToArray()

其中“My.Resources.arial”和其他人是字体预览的png文件

代码工作正常但我的AvialableFontsCombobox只显示“arial.png”,“courier.png”...作为字符串而不是图形文件。

并添加

    With AvialableFontsCombobox 
        .DrawMode = DrawMode.OwnerDrawVariable
    End With

我只得到空格。

我缺少什么?我是否需要做更多的事情?

Private Sub AvialableFontsCombobox _DrawItem(sender As Object, e As DrawItemEventArgs) Handles AvialableFontsCombobox .DrawItem

1 个答案:

答案 0 :(得分:1)

当您将Combo-ListBox设置为OwnerDraw时,您说您将处理项目的绘制 - 这意味着将代码添加到DrawItem事件中。在这种情况下,您似乎想要为每个绘制一些PNG图像。另一种方法是在该Font中绘制每种字体(或示例文本)的名称。图像方法可能更容易,因为您可以确定每个图像的大小完全相同,即使这意味着在某些图像上有更多的空白区域。

首先是一些设置事项:

转动Option Strict On 。您正在存储来自资源的图像以及一个数组中的一些字符串,这意味着该数组为Object。我喜欢将所有小块存放在一起的想法,但还有另一个问题......

您希望确保对My.Resources.fontname的引用仅运行一次。每次运行代码时,都会创建一个新图像对象。如果你没有检查和处理旧的应用程序,你的应用程序将泄漏(上一个问题的列表更长)。

' form/class level declaration
Private FontImgs As Image()

在其他地方进行初始化:

' build it only once
If FontImgs Is Nothing Then
    FontImgs = New Image() {My.Resources.Arial, My.Resources.Calibri,
                            My.Resources.Segoe, My.Resources.Verdana}
End If

Dim myFonts As New List(Of FontItem)

Dim data = {{"Arial", "arial.ttf", "arialbd.ttf"},
           {"Calibri", "Calibri.ttf", "Calibri.ttf"},
           {"Segoe", "Segoe.ttf", "Segoe.ttf"},
           {"Verdana", "verdana.ttf", "verdanab.ttf"}
           }

For n As Int32 = 0 To FontImgs.Length - 1
    myFonts.Add(New FontItem(FontImgs(n), data(n, 1), data(n, 2), data(n, 0)))
Next

cboFonts.DataSource = myFonts
cboFonts.DisplayMember = "Name"

如果将列表初始化为彼此接近的列表,则可以很容易地确保图像引用的顺序与其余字体数据的顺序相同。顺便说一下,你的代码将Name作为FontFile传递 - 构造函数的顺序似乎不正确。

  • 使用透明BG
  • 创建图像
  • 使它们大小相同但只有最长的那么大(最小化空白区域)
  • 无需向控件添加项目,只需将您的列表用作DataSource
  • 即可

如果这是在重新访问的Dialog表单上,请确保处理该数组中的图像,或者将其作为传递给表单的应用程序级别对象。

对于CBO:

  • OwnerDraw =已修复
  • ItemHeight =图像的高度。我的全都是179w x 28h,所以我使用了28
  • DropDownHeight到图像高度的多个加上边距。示例:95允许在滚动条出现之前显示3个图像。
  • DropDownWidth以容纳图像宽度加一点;我用了190
  • 控件的文本部分将遵循项目大小,以允许您在那里绘制所选项目。我让它打印“名称”(`DisplayMember'),但我将字体大小设置为14,利用空间

设置完成后,在DrawItem事件中添加一些代码:

Private Sub cboFonts_DrawItem(sender As Object, 
            e As DrawItemEventArgs) Handles cboFonts.DrawItem

    ' no item, early exit
    If e.Index < 0 Then Return

    e.DrawBackground()
    ' get the image from the cbo.fiontitem.imageprop
    Dim img = DirectCast(cboFonts.Items(e.Index), FontItem).TTImageFile

    ' size of the image
    Dim rect = New Rectangle(e.Bounds.X, e.Bounds.Y,
                                img.Width, img.Height)
    ' draw it
    e.Graphics.DrawImage(img, rect)

    e.DrawFocusRectangle()

End Sub

enter image description here

我认为我为图像使用了太大的字体,但你明白了。使用小于实际大小的rect(缩略图)可以缩小图像,但实际上使用较小的字体/图像可能无法缩放。