Class Let/Get

Discussion in 'AutoCAD' started by Paul Richardson, Aug 27, 2004.

  1. I created a test class that will create and delete ADT
    selections sets. I would like to add error checking..Should I do this thru a
    Let/Get property instead of the function? Or place error check in the
    function itself. How do I change this to a
    property? Had no luck with it...

    Thank You,
    Paul

    'Start Class cADTss.cls*****************************
    Option Explicit

    Private ssGen As AcadSelectionSet
    Private GPCode(0) As Integer
    Private GPData(0) As Variant
    Private groupCode As Variant
    Private dataCode As Variant
    'CreateSS*
    Public Function ssCreate(ByVal ssType As String) _
    As AcadSelectionSet

    Set ssGen = ThisDrawing.SelectionSets.Add(ssType)

    GPCode(0) = 0
    GPData(0) = "Aec_" + ssType

    groupCode = GPCode
    dataCode = GPData

    ssGen.Select acSelectionSetAll, , , _
    groupCode, dataCode

    Set ssCreate = ssGen

    End Function

    'DeleteSS
    Public Function ssDel(ByVal ssName As String)
    ThisDrawing.SelectionSets(ssName).Delete
    End Function

    'EndClass*****************************

    'Test sub to call cADTss.cls***************
    Option Explicit
    Sub test()
    Dim selset As New cADTss
    Dim ssWall As AcadSelectionSet
    Dim ssDoor As AcadSelectionSet

    Set ssWall = selset.ssCreate("Wall")
    Set ssDoor = selset.ssCreate("Door")
    selset.ssDel ("Wall")
    selset.ssDel ("Door")

    End Sub
     
    Paul Richardson, Aug 27, 2004
    #1
  2. Paul Richardson

    Ed Jobe Guest

    Although you can get it to work, you don't need to put it in a class. Its
    kind of overkill. Just put this function in a reg module and you can call
    the function without instantiating an object and qualifying the name with
    the class name. Also take note of the error handling inside the function.

    Public Function AddSelectionSet(SetName As String) As AcadSelectionSet
    ' This routine does the error trapping neccessary for creating selection
    sets.
    On Error Resume Next
    Set AddSelectionSet = ThisDrawing.SelectionSets.Add(SetName)
    If Err.Number <> 0 Then
    Set AddSelectionSet = ThisDrawing.SelectionSets.Item(SetName)
    End If
    End Function
     
    Ed Jobe, Aug 27, 2004
    #2
  3. Ed,
    I would like to have a group of tools I use frequently when programming. SS
    being one of the most frequent. I am also going to add the ability to send
    filters to the SS. How do you decide to when to use a class? Is there some
    benifit to having the instance? Really just wanted to understand creating
    classes better..and when to.
    Thank You,
    Paul
     
    Paul Richardson, Aug 27, 2004
    #3
  4. Paul Richardson

    Ed Jobe Guest

    Pretty much, you only create a class when you need to define what
    properties/methods an object has and have control over how the object
    behaves. If you can use the ones that come with an object/functon, then just
    call it. For a simple function, you can, but don't have to put it in a
    class. As far as organizing tools goes, there are several methods. Some use
    the tools that come with Visual Studio. Sort of like a database with code
    snippets and you look it up and paste it into your module. For vba, what I
    like to do is put commonly used code into a separate dvb so that I don't
    have copies all over the place. I call mine Toolbox.dvb. Then if you need to
    use some tools in another project, reference Toolbox.dvb and call the
    function using the syntax, Project.Module.Procedure. The only caveat to this
    method (applies to vba only) is that if the toolbox contains a class object,
    outside projects can't directly instantiate an instance. The toolbox must
    provide a function that returns an instance of the class. The class's
    Instancing property has to be set to PublicNotCreatable.
     
    Ed Jobe, Aug 27, 2004
    #4
  5. In addition to what Ed suggests, I'll save my commonly used code that
    doesn't fall into the class category in modules. Then when I start a dvb or
    vbp I just attach it. But my situation is kind unique since I almost never
    use what I write =) When I finish Client A's job, I forget about it and
    move to Client B. If I need to do maint work, I have an ide add-in that
    compares the attached mods to the master on my hd and it'll
    remove/re-import as needed.

    -- Mike
    ___________________________
    Mike Tuersley
    CADalyst's CAD Clinic
    Rand IMAGINiT Technologies
    ___________________________
    the trick is to realize that there is no spoon...
     
    Mike Tuersley, Aug 27, 2004
    #5
  6. Thank You Gentlemen...
     
    Paul Richardson, Aug 27, 2004
    #6
  7. One way you could dip your toes into classes is to modify existing ones like
    UserForms. I've made some of my forms be "smarter" forms by adding
    properties to them (just by adding Let / Get subroutines and module-level
    variables). One reason I do this is to simplify the code outside of the
    form... instead of checking the state of several controls, I can use
    something like "If frmQuery.InputsValid = true ..." instead of "If
    frmQuery.chkBox1 = True and frmQuery.chkBox2 = False and "

    Another thing I like about this is that you could update the member variable
    (the module-level variable that stores whether inputs are valid) be updated
    whenever your chkBox1.Change event fires (or any of the checkboxes). So
    your "Valid" status is sort of self-updating.

    I know you could do similar stuff with a Global (which you want to avoid
    anyway) variable called gbInputsValid, but by using a new property it is
    logically tied to the form, and [key point] multiple instances of a form
    each store their own value. For instance, with two forms created by your
    code (using "Set frmQuery2 = New frmQuery"), frmQuery1.InputsValid equals
    True but frmQuery2.InputsValid equals False.

    Hope this makes sense, and I'd like to hear some OO gurus' opinions on this
    method, if their patient enough to read this far.

    James
     
    James Belshan, Aug 27, 2004
    #7
  8. I didn't know you could edit these..I see trouble;) Could you send a quick
    Get/Let sample and direct me to the UserForm class location?

    If I understand the Let\Get Property it's main purpose is to check for valid
    data before releasing. Also, VB creates an internal Let\Get Property anyway
    if you just Declare a Public Variable.

    Thanks James..
    Paul
     
    Paul Richardson, Aug 27, 2004
    #8
  9. You don't have to edit the UserForm class definition... when you insert a
    form in the IDE, you can just add the subs into a form's code window. (Side
    note: what I'm doing is similar in Java to extending a class to make
    another one. For instance, I could make a new, more specific, class that
    EXTENDS a basic, more generic, one. So I automatically get all of the base
    class's methods/properties, and I can add my own, more specific ones....
    class AcadLine extends AcadEntity or AcadObject, in a way). I don't have
    any samples of the more powerful advantages, such as multiple instances of a
    form calling the same property but getting individual answers, but I think
    it's realistic.

    The first sub let me keep the calling code from having to deal with the
    form's controls, and instead get the value I really wanted. The next two
    subs show validation (like you mentioned), ignoring inputs that don't match
    one of the expected sizes.

    HTH, James


    Public Property Get DwgUnitsPerPixel() As Double
    DwgUnitsPerPixel = Val(txtPaperUnits.Text) / Val(txtDwgUnits.Text) /
    Val(cboRes.Value)
    End Property



    Public Property Get PlotSize() As String
    PlotSize = cboDwgSize.Value
    End Property

    Public Property Let PlotSize(newSize As String)
    Select Case Trim$(UCase$(newSize))
    Case "B SIZE": cboDwgSize.Value = "B Size"
    Case "D SIZE": cboDwgSize.Value = "D Size"
    Case "H SIZE": cboDwgSize.Value = "H Size"
    Case "J SIZE": cboDwgSize.Value = "J Size"
    Case Else
    End Select
    End Property
     
    James Belshan, Aug 28, 2004
    #9
  10. Thanks James...If I want my Property to return an Object should I use
    Set\Let instead?
    Paul
     
    Paul Richardson, Aug 28, 2004
    #10
  11. James,
    I won't put myself into the OO guru category, but I will comment anyway :)

    The following procedure demonstrates what I consider to be a proper way to
    use forms, which is just as you described. Segregating code this way makes
    maintenance much easier. It also starts opening up possibilities of other
    OO methods in your code.

    Public Sub FormExample()
    Dim layerForm As UserForm1
    Set layerForm = New UserForm1

    'Pseudo code to collect layer names to display on form
    Dim layerNames As Variant
    layerNames = GetLayers(ThisDrawing.Database, "A-*")

    'On UserForm1 a property has been created called Layers.
    'It accepts and returns an array of layer names.
    'The Layers property will take the supplied layer names
    'and provide them to a control on the form for display
    'and user selection. Note that the form is not displayed
    'on screen yet. We are simply passing data to it at this
    'point.
    layerForm.Layers = layerNames

    'Display the form and pass control to it.
    layerForm.Show

    'A control on the form, typically a "Close" button, will
    'call the forms Hide method which will transfer
    'program flow back to this calling procedure.
    'The layerForm object is still a valid object in the scope
    'of this procedure and calls can be made to its members
    'including, and especially, user defined methods and properties.

    'Get the layers that the user selected
    Dim selectedLayers As Variant
    selectedLayers = layerForm.Layers

    Dim layerName As Variant
    For Each layerName In selectedLayers
    'Code to work on user selected layers
    Next layerName
    End Sub

    --
    Bobby C. Jones

    You're use of properties and methods on forms is the correct way to use
    forms.
     
    Bobby C. Jones, Aug 28, 2004
    #11
  12. Thanks James...If I want my Property to return an Object should I use
    Set\Let instead?

    No.... You would have to use Set to point a variable to the property,
    though, and also within the property to point your property name to your new
    Object.

    Here's an example... I used Bobby's idea of having a button that just hides
    the form instead of actually closing the form. If you run this a couple
    times from the IDE, notice how the LineCount doesn't init back to 0 between
    runs since the form is staying hidden in memory. But if you use the X to
    close it, the form unloads and it bombs the rest of the program, since
    there's no form object available anymore.


    Hope this works for you.... James


    Code:
    '------- create a UserForm with two command buttons and one label
    
    '------ paste this into the form's Code area
    Dim mvarLineCount As Integer
    
    Private Sub CommandButton1_Click()
    mvarLineCount = mvarLineCount + 1
    Label1.Caption = Format$(mvarLineCount) & " lines"
    End Sub
    
    Public Property Get RandomLine() As AcadLine
    Dim startPoint(0 To 2) As Double
    Dim endPoint(0 To 2) As Double
    
    ' Define the start and end points for the line
    startPoint(0) = Rnd(): startPoint(1) = Rnd(): startPoint(2) = 0#
    endPoint(0) = Rnd(): endPoint(1) = Rnd(): endPoint(2) = Rnd()
    
    Set RandomLine = ThisDrawing.ModelSpace.AddLine(startPoint, endPoint)
    End Property
    
    Private Sub CommandButton2_Click()
    Me.Hide
    End Sub
    
    Private Sub UserForm_Initialize()
    mvarLineCount = 0
    Label1.Caption = "0 lines"
    CommandButton1.Caption = "Add Random Line"
    CommandButton2.Caption = "Create Lines"
    End Sub
    
    Public Property Get LineCount() As Integer
    LineCount = mvarLineCount
    End Property
    
    '------- paste this into Module1 and run it a few times
    Sub test()
    
    Dim i As Integer
    
    UserForm1.Show
    
    Dim newLines() As AcadLine
    
    MsgBox "LineCount = " & Format$(UserForm1.LineCount)
    ReDim newLines(0 To UserForm1.LineCount - 1)
    
    For i = 1 To UserForm1.LineCount
    Set newLines(i - 1) = UserForm1.RandomLine
    Next 'i
    
    Application.ZoomAll
    
    End Sub
    
    

    James
     
    James Belshan, Aug 28, 2004
    #12
  13. Sorry to have to disagree, but this is most definitely
    not what I would consider the 'proper way to use forms'.

    Primarily it is because it couples AutoCAD specific
    functionality (which should be regarded as generic
    and reusable), to a form. You never couple code that
    implements generic, reusable functionality directly to
    a form or other container-type UI element.

    The correct way to do it, would be to develop a custom
    control (if for example, you display layer names in a
    ListBox, then you might derive a new control class from
    the ListBox, called 'LayerListBox', which encapsulates
    the code logic needed to display and allow selection of
    layer names). And, the LayerListBox control could have
    a Database property that can be set to an AutoCAD database,
    and when you assign a vaule to that property, the control
    would do the rest (get the list of layers from database,
    and populate itself with them).

    This follows the same pattern as 'Data bound' Controls
    where you give the control a datasource, and it goes and
    gets the data from it, and populates itself with same.
    Well, an AutoCAD database or Document can be regarded as
    just another kind of 'data source', right?

    There's not really much significance to the fact that
    the conventional applications for 'data-bound' or 'data-
    aware' controls are generally applied to conventional
    databases like SQL or Access tables. The same concept
    can be employed with AutoCAD-specific data like layers.

    For years, I've used custom controls developed in Delphi,
    like TAcadLayerListBox, TAcadBlockComboBox, and so forth.
    Plop one of them onto a form, set the Database property
    to an AcadDatabase, and the control does the rest. The
    form which the control resides on has no concept of what
    is going on, as it should be.

    The basic goal is to avoid putting code that implements
    generic, reusable functionality into forms, because you
    can't as easily reuse that code if it lives in a form.

    Is it more work to do it the right way? Initially, yes.
    But in the long term, the reusability of doing it that
    way, more than compensates for the up-front investment.
     
    Tony Tanzillo, Aug 28, 2004
    #13
  14. Absolutely. Forms should only contain code necessary for the
    inter-functionality of the form - click button1 and it populates listbox1
    and disables button2.

    If custom controls are not generated, then the form should call the
    supporting code within the fuction-specific mod or cls. It makes
    migrations/updates easier. For a simpler example than Tony's, put all the
    layer specific functions within their own ALayer module/class. Need to
    access layer stuff, attach the mod/cls; need maintenance done, fix the
    master and update the individual projects by deleting the old and
    re-attaching the new. Granted, Tony's custom controls are better, but for
    anyone not up on creating a control, separating code is a good start and
    its easier to follow should someone else need to revise your code.

    -- Mike
    ___________________________
    Mike Tuersley
    CADalyst's CAD Clinic
    Rand IMAGINiT Technologies
    ___________________________
    the trick is to realize that there is no spoon...
     
    Mike Tuersley, Aug 29, 2004
    #14
  15. Thanks...Leave it to you to guys to show me how much I don't know:)
     
    Paul Richardson, Aug 29, 2004
    #15
  16. Classes are new data types. Generally, you'll create a class when you
    want data and the routines to manipulate that data to act as a single unit.
     
    Frank Oquendo, Aug 29, 2004
    #16
  17. Paul, I apologize.... I didn't even realize there was a "Property Set"
    statement... I thought you were using intuition. I just found it in the
    help, so I still can't answer your question, but at first glance it looks
    like you're on the right track.

    James
     
    James Belshan, Aug 30, 2004
    #17
  18. Thanks James...I think I got it working...No need to appolgize to me!:)
     
    Paul Richardson, Aug 30, 2004
    #18
  19. Please don't apologize for disagreeing Tony. We always learn a great deal
    when you do.
     
    Bobby C. Jones, Aug 30, 2004
    #19
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.