CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Dec 2012
    Posts
    38

    [RESOLVED] [VB6]About properties...

    Hi all,

    I've another question for you whereas nobody could help me.

    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.

    That's all folks.
    bye

  2. #2
    Join Date
    Dec 2007
    Posts
    234

    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...

    -tg
    * I don't respond to private requests for help. It's not conducive to the general learning of others.-I also subscribe to all threads I participate, so there's no need to pm when there's an update.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help - how to remove eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to???
    * On Error Resume Next is error ignoring, not error handling(tm). * Use Offensive Programming, not Defensive Programming.
    "There is a major problem with your code, and VB wants to tell you what it is.. but you have decided to put your fingers in your ears and shout 'I'm not listening!'" - si_the_geek on using OERN
    MVP '06-'10

  3. #3
    Join Date
    Dec 2012
    Posts
    38

    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.

  4. #4
    Join Date
    Dec 2001
    Posts
    6,332

    Re: [VB6]About properties...

    I think you'd do better to create a Public Sub or Function within the class module. Something like this perhaps:
    Code:
    Public Function Play(Filename As String) As Boolean
      'Play the file
      'If successful, set Play to True (for error handling if desired, otherwise use a Sub)
    End Function
    As for creating default properties, go to Procedure Attributes under Tools, click Advanced, then select Default for the Procedure ID.
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  5. #5
    Join Date
    Dec 2012
    Posts
    38

    Re: [VB6]About properties...

    Quote Originally Posted by WizBang View Post
    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!

    Quote Originally Posted by WizBang View Post
    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.
    Last edited by Cereal Killer; December 14th, 2012 at 04:28 AM.

  6. #6
    Join Date
    Dec 2001
    Posts
    6,332

    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?

  7. #7
    Join Date
    Dec 2012
    Posts
    38

    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 like
    Game.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 -

  8. #8
    Join Date
    Dec 2001
    Posts
    6,332

    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:
    Code:
    Option Explicit
    Public Enum Sounds
      Sound1
      Sound2
      Sound3
      Sound4
    End Enum
    
    Public Sub Play(Sound As Sounds)
      'Play the sound
    End Sub
    Then, from anywhere in your application, a sound could be played like:
    Code:
    Module1.Play Sound3
    You can also use a unique name for the Public Sub, in which case there'd be no need to specify the module name.

    If you use a class for the sound, then you'd use it this way:
    Code:
    Dim S As clsSound
    
    Set S = New clsSound
    
    S.Play Sound3
    
    Set S = Nothing
    If you want a sound class to be within a game class, then it could work like this:
    Code:
    Dim G As clsGame
    
    Set G = New clsGame
    
    G.Sound.Play Sound3
    Yet another way to do it, the syntax would more closely resemble what you've been asking:

    In your sound class:
    Code:
    Public Sub Play()
      'Play the sound
    End Sub
    In your game class:
    Code:
    Public Enum Sounds
      Sound1
      Sound2
      Sound3
      Sound4
    End Enum
    
    Public Function Sound(S As Sounds) As clsSound
    Set Sound = New clsSound
    End Function
    Then you'd use it like:
    Code:
    Dim G As clsGame
    
    Set G = New clsGame
    
    G.Sound(Sound3).Play
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  9. #9
    Join Date
    Dec 2012
    Posts
    38

    Re: [VB6]About properties...

    Quote Originally Posted by WizBang View Post
    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.

    Anyway, thank you for all the time you spent to help me...
    Bye bye,

    Cereal Killer

  10. #10
    Join Date
    Dec 2001
    Posts
    6,332

    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?

  11. #11
    Join Date
    Dec 2012
    Posts
    38

    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.

    However, thanks again, but I took my ultimate decision.

  12. #12
    Join Date
    Dec 2001
    Posts
    6,332

    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.
    Attached Files Attached Files
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  13. #13
    Join Date
    Dec 2012
    Posts
    38

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

    This is a part of your code
    Code:
    Private Sub Form_Load()
    Dim G As clsGame
    Set G = New clsGame
    With G
      Debug.Print .Sound(None).SoundName & " (" & .Sound(None).SoundID & ")"
      .Sound(Ding).Play
      .Sound(2).SoundID = 4 'cannot change property - no effect
      Debug.Print .Sound(None).SoundName & " (" & .Sound(None).SoundID & ")"
      .Sound(Dong).Play
    End With
    Set G = Nothing
    End Sub
    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:
    Code:
    Function KeyExists(AppName As String, Section As String, KEY As String) As Boolean
      On Error Resume Next
      Call GetSetting(AppName, Section, KEY, Nothing)
      KeyExists = (Err = 0)
    End Function
    - another common one is this:
    Code:
    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?
    Last edited by Cereal Killer; December 17th, 2012 at 04:28 AM.

  14. #14
    Join Date
    Dec 2001
    Posts
    6,332

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

    Quote Originally Posted by Cereal Killer View Post
    ...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.
    Attached Files Attached Files
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  15. #15
    Join Date
    Dec 2012
    Posts
    38

    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:
    Code:
    With Game.Sounds.Item(<Index>)
        .Open_ <Alias>
        .Play <Sync|Async>
        .Close_
        MsgBox .Name
        MsgBox .Alias
    End With
    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.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured