If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register or Login
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

[RESOLVED] [VB6]About properties...

First of all, I'd like to know how you would do to pass a param of a property of one class to another class. I'll explain better:

I've two class modules (clsGame and clsSound). In clsGame I have this code:

Code:

Dim m_Sound As New clsSound
Public Property Get Sounds(ByVal Item As String) As clsSound
Set Sounds = m_Sound
End Property

while in clsSound

Code:

Public Sub Play()
'Play a sound here
End Sub

This code should play the sound which name is passed as param in Sounds property from clsGame... obviously it doesn't work because I cannot pass 'Item' from Sound property to 'Play' method, unless I've to move the param from the property into the sub, or keep 'Item' as public var somewhere else or save it into registry and delete it when it isn't more in use.

There's a work-around to use a param of a property of a class into another class without creating public vars or other?

Then, I'd to know how to create default properties (such as the Text property for Textboxes or Caption for Labels, etc...). Most programmers said me it's not possible, but I don't believe that. In fact, reading from MSDN I discovered that it would be possible (even if there isn't how to do it)... So I hope you know how.

Re: [VB6]About properties...

Wait... hold on a sec... first you wouldn't pass the parm of a property to something else... you should be using the property... but then looking at your code... what's Item? You're passing it to the property, but then totally discard it...so what's the Point? Besides it's the Get method of the property, so you shouldn't be passing into it... unless the property is an array or part of a dictionary... but then you're not using it anyways, so it doesn't matter if you're passing in something or not...

If clsSound has a Play method, then that's what you should be calling... the Play method of the instance of the class... in this case m_Sound.Play ... since m_Sound is private inside of clsGame, you might need a method in clsGame that invokes the Play method of m_Sound... but it depends on where and how you do want to invoke it.

Lastly... it IS possible to create default properties in VB6 ... but it's not intuitive... I forget exactly how (it's been a while since I've needed to do this and I no longer have VB6 installed) ... but you use the Class Editor tool and set the Property Index to 0 on the property you want as the default... it's not something that can be done from the normal code editor...

Re: [VB6]About properties...

You're right: I was just a bit confused with my explaination. I'll try to be cleaner, even though I don't know how to explain...

I wish that, when I call the Play method in this way,

Code:

Game.Sounds("C:\WINDOWS\Chimes.WAV").Play

the method read the param Item of Sounds property and sounds it.

But as well as it isn't possible, I have to keep Item into an upper level (e.g. into a bas module) so that clsSound can read it. This solution forces me to have a module only for this variable, and I don't like.

I thought to save Item into registry and read from it when I had to play it, but also this solution doesn't satisfy me.

However now I've found a middle way, that's something like this (I'm not sure I'm writing right 'cause at the moment I don't have my project):

Code:

'clsGame
Dim m_Sounds As New clsSound
Public Property Get Sounds(ByVal Item As String) As clsSound
Dim tmp As String: tmp = m_Sounds.Sound(Item)
Set Sounds = m_Sounds
End Property
'clsSound
Dim OK As Boolean
Public Property Get Sound(Optional ByVal Item As Variant) As String
Static m_Item As String
If Not IsMissing(Item) Then
m_Item = Item
OK = True
Else
Sound = m_Item
End If
End Property
Public Sub Play()
If OK Then
Debug.Print Me.Sound
OK = False
End If
End Sub
'Somewhere else in your code
Dim Game As New clsGame
Call Game.Sounds("C:\WINDOWS\CHIMES.WAV").Play

It should work... In the morning I'll look my project and I'll correct the post if it is not correct...

Anyway, I'd be glad if you could be more accurate into describing me the process about how to create default properties.

Re: [VB6]About properties...

Originally Posted by WizBang

I think you'd do better to create a Public Sub or Function within the class module.

Oh, I know this is the easier way to do what I want, but I discarded this possibility because it won't reproduce the scheme I have in my mind. I wish to build up something like the property Drives of the FSO object:

Code:

Dim FSO As New FileSystemObject
FSO.Drives("C:\").FreeSpace

As well as I must play one sound at time, it's easier for me write a code similar to this:

Code:

With Game.Sound("C:\WINDOWS\CHIMES.WAV")
.Play
Do While .IsStillPlaying()
DoEvents
Loop
.Stop
'etc..
End With

instead of passing to each procedure the file name to which I'm referring to. With the code above I would pass only once the param I need. And when I change that param the code works with the newer one (i.e. it plays the new file and more...)

I thought that I could pass the param from Sound property to clsSound if I would wrote a Friend property in that class. But this forces me to have both a LET and a GET property, that is also visible in my 'main' project and not only among the classes. This means that when I write my code, into the Intellisense I'll see within other properties that one that needs to exchange the param. There would not be great problems, if it wouldn't be that I have in my project lots and lots of lines of code among classes' properties and other... so, I wish that Intellisense hides the 'un-necessary things' I never use in my main project.

And for now the solution I found I believe that can satisfy at best my requests. But if you know for sure how the FSO.Drives property works, if you tell me I can copy the algorithm to create my own properties

NOTE: When I talk about 'Main project' I'm refer to the game itself, and not to all the classes I use to build it!

Originally Posted by WizBang

As for creating default properties, go to Procedure Attributes under Tools, click Advanced, then select Default for the Procedure ID.

Thank you very much, you're always so kind. With these info I believe I can improve my codes since now.

Re: [VB6]About properties...

There are a few ways to do what you want with classes and properties. One is by using an Enum. Another is by using a class as a parameter. Yet another is by using a class as a Public property. A UDT (User Defined Type) can also be used to achieve some advantageous capabilities as well.

One use of an Enum is that you could pass multiple commands into a procedure or property, so that different functions can be performed without the use of separate Public procedures. In addition, VB Intellisense will provide easy access to all members of the Enum.

To do something like FSO.Drives, you could use a class as a property. However, this may not be the best solution for your particular needs. A lighter weight approach might be to use an Enum, or UDT.

Anyway, my suggestion of a Public Sub or Function still stands. A Public Function could actually be more useful than a property. It simply depends on what exactly you need to do.

I will try to put together a small example project for you later, demonstrating some of the aforementioned approaches.

Please remember to rate the posts and threads that you find useful.How can something be both new and improved at the same time?

Re: [VB6]About properties...

I explain you more in details how my project is structured:

I have several classes (clsGame, clsSound, clsPlayers, etc...). I declare as public Game as a new instance of clsGame.

Game has several properties and methods. Some properties are grouped into clsSound and others into clsPlayers. So Game shows a Sounds property (that returns an instance of clsSound within related properties and methods) and a Players property (that returns an instance of clsPlayers within related properties and methods). We MUST put the focus on SOUNDS property.

Sounds property accepts a param (that is an Enum of the possible wav sounds my program can play) and gets back a clsSound instance. The clsSound has a Play method, that has to play the wav sound which name is passed to Sounds property.

It's something like if I have to return a collection of clsSound: in basis of the param, I return the correct instance of clsSound. The return clsSound has to execute the method I invoke when I call Sound property.

So the code resulting should be likeGame.Sounds(<Enum>).Play

The only way I found to make it work was that one I posted before. And things are going to be more complicated when I write new code and I add functionality. UDTs would help me if I've only to show properties and not also methods and functions from a property. It is possible in VB.Net, not in VB6

Anyway I look forward to your sample project as soon as you'll post it. Maybe we're saying the same things but we don't understand each other - you must know I come from Italy and my skills in English suffer of some limits -

Re: [VB6]About properties...

If there is only one instance of the sound class, then you need not use a class for it. A standard module would provide all the functionality you seek, while consuming fewer resources. For example, in a module you might have:

Re: [VB6]About properties...

If there is only one instance of the sound class, then you need not use a class for it. A standard module would provide all the functionality you seek, while consuming fewer resources.

Bad news: I've more than one clsSound.

Then I wanted to avoid to pass directly as param the sound I was going to play, because Play method has several params and adding new ones it would be difficult to read the code and to write it, too. Obviously this is my personal opinion

However, I studied hard and I finally found a good solution, that lets me to do all want. I post here

Code:

'In clsGame
Dim m_Sound As New clsSound
Public Property Get Sound(ByVal Index As Integer) As clsSounds
Set Sound = m_Sound 'Return the instance of clsSounds
On Error Resume Next
Err.Raise 999 'Raise this err to point out that Item property can be written
Sound.Item = Index 'Pass the param
End Property
'In clsSounds
Dim m_Item As String
Public Property Let Item(ByVal n_Item As String)
If Err = 999 Then
m_Item = n_Item
Err.Clear
ElseIf Err = 0 Then
Err.Raise 383
End If
End Property
Public Property Get Item() As String
Item = m_Item
End Property
Public Sub Play()
Debug.Print "I'm going to play the item : " & Me.Item
End Sub
'In Form1
Private Sub Form_Load()
Dim Game As New clsGame
Call Game.Sound(<Index>).Play
Game.Sound(<Index>).Item = <something> 'Returns the err 383 - Readonly property
End Sub

This code works exactly as I want: even though it uses both a LET and a GET property, the LET property works only if it is called inside of Sound property. De facto, it's like if I have only the GET property, who returns the item currently set.

Re: [RESOLVED] [VB6]About properties...

Perhaps you missed the last of the solutions I gave you, as it accomplishes what you asked, more intuitively than what you're now doing. Didn't you want the Intellisense to show the sound choices Enum?

Incidentally, for multiple parameters, you can use a UDT to group them, making it far easier to work with.

Please remember to rate the posts and threads that you find useful.How can something be both new and improved at the same time?

Re: [RESOLVED] [VB6]About properties...

I looked to your last solution and even though I didn't try it, I don't think it works, because there's one point you've not considered: how does the Play method (that is written into clsSound) play the file which name (or Enum) is passed to Sound property as its own param (and for this, it's like if it was declared as Private) from another class?

It is necessary to have something else that keeps the Enum so that Play can read the value and then to play it. The possible solutions are three:

the first one is to add a module and declare a var into it as Public that keeps the Sound value so that Play can access to it, but this forces to have one module to do this only.

the second one is to save into registry the value when Sound property is executed so that when Play method is invoked it read from registry the value and plays the sound. But also this way is not perfect, cause you get registry dirty and you're obliged to save and delete the keys you wrote each time the properties are used. Another disadvantage is that you cannot use the With...End With staments 'cause the operations saving/deleting don't let you to use it.

the last option you have is to use a LET/GET property, without using any 'strange' code to control how property is written. This approach is the easier but you can easly make errors when you write your code.

With my code, you have more control on what you're doing. The first advantage is the capabality to use With...End With structure to manage the Sound property within all its sub-properties and methods. Then you can access to each function without writing each time the param that does it work. At least you can know at any time what is the sound you're playing simply reading the Item property exposed by Sound property... you don't ever need to worry about some mistakes to assign in writing a new value to Item that could raise an error because as my property is structured if you try do this, you return an run-time error of read-only property.

I think this is the best property I have ever written because it meets EXACTLY my needs.

Re: [RESOLVED] [VB6]About properties...

Ooops...my mistake, in haste I omitted some code. My apologies.

However, the code you posted will not work exactly right. It cannot return the actual Item value, because a new value is assigned when attempting to read it. But perhaps worst of all, intentionally raising an error just to make the code work is poor programming practice.

Attached is an example project which functions more desirably. It will not allow the sound value to be altered except when invoking the Play function. The value passed when merely reading the sound value is essentially a dummy argument, having no effect. No errors need be raised to do this. It also provides the Intellisense for the sound value, which you indicated that you wanted. Plus I added an extra goodie or two just for fun.

There are of course many different ways to accomplish this. It just depends on what you need and/or want. For instance, you mentioned needing more than one copy of the sound class. In such a case, you could use an array, and that opens up a few other possibilities.

The line marked is a non-sense line: if I cannot assign a new value, why don't I receive any error?
I can forget this and try to change the value later. And when the program doens't work as I think, I might be crazy before I remember the reasoning at the basis of the property, don't you?

I believe it's better to get back an error if I cannot do something (e.g. the MultiLine property of a TextBox does it: in run-time you receive an error if you try to change its value).

You noted me the overwriting fault... How do you receive this?
If you call the Item property, you get back exactly the value passed as Index to Sound property... If there's something I missed, please tell me. I did lots of tests, and I didn't note anything wrong.

At the end, I would reply to one thing only:

intentionally raising an error just to make the code work is poor programming practice.

That's not true. There are a lots of different reasons to do that, and it is often the only way to do them. Some examples:

- this is the most well-known one: creating a DebugMode function. You may do it using the Debug.Assert statement and writing lots of lines of code. But a shortcut exists: you surely know that Debug.Print ONLY works in debug mode and not also in compiled EXEs. You can write the DebugMode function taking advantages of this and writing 3 lines of code:

Code:

Function DebugMode () As Boolean
On Error Resume Next
Debug.Print 1 / 0 'whereas this statement is run only at debug time, the error is raised in debug mode only
DebugMode = (Err = 11)
Err.Clear
End Function

- another example could be that to verify if key exists in Registry, like this:

Function FileExists (FileName As String) As Boolean
On Error Resume Next
FileExists = ((GetAttr(FileName) And vbDirectory) = vbNormal)
End Function

As you can see intentionally raising errors it's a way to do things rapidly (and in most cases also well) using VB code only. Think: VB.NET offers you this capability by the Try...Catch...Finally statements.

I believe that an error, if it is managed correctly, it's a value like another, neither more nor less of a byte variable you can declare...

I repeat again: these are all my personal opinions, I took after few years of programming, and they might be wrong or right, but it doens't matter: the important thing is that my program works fine indipendently from the way I used to develop it, don't you agree?

Re: [RESOLVED] [VB6]About properties...

Originally Posted by Cereal Killer

...if I cannot assign a new value, why don't I receive any error?
I can forget this and try to change the value later. And when the program doens't work as I think, I might be crazy before I remember the reasoning at the basis of the property, don't you?

You could raise an error when attempting to change the value if you wish. Just as you could raise an error when attempting to assign an invalid value. It is entirely up to you. The example is merely to demonstrate how the value can be read without changing it. It is your project, so it wouldn't be proper for me to write the whole thing for you. However, it would make sense that a value which can be set at runtime should also be readable at runtime.

You noted me the overwriting fault... How do you receive this?
If you call the Item property, you get back exactly the value passed as Index to Sound property... If there's something I missed, please tell me. I did lots of tests, and I didn't note anything wrong.

Simply reading the value requires passing a value to the Sound procedure. That value is then assigned, so you cannot actually read the value which is already assigned. This is one main reason why I suggested some other ways to go about it, other than passing a value to the Sound procedure, even when you don't want to assign a value.

As you can see intentionally raising errors it's a way to do things rapidly (and in most cases also well) using VB code only. Think: VB.NET offers you this capability by the Try...Catch...Finally statements.
...
I believe that an error, if it is managed correctly, it's a value like another, neither more nor less of a byte variable you can declare...

There is a large difference between handling errors which are beyond the ability of your program to prevent, and intentionally causing an error to make code work. This is certainly different than raising an error in response to invalid input or other inappropriate action on the part of the user. You see, your code creates an error even when the function is being used correctly.

I repeat again: these are all my personal opinions, I took after few years of programming, and they might be wrong or right, but it doens't matter: the important thing is that my program works fine indipendently from the way I used to develop it, don't you agree?

I do not agree because it is impossible to read the value currently set. If you do not want to read the value, perhaps you should raise an error, otherwise, (to use your own argument) you might forget this and try to read it later. But again, a value which can be set at runtime should be readable at runtime.

I've attached an example of a way to do it which is more intuitive, and avoids some of the problems we've been discussing.

Re: [RESOLVED] [VB6]About properties...

I understood we see things differently.

I don't say you are wrong, I only say that you cannot fully understand the 'philosophy' of my program, and how and why it is structured in that way, and try to explain you it is really difficult, neither do I.
I analyzed the project as best I could and after some months of work there are some aspects missed me yet. Things aren't so easy as they seem.

Yesterday, I had to change again my code, and now I have something like this:

This new code lets me to do things I couldn't do before (e.g. playing more than one sound at time). The new structure also avoid the risk to overwrite the file name of the sound when you attempt to read it, because Item gets back the right instance of clsItem from a collection in basis of the Index you pass it.

The code is based on the old one (as concerning to the Name property, while the Alias property returns the argument of Open_ method or a null string if sound is not opened).

I can't understand what is the matter if I raise intentionally an error to check whether properties can be written or not... I think it is the easier way to do what I want.