"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
Go Back  Xtreme Visual Basic Talk > > > "Portrait Chooser" Using Resource File


Reply
 
Thread Tools Display Modes
  #1  
Old 01-04-2011, 08:04 PM
Varwulf Varwulf is offline
Newcomer
 
Join Date: Jan 2011
Posts: 5
Default "Portrait Chooser" Using Resource File


Forgive my rather neanderthal description and title, but to summarize, this is what I have going on.

I'm building a basic text based adventure game (main purpose is to just keep me fresh between programming classes during break, since I have my final VB course next semester and am trying to explore some different concepts and ideas for coding in VB) in Visual Studio 2008. During the character creation process, the user is allowed to choose a portrait to represent their character in game. I've loaded up my resource file with the portraits in question, but there is one thing I'm having some trouble with when it comes to selecting the portraits from that file. Keep in mind, I know how to do this exact thing by loading the pictures up into their own asset folder and grabbing them from there to display on the form. The resource file seems like a more intelligent way of doing it, but I've not used it much in past applications.

So, when the user clicks on the "next" arrow to cycle through the possible portrait choices, I want to change the current image in the picture box from, let's say, image1, to image2. Straight forward and all.

I could load all of these images up into an image list, but again, this is all for exploratory purposes, so the following if statement is being used for that purpose only. I plan to code a more effective way of cycling through the images at a later date.

If picCharPort.Image = My.Resources.Image1 Then
picCharPort.Image = My.Resources.Image2
End If

For some reason, I am fully capable of assigning My.Resources.Image1 to picCharPort.Image normally, but when I attempt to switch the image to another image like in this if statement, it creates and error.

It essentially does not like the "=" operator being used, so I switched it to Is, and it still doesn't work (however, without displaying an error). It's a bit challenging to diagnose without an error message, so I guess I'm just asking if anyone knows a better idea on how to go about getting this to work? Is the resource file really a good idea in this case (considering, the portrait options change depending on character class/gender, etc)?

Again, I apologize for the lack of proper terminology, I'm not much for it, I prefer to learn and practice the actual logic behind it all instead.

Thanks in advance for any input anyone can provide.
Reply With Quote
  #2  
Old 01-04-2011, 10:24 PM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

providing your images are named image1 and image2
If PictureBox1.Image.ToString Is My.Resources.Image1.ToString Then
PictureBox1.Image = My.Resources.Image2
End If
Reply With Quote
  #3  
Old 01-04-2011, 11:16 PM
Varwulf Varwulf is offline
Newcomer
 
Join Date: Jan 2011
Posts: 5
Default

Haha, you know, I can't believe I didn't think of that. I'll give it a try now, though I am sure it'll work.

Edit:

The only problem I am seeing is when I get to image 3 (checking if image 2, switching to image 3), it still cycles through the if statement as if it were image 1 and changes to image 2.

Strangeness. Even refreshing the picturebox after changing the image doesn't make a difference.

Last edited by Varwulf; 01-04-2011 at 11:27 PM.
Reply With Quote
  #4  
Old 01-05-2011, 08:25 AM
AtmaWeapon's Avatar
AtmaWeapon"Portrait Chooser" Using Resource File AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

There's a way to solve both problems at once.

The first problem is related to how images work. "Is" performs what's known as a reference comparison. This means it checks if its operands are exactly the same object. I'll discuss why this doesn't work later. If "=" is overloaded by an object, it is supposed to perform a value comparison. This means it compares some or all of the properties of each object to determine if they are equal if they don't refer to the same object. For Images, this would be quite slow as the only sane thing to do would be to compare size, pixel format, and the color value of each pixel. Depending on the pixel format, this could be very complicated or unreliable. Depending on the size, this could be very slow. So the "=" operator is not overloaded; if you desire a value comparison it's taken as a warning that you have to write it yourself.

Frog's code doesn't work because it makes the silly assumption that ToString() is unique for two instances of an image. ToString() is supposed to provide a string representation of an object. Ask yourself, "For an arbitrary image, what would be a valid string representation?" This is actually a difficult question. You can't use a hexadecimal string of the bytes because images can be hundreds of megabytes. You could include the size, but having two 200x200 images doesn't tell you which is which. You can't do an analysis of what the image looks like because it would require algorithms that don't exist. You can't check the file path because 1) there's no property of Image that indicates a file path and 2) you can create images in memory with no backing file. Since there's not really a sane way to create a unique string, MS stuck with the only thing left: the class name. A quick trip to the debugger should reveal that for every Image object, the value of ToString() is its type name; for resources it's almost always System.Drawing.Bitmap but there may be scenarios in which you get some other type. Since every image has the same string representation, using ToString() for value comparison is silly: all images will be considered equal.

So what do you do? Use reference comparison. But you tried that and it didn't work, why? Remember that reference comparison is only true if the two variables refer to the same object:
Code:
Dim image1 = My.Resources.Image1
Dim image1Alias = image1

If image1 Is image1Alias Then
    MessageBox.Show("The same!")
End If
The above code would show its message box, because when image1 is assigned to image1Alias only the reference is copied. There's one copy of the image in memory and two variables that reference it. So why doesn't the next one show its message?
Code:
Dim image1 = My.Resources.Image1
Dim image1Copy = My.Resources.Image1

If image1 Is image1Copy Then
    MessageBox.Show("The same!")
End If
I left a hint in the variable names. My.Resources.Image1 always loads the Image object from the application's resources; while it returns an image with exactly the same properties every time what it returns is not the same object. In this case, there are two identical copies of Image1 in memory and one variable for each copy. The Is operator sees that its operands are not the same object and returns false.

Since My.Resources returns a different object each time and value comparisons of images are difficult and expensive, it's best to pre-load a collection of the images you want to use. Then, you never use My.Resources to get an image again; if you need an image fetch it from that list. As long as you stick to that principle, you'll only have one copy of each image in memory and performing reference comparisons will be easy.

Here's an example that does sort of what you're asking:
Code:
Public Class Form1

    Private _portraits As List(Of Image)
    Private _portraitIndex As Integer
    Private _selectedPortrait As Image

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)

        _portraits = New List(Of Image)()
        _portraits.Add(My.Resources.Chrysanthemum)
        _portraits.Add(My.Resources.Hydrangeas)
        _portraitIndex = 0
        pbPortrait.Image = _portraits(_portraitIndex)
    End Sub

    Private Sub btnNextPortrait_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNextPortrait.Click
        _portraitIndex += 1
        If _portraitIndex = _portraits.Count Then
            _portraitIndex = 0
        End If

        pbPortrait.Image = _portraits(_portraitIndex)
    End Sub
End Class
When the form loads, OnLoad() is called (this is part of the process of raising the Load event.) The code creates the list of images from the resources*, initializes an index into those portraits, and puts the first image in the portrait picture box. Now the form is displaying portrait 0. When the user clicks the "next" button, the portrait index is incremented and the next image is displayed in the picture box (if the index is larger than allowed by the list, it wraps around to 0.) This... actually eliminates the need for the comparison at all and I feel dumb for wasting so much time on the explanation. Let's add a feature so I haven't wasted my effort.

There's surely some "I'm done" button that locks in the portrait selection. When this happens, you need to remember which portrait was selected. It would also be nice if you told Windows it could free the memory for the portraits that you aren't going to use. The easiest way to do this would be to call Dispose() on each image in the portrait list, but you don't want to dispose of the selected image (this would free its memory and crash your program when you try to use it.) So you can loop over each portrait and delete it if it's not the selected one (this is the purpose of the unused _selectedPortrait variable in the last example, you can just paste this in after adding the right control
Code:
Private Sub btnSelectPortrait_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelectPortrait.Click
    _selectedPortrait = _portraits(_portraitIndex)
    For Each unselectedImage As Image In _portraits
        If unselectedImage IsNot _selectedPortrait Then
            _portraits.Remove(unselectedImage)
            unselectedImage.Dispose()
        End If
    Next
End Sub
So there you have it.

* If you have many images in your resources, there's a way to initialize the list in a loop to save some typing. I omitted this for simplicity.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #5  
Old 01-05-2011, 10:51 AM
Varwulf Varwulf is offline
Newcomer
 
Join Date: Jan 2011
Posts: 5
Default

A very comprehensive and detailed explanation, Atma, I am extremely thankful for such a thought out reply. I will certainly go over it again before utilizing it, but what you say makes a lot of sense and certainly fleshes out what I am trying to do in a way I haven't ever done before. The primary reason for my wanting to use the resource.resx file to store the images is because I don't want the user deleting or renaming images in the assets folder, causing all kinds of havoc on the game. I am certain you can understand the reasons for that :P

In any case, I will give this a shot when I have a moment, it looks more than solid to me, so thank you again for your detailed reply!
Reply With Quote
  #6  
Old 01-05-2011, 01:23 PM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

Have to admit I made a boo boo - sorry
Reply With Quote
  #7  
Old 01-05-2011, 01:52 PM
AtmaWeapon's Avatar
AtmaWeapon"Portrait Chooser" Using Resource File AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

No apologies needed; ToString() is unique for some classes and not for others; the only reason I knew why your code wouldn't work was I had to learn that lesson the hard way several years ago
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #8  
Old 01-05-2011, 03:48 PM
Varwulf Varwulf is offline
Newcomer
 
Join Date: Jan 2011
Posts: 5
Default

Learning the hard way is the best way to remember, and not make the mistake again

Also, I designed a pretty solid class with the help you gave me and it works flawlessly. I am very appreciative
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File "Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
 
"Portrait Chooser" Using Resource File
"Portrait Chooser" Using Resource File
 
-->