Results 1 to 10 of 10
  1. #1
    Join Date
    Sep 2010
    Posts
    18

    Building a String from Numerous Subforms

    Hi Programmers,
    How could one best build a string from check boxes on multiple continuous subforms? I’m expanding on Albert Kallal’s form in his MultiSelect.mdb at www.kallal.ca/msaccess/msaccess.html, and am using his form as a subform but putting the cmdbuttons on the main form. My challenge is that I’ve duplicated the subform 10xs so that each subform shows a different subset of records from the same underlying table and behaves seemingly independently. This works fine.

    In Albert’s dbase, the string is built in the main form with:
    Dim strWhere As String
    strWhere = MySelected
    If strWhere <> "" Then
    strWhere = "CourseID in (" & strWhere & ")"

    However, I need to combine 10 strings from my 10 subforms into one main form string, and use that string for a report. Is there an easy way to do this? Note that some of the subforms will not have any “yes” checkboxes.

    Here is a start…

    Private Sub Command16_Click()

    Dim strWhere1 As String
    Dim strWhere2 As String
    Dim strWhere3 As String
    Dim strWhere4 As String
    Dim strWhere5 As String
    Dim strWhere6 As String
    Dim strWhere7 As String
    Dim strWhere8 As String
    Dim strWhere9 As String
    Dim strWhere10 As String



    strWhere1 = MySelected
    If strWhere1 <> "" Then
    strWhere1 = "CourseID in (" & strWhere1 & ")"

    strWhere2 = MySelected
    If strWhere2 <> "" Then
    strWhere2 = "CourseID in (" & strWhere2 & ")"

    strWhere3 = MySelected
    If strWhere3 <> "" Then
    strWhere3 = "CourseID in (" & strWhere3 & ")"

    strWhere4 = MySelected
    If strWhere4 <> "" Then
    strWhere4 = "CourseID in (" & strWhere4 & ")"

    strWhere5 = MySelected
    If strWhere5 <> "" Then
    strWhere5 = "CourseID in (" & strWhere5 & ")"

    strWhere6 = MySelected
    If strWhere6 <> "" Then
    strWhere6 = "CourseID in (" & strWhere6 & ")"

    strWhere7 = MySelected
    If strWhere7 <> "" Then
    strWhere7 = "CourseID in (" & strWhere7 & ")"

    strWhere8 = MySelected
    If strWhere8 <> "" Then
    strWhere8 = "CourseID in (" & strWhere8 & ")"

    strWhere9 = MySelected
    If strWhere9 <> "" Then
    strWhere9 = "CourseID in (" & strWhere9 & ")"

    strWhere10 = MySelected
    If strWhere10 <> "" Then
    strWhere10 = "CourseID in (" & strWhere10 & ")"

    End If

    DoCmd.OpenReport "Courses1", acViewPreview, , strWhere

    End Sub

    Thanks for help

  2. #2
    Rod is offline Expert
    Windows Vista Access 2007
    Join Date
    Jun 2011
    Location
    Metro Manila, Philippines
    Posts
    679
    Just perused Albert Kallal's mdb. It's an elegant solution to an oft stated requirement.

    You do not ask for help with moving the command buttons to the parent form so I conclude that's OK. Ten subforms seems excessive but if you're happy then again, OK. However the bank of string statements you quote looks awful. Yes there's an easier way, there's always an easier way.

    If you still need help tell us exactly what information is returned for each selected row. (In Albert's case it was simply a record number.) Also tell us what the resultant concatenated string should look like. Finally tell us the names of the ten subform controls.

  3. #3
    Join Date
    Sep 2010
    Posts
    18
    Thanks for responding Rod.

    Very similar to Kallal's dbase--the info that is returned is a record number. Basically, I'm trying to simply grab or pull the "IsSelected" record numbers from out of the 10 subforms (copies of sfrmCourses) and simply join the record numbers together in a string on the parent form. I'm just a beginner developer and don't know how to do this.

    copies of the subform control:
    sfrmCourses1, sfrmCourses2, ..., sfrmCourses3

    Just like in other where strings for queries or reports, I just wanted the resultant string to be separated by commas.

    The report I'm planning on will simply list the records that are selected from the Yes/No checkboxes in the subform copies. One of the reasons that I've copied the subform 10xs is to filter each subform differently; but the underlying records are all from the same table.

    Thanks again,
    ST

  4. #4
    Rod is offline Expert
    Windows Vista Access 2007
    Join Date
    Jun 2011
    Location
    Metro Manila, Philippines
    Posts
    679
    OK, I think I understand. If you ask 10 Access programmers how to fulfil your requirements you will get eleven solutions; some solutions will be more suited to a particular setup than others. I however offer only one solution.

    OK, what I will do is explain how I intend to fulfil your requirement (including some commentary and theory) before going on to give you practical help with the implementation itself. I always believe in trying to explain because then maybe my correspondents can sort a few things out for themselves. If I’m too detailed or saying things you already know then tell me.

    There is a VBA object class called a Collection and Albert uses an instance of this class to store the record number of the rows selected. As a record is selected it is added to the collection and if it is deselected it is removed from the collection. When a resultant string is required, Albert loops through the collection concatenating the record numbers. He also interrogates this collection to determine whether each checkbox should be true or false.

    You now have ten copies of the form and therefore you have ten collections. Moreover these ten forms are subforms and you need to address them from the main form. I propose your main form also has a collection. When a resultant string is required, each of the collections on the subforms is interrogated in turn and the selected record numbers added to the main form collection. Then the resultant string is built from the main form’s collection. The main form collection can be built so that the record numbers are sorted and duplicates dropped! It would be possible to maintain the main form’s collection as you go along but then subforms need to either push data to the main form or alert the main form that a row has been (de)selected. I prefer my solution because it is more straightforward and Albert’s form may be used with minimal change.

    You could also simply extract the ten strings and concatenate them – the solution you were trying to find for yourself. Again, I prefer my solution because you can sort the record numbers and because the string handling is much simpler.

    A situation that confuses every beginner with Access is the way of addressing a subform. The main form has a control in which the subform is displayed. This control is not the subform. Many beginners confuse the control and the subform and address the control thinking they are addressing the subform. This is not helped by the fact that Access uses the subform’s name as the default name for the control (or used to, I haven’t checked lately). The control has a property called Form that is a reference to the form displayed. So the general pattern of addressing a subform is:

    Me.sfrControl.Form

    It gets tedious typing this out in full each time so I recommend a local variable is dimensioned to act as an alias. You have defined your subform control names in a consistent manner and it will be possible to loop through these controls – is the tenth called ‘sfrmCourses10?’ (BTW The accepted Reddick tag for a subform control is ‘sfr’ without the ‘m’ but no matter.)

    OK, let’s get on with it. I am assuming you are comfortable with navigating around the VBA coding window and the form design window (including the property sheets). If you aren’t, shout.

    There is one change and only one change to make to Albert’s code. (Some of the code is now redundant but we can leave it there. I also assume you have removed the command buttons.) We need to make the subform’s collection ‘visible’ to the main form. In the VBA coding window for FORM_UnboundCheckBox (or whatever you’ve now called it) find the line (it’s at the top)

    Code:
    Dim colCheckBox As New Collection
    And change it to be

    Code:
    Public colCheckBox As New Collection
    You may also want to ‘comment out’ the Debug.Print statement. It doesn’t get in the way but ‘every little helps.’
    Now there’s quite a bit to add to the main form but it’s straightforward. Display your main form’s module in the VBA coding window. If it doesn’t show in the hierarchy then display your main form in design view and check that the value of Has Module (‘Other’ tab in the Property Sheet window) is set to ‘Yes.’

    I attach what your main form module should look like. I have renamed the command buttons as btnShow and btnClear. (This makes much more sense than command14 and command17.) I have not programmed for the report – one step at a time – when this is working for you let’s do the report. Or maybe you can have a go.

    Code:
     
    Option Compare Database
    Option Explicit
     
    Private mcolSelected As New VBA.Collection
    Private mfrmSub As Form_UnBoundCheckBox 'Use your own name if necessary.
     
    Private Sub BuildCollection()
    Dim i As Integer
    Dim j As Integer
    Set mcolSelected = Nothing 'Quick trick to empty the main collection. 
    For i = 1 To 10
    Set mfrmSub = Me.Controls("sfrmCourses" & CStr(i)).Form 'Set mfrmSub for each subform in turm.
    For j = 1 To mfrmSub.colCheckBox.Count
    AddToMainCollection mfrmSub.colCheckBox(j) 'Adds the record id in sequence.
    Next j
    Next i
    Set mfrmSub = Nothing
    End Sub
     
    Private Sub AddToMainCollection(rlngRecordID As Long)
    Dim i As Integer 
    For i = 1 To mcolSelected.Count
    If mcolSelected(i) = rlngRecordID Then Exit Sub 'Drop duplicate record ids.
    If mcolSelected(i) > rlngRecordID Then
    mcolSelected.Add rlngRecordID, , i 'Add in sequence.
    Exit Sub
    End If
    Next i
    mcolSelected.Add rlngRecordID 'Add at end 
    End Sub
     
    Private Function BuildSelectionString() As String
    Dim i As Integer
    For i = 1 To mcolSelected.Count
    If BuildSelectionString <> "" Then BuildSelectionString = BuildSelectionString & ","
    BuildSelectionString = BuildSelectionString & CStr(mcolSelected(i))
    Next i 
    End Function
     
    Private Sub btnClear_Click()
    Dim i As Integer
    For i = 1 To 10
    Set mfrmSub = Me.Controls("sfrmCourses" & CStr(i)).Form
    Set mfrmSub.colCheckBox = Nothing
    mfrmSub.Check11.Requery
    Next i
    Set mfrmSub = Nothing
    End Sub
     
    Private Sub btnShow_Click()
    BuildCollection
    If mcolSelected.Count = 0 Then
    MsgBox "Nothing selected."
    Else
    MsgBox "Records selected = " & BuildSelectionString
    End If
    End Sub
    My test with only two subforms suggest this is quite slow. It's nothing I have done ("Honest guvner!") but is due to the Access reaction time of the checkbox control source and requery.

  5. #5
    Join Date
    Sep 2010
    Posts
    18
    Hi again Rod,

    Thanks for all of your time and effort. I am going to try this later today and will post my results.

  6. #6
    Join Date
    Sep 2010
    Posts
    18
    MAN THAT IS WAY COOOOOOL!!!

    Even though you said that there are multiple ways to accomplish this, your code worked perfectly, and there is 0 time lag. Your explanations are outstanding.

    Now I can just use BuildSelectionString in a query to produce reports...think I can figure this out.

    However, now starting to churn in my head are new ideas like...emailing a report to multiple staff...bypassing Outlook...embedding the report in the body rather than in an attachment...transparency to users (who are students without email accounts)...trial and error...research...losing sleep and hair...probably another thread for another day...

    Thanks again Rod

  7. #7
    Rod is offline Expert
    Windows Vista Access 2007
    Join Date
    Jun 2011
    Location
    Metro Manila, Philippines
    Posts
    679
    The quick and dirty (surely not!) way of emailing without using Outlook directly is to use the SendObject macro action. I think however that it will use your email client and if this is Outlook, then you're stuck with Outlook. Why not read up on SendObject in the Access on-line help.

    'Transparency.' There's a useage that always fascinates me. Surely it's the wrong word. If something is transparent I can see right through it, not see it at all. Translucent or opaque seem to me to be more appropriate and accurate.

    Get back if you need more help.

  8. #8
    Join Date
    Sep 2010
    Posts
    18
    Hi once more,

    I have one more dilemma pertaining to the original topic. I now need to parse or split the "BuildSelectionString" and append it to a join table (jClientsAndCourses), and also append the ClientID and other fields to each new row.

    A thread from another site that is most similar to this issue is:
    http://www.access-programmers.co.uk/...d.php?t=201907, which is where the below code came from.

    A preliminary attempt at coding worked somewhat for the table field named "CourseID"--recall that "BuildSelectionString" is a comma delimited string of CourseIDs selected from the subforms.

    How can I also append the client's ID (ClientID) as well as the general date/time (ScheduleDateTime) from the main form into the same table, jClientsAndCourses? I've tried various things like rs(ClientID) = me.ClientID in the below code but cannot figure out the syntax.


    Private Sub cmdSave_Click()
    BuildCollection

    Dim strParts() As String
    Dim rs As DAO.Recordset
    Dim intCounter As Integer

    strParts = Split(BuildSelectionString, ",")
    Set rs = CurrentDb.OpenRecordset("jClientsAndCourses")

    For intCounter = LBound(strParts()) To UBound(strParts())
    rs.AddNew
    rs(CourseID) = strParts(intCounter)

    rs.Update
    Next intCounter
    rs.Close
    Set rs = Nothing

    End Sub

    Thanks

  9. #9
    Join Date
    Sep 2010
    Posts
    18
    Just to close out this thread...

    My problem was appending the string of CourseIDs (BuildCollection) as separate rows into the table jClientsAndCourses along with setting the values of the corresponding fields to those in the current main form.

    Syntax changes:

    Private Sub cmdSave_Click()
    BuildCollection

    Dim strParts() As String
    Dim rs As DAO.Recordset
    Dim intCounter As Integer

    strParts = Split(BuildSelectionString, ",")
    Set rs = CurrentDb.OpenRecordset("jClientsAndCourses")

    For intCounter = LBound(strParts()) To UBound(strParts())
    rs.AddNew

    rs.Fields("ClientID") = Me.ClientID
    rs.Fields("CourseID") = strParts(intCounter)
    rs.Fields("ScheduleDateTime") = Me.txtDateTime

    rs.Update
    Next intCounter
    rs.Close
    Set rs = Nothing

    End Sub

    I'm learning. Thanks again Rod.

  10. #10
    Rod is offline Expert
    Windows Vista Access 2007
    Join Date
    Jun 2011
    Location
    Metro Manila, Philippines
    Posts
    679
    Yes, you are learning - but you've 'gone there and back to see how far it is.'

    You have built a string from the collection, split the string into an array, and then iterated through the array - and it works!

    You could have simply iterated through the collection.

Please reply to this thread with any new information or opinions.

Similar Threads

  1. Building a FAQ
    By Karin in forum Access
    Replies: 5
    Last Post: 03-07-2011, 11:26 AM
  2. Building
    By jlech1805 in forum Access
    Replies: 1
    Last Post: 11-17-2010, 12:10 PM
  3. GROUP numerous lines to one record
    By tweetyksc in forum Queries
    Replies: 3
    Last Post: 07-21-2010, 01:14 PM
  4. Building Array
    By jgelpi16 in forum Forms
    Replies: 12
    Last Post: 03-22-2010, 12:33 PM
  5. Problem with building SQL string (VBA)
    By cdpeck in forum Programming
    Replies: 1
    Last Post: 09-15-2009, 04:25 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Other Forums: Microsoft Office Forums