首页 > 解决方案 > 如何获取 PictureBox 中图像资源的名称?

问题描述

我正在开发一款游戏,它有一个放置系统,它几乎完成了,我正在尝试使用 My.Settings 制作一个保存系统,这是我到目前为止的代码

Private Sub Menu_Save_Click(sender As Object, e As EventArgs) Handles Menu_Save.Click
    Dg_1 = MessageBox.Show("Are you sure you want to save? This will overwrite your previous save.", "Warning!", MessageBoxButtons.YesNo)
    If (Dg_1) = DialogResult.Yes Then
        If (Generated = 0) Then
            Tb_Chat.Text += Environment.NewLine
            Tb_Chat.Text += "Cannot save a blank world"
        ElseIf Generated = 1 Then
            My.Settings.savslot1_isused = True
            My.Settings.savslot1_hearts = Hp
            My.Settings.savslot1_hunger = Hunger
            My.Settings.stg_slot01 = Pb_BlockSpace001.Image
            My.Settings.stg_slot02 = Pb_BlockSpace002.Image
            My.Settings.stg_slot03 = Pb_BlockSpace003.Image
            My.Settings.stg_slot04 = Pb_BlockSpace004.Image
            My.Settings.stg_slot05 = Pb_BlockSpace005.Image
            Tb_Chat.Text += Environment.NewLine
            Tb_Chat.Text += "World Saved. " + TimeOfDay + "."
        Else
            Exit Sub
        End If
    End If
End Sub

(我只保存了 5 个块来测试它)

那么它会出现一个错误说:

“图像”类型的值无法转换为“字符串”

我怎样才能使它获得资源的名称而不是尝试将图像转换为字符串???

标签: vb.netvisual-studiowinforms

解决方案


由于位图图像位于 My.Resources 中,请考虑以下内容。

首先如上所述,您可以在 PictureBox 的 Tag 属性中设置图像名称并在需要时检索它,或者使用PictureBox带有属性的自定义(如果需要,更改名称)ResourceName 将存储资源名称。

Public Class ImageBox
    Inherits PictureBox
    ''' <summary>
    ''' Name of resource in projects Resources
    ''' </summary>
    ''' <returns></returns>
    Public Property ResourceName() As String
    
End Class

创建ImageResourceHelper.vb并添加以下内容

Namespace My
    <ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)>
    Partial Friend Class _MyImages

        Private ReadOnly MyProperties As Reflection.PropertyInfo()
        Private ReadOnly MyBitmapNames As List(Of String)
        Public BitMapImages As new Dictionary(Of String, Bitmap)

        Public ReadOnly Property HasImages() As Boolean
        get
            Return BitMapImages.Count >0
        End Get
        End Property

        Private Sub GetBitMapImages()

            'BitMapImages = New Dictionary(Of String, Bitmap)

            Dim propertyInfo As Reflection.PropertyInfo() =
                GetType(Resources.Resources).GetProperties(Reflection.BindingFlags.NonPublic Or
                                                              Reflection.BindingFlags.Instance Or
                                                              Reflection.BindingFlags.Static)

            Dim BitMaps = (From T In propertyInfo Where T.PropertyType Is GetType(Bitmap)).ToList

            If BitMaps.Count > 0 Then
                For Each pInfo As Reflection.PropertyInfo In BitMaps

                    BitMapImages.Add(
                        pInfo.Name.Replace("_", " "),
                        CType(Resources.ResourceManager.GetObject(pInfo.Name), Bitmap)
                    )

                Next
            End If

        End Sub
        Public Function BitmapFromResource(sender As String) As Bitmap

            Dim Item = (
                    From propertyInfo In MyProperties
                    Where propertyInfo.PropertyType Is GetType(Bitmap) AndAlso propertyInfo.Name = sender
                    ).FirstOrDefault

            If Item IsNot Nothing Then
                Return CType(Resources.ResourceManager.GetObject(Item.Name), Bitmap)
            Else
                Dim bm As New Bitmap(256, 256)
                Dim gr As Graphics = Graphics.FromImage(bm)
                gr.Clear(Color.Transparent)

                Return bm

            End If

        End Function
        Public ReadOnly Property BitmapNames As List(Of String)
            Get
                Return MyBitmapNames
            End Get
        End Property
        Public Sub New()

            MyProperties = GetType(Resources.Resources).
                GetProperties(
                    Reflection.BindingFlags.NonPublic Or
                    Reflection.BindingFlags.Instance Or
                    Reflection.BindingFlags.Static)

            MyBitmapNames = (
                From propertyInfo In MyProperties
                Where propertyInfo.PropertyType Is GetType(Bitmap)
                Select propertyInfo.Name
                ).ToList

            GetBitMapImages()

        End Sub
    End Class
    <HideModuleName()>
    Friend Module Resource_Images
        Private ReadOnly instance As New ThreadSafeObjectProvider(Of _MyImages)
        ReadOnly Property Images() As _MyImages
            Get
                Return instance.GetInstance()
            End Get
        End Property
    End Module
End Namespace

表单设计器

  • 添加一个按钮来设置图像(也可以在 ListBox 的选择更改或 BindingSource 的位置更改事件时完成。
  • 添加另一个按钮以获取当前资源名称。
  • 添加列表框
  • 添加自定义图片框

我的设置

添加一个名为SelectedImageNameString 的新设置。

表格代码

以下代码使用资源名称加载 ListBox,确定是否SelectedImageName设置,如果设置为 PictureBox 图像资源名称,如果未设置,则从资源中选择第一张图像。

On Form Closing 事件 如果通过检查 PictureBox ResourceName 属性设置图像,则设置SelectedImageName将在 Form Shown 事件中拾取的资源是否仍然存在。

Imports System.ComponentModel

Public Class Form1

    Private ReadOnly ImageBindingSource As New BindingSource

    Private Sub SetImageButton_Click(sender As Object, e As EventArgs) Handles SetImageButton.Click

        If ListBox1.SelectedItem Is Nothing Then
            Exit Sub
        End If

        Dim current = CType(ListBox1.SelectedItem, KeyValuePair(Of String, Bitmap))

        PictureBox1.Image = current.Value
        PictureBox1.ResourceName = current.Key

    End Sub
    Private Sub GetImageNameButton_Click(sender As Object, e As EventArgs) Handles GetImageNameButton.Click
        If Not String.IsNullOrWhiteSpace(PictureBox1.ResourceName) Then
            MessageBox.Show(PictureBox1.ResourceName)
        Else
            MessageBox.Show("Set an image and try again")
        End If
    End Sub
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown

        ImageBindingSource.DataSource = My.Images.BitMapImages

        ListBox1.DataSource = ImageBindingSource
        ListBox1.DisplayMember = "Key"
        ListBox1.ValueMember = "Value"

        If My.Images.HasImages Then
            If Not String.IsNullOrWhiteSpace(My.Settings.SelectedImageName) Then
                If My.Images.BitMapImages.ContainsKey(My.Settings.SelectedImageName) Then
                    PictureBox1.Image = My.Images.BitMapImages(My.Settings.SelectedImageName)
                    PictureBox1.ResourceName = My.Settings.SelectedImageName
                    ListBox1.SelectedIndex = ListBox1.FindString(My.Settings.SelectedImageName)
                Else
                    PictureBox1.Image = My.Images.BitMapImages.First().Value
                    PictureBox1.ResourceName = My.Images.BitMapImages.First().Key
                End If
            End If
        End If

    End Sub

    Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        If Not String.IsNullOrWhiteSpace(PictureBox1.ResourceName) Then
            My.Settings.SelectedImageName = CType(ListBox1.SelectedItem, KeyValuePair(Of String, Bitmap)).Key
        End If
    End Sub
End Class

当然这是针对一个 PictureBox,对每个 PictureBox 重复。此外,如果一个或多个资源是图标,则需要相应地调整检索图像的代码。BitmapFromResource 方法也可用于按名称从资源中获取图像,如果未找到则返回空图像。


推荐阅读