TheSwamp

Code Red => VB(A) => Topic started by: hardwired on April 01, 2008, 07:17:22 AM

Title: Layouts and Listboxes and other L-words..
Post by: hardwired on April 01, 2008, 07:17:22 AM
Hi,

On a new program i have a listbox which is populated by the current drawing's layouts and the main point of the program is to add / edit revision data to the titleblocks..

I have it running so that it updates the current layout, but after now adding the listbox, what i want is to have the user select the required layouts from the listbox, so could be one, three, all etc..

These are the bits and pieces i'm stuck on, so any help would be much appreciated:


1: How can i code it to find out which layouts the user selects, then loops through only these to update the titleblocks?

2: I want a Select All checkbox - so how can i program it to select all entries in the listbox..

3: When the form first loads, i want the current layout to be the only selected entry in the listbox, likewise, if the user unchecks the Select All checkbox, i want it to resort back to only the current layout selected..

Thanks..
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 08:44:24 AM
Listboxes are notorious for being a little stubborn to work with. Ok .. not stubborn, but a little unintuitive.

To be able to select multiple items in the listbox, set the multiselect property to frmMultiSelectMulti (1)

To determine what items are selected, you will need to loop through the listbox and check each item

Code: [Select]
Private SelectedLayouts() As String

Private Sub ListBox1_Change()
    Dim X As Integer
    ReDim SelectedLayouts(0)
'loop through the listbox
    For X = 0 To ListBox1.ListCount - 1
'if an item is selected
        If ListBox1.Selected(X) = True Then
'then increment our array and add it to the array
            ReDim Preserve SelectedLayouts(UBound(SelectedLayouts) + 1)
            SelectedLayouts(UBound(SelectedLayouts)) = ListBox1.List(X)
        End If
    Next X
End Sub

Now you have an array with all of the selected layouts

The SelectedLayouts() variable definition should be placed in the declarations portion of the form so it is available globally to the rest of your form.

Now to select all items in the listbox using a checkbox.

Code: [Select]
Private Sub CheckBox1_Click()
 Dim X As Integer
 For X = 0 To ListBox1.ListCount - 1
    ListBox1.Selected(X) = CheckBox1.Value
 Next X
End Sub

Cheers
Title: Re: Layouts and Listboxes and other L-words..
Post by: hendie on April 01, 2008, 08:51:40 AM
and you should be aware that the dxf code 410 to filter layouts doesn't work in VBA
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 09:10:57 AM
Ah .. forgot that little tidbit of information
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 01, 2008, 10:10:36 AM
Keith, you are a legend, you seem to help me everytime, so thanks..

Right got the select all thing and now got the array for the slected items, but now from this, how do i loop through the layouts using this array. I did have:

Code: [Select]
Dim Cx as Integer
For Cx = LBound(SelectedLayouts) To UBound(SelectedLayouts) - 1
   ThisDrawing.ActiveLayout = SelectedLayouts(Cx)
   ' blah blah blah code for revising stuff blah blah..
next Cx

Obviously For Cx = LBound(SelectedLayouts) To UBound(SelectedLayouts) - 1 just loops through the string values, so how do i pass them to the layouts. I thought that the ThisDrawing.ActiveLayout = SelectedLayouts(Cx) line would do that but i get a type mismatch error on that..

Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 10:21:18 AM
Ok .. a couple of pointers ...

You don't need to set the ActiveLayout unless you are graphically selecting objects from the screen using the mouse or programmatically selecting them using coordinates. I suspect you want to do it programmatically and can modify the attributes by selecting the proper block to work with.

If you do need to set ActiveLayout, you will need to pass the Layout object, not just the name .. to do that ...

Code: [Select]
ThisDrawing.ActiveLayout = ThisDrawing.Layouts.Item(SelectedLayouts(Cx))

Now, presumably you are going to be selecting title blocks on each layout. To do this, all you need to do is get a collection of all the title blocks in the drawing and filter them based on the layout they are in. It is a little tricky as hendie mentioned .. there is no filter for layout in VBA ... so you have to actually check the layout property of each block reference you have selected.
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 01, 2008, 10:39:01 AM
I get a Key Not found error on the ThisDrawing.ActiveLayout = ThisDrawing.Layouts.Item(SelectedLayouts(Cx)) line you gave me..

Yeah, i do want to access the titleblocks without looping through the layouts if i can and its not too hard. Up until now, all the stuff for updating titleblocks and attributes on these blocks i have done by physically looping through each layout, but sometimes due to regen times, this can be so time consuming. If i can't filter the layouts in VBA, how do do it?
Title: Re: Layouts and Listboxes and other L-words..
Post by: hendie on April 01, 2008, 10:50:05 AM
check the value of SelectedLayouts(Cx) in the locals window... you definitely made it global didn't you ?

you can filter the layouts in vba, you just can't use the 410 dxf code, which makes it a bit more involved
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 10:58:14 AM
The problem is that in the code I provided (and you subsequently used) I have initialized SelectedLayouts with 0, then increment from there. The reason I did this is because the count is not zero based .. i.e. Layout #3 = SelectedLayouts(3) .. you should begin your loop at LBound(SelectedLayouts) + 1 and end it at UBound(SelectedLayouts) .. or alternatively you could revise the code I provided to begin storing at index 0 instead of index 1
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 01, 2008, 12:16:12 PM
Brilliant Keith, thanks so much nearly there now, just need to sort out getting the current layout (the program goes to paperspace when run) to be highlighted in the listbox - how can i achieve that?
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 02:38:26 PM
Not sure I understand what you are looking to do .. do you want to go to paperspace in the layout selected in the list? If so, you will create a problem when you select more than one layout from the list.

I mentioned earlier that you could filter the title blocks into a selection set and only operate on the ones you selected.

This utility will return the block if it exists, otherwise it returns nothing. You will have to verify the block actually exists before operating on it.

Code: [Select]
Function GetBlockReferenceByLayout(ByVal strBlockName As String, ByVal strLayoutName As String) As AcadBlockReference

'setup variables
Dim BLCollect As AcadSelectionSet
Dim BlkRef As AcadBlockReference
Dim GCode(1) As Integer
Dim GData(1) As Variant
Dim GPCode As Variant
Dim GPData As Variant

'filter for selection set
GCode(0) = 0
GData(0) = "Insert"
GCode(1) = 2
GData(1) = strBlockName
GPCode = GCode
GPData = GData

'create selection set
Set BLCollect = ThisDrawing.SelectionSets.Add("BLOCKREF")
'add items to selection set
BLCollect.Select acSelectionSetAll, , , GPCode, GPData
'loop through all items in selection set
For Each BlkRef In BLCollect
    'compare layout name
    If UCase(ThisDrawing.ObjectIdToObject(BlkRef.OwnerID).layout.Name) = UCase(strLayoutName) Then
        'return the reference
        Set GetBlockReferenceByLayout = BlkRef
        Exit For 'exit the 'for' loop since we have the title block. This assumes only a single block in each layout
    End If
Next BlkRef

'delete the selection set
BLCollect.Delete
'clear the variable
Set BLCollect = Nothing
End Function

Usage should be in the following format ...
Code: [Select]
Dim blkObject As AcadBlockReference
Set blkObject = GetBlockReferenceByLayout("titleblock", "layout1")
If blkObject = Nothing Then
 MsgBox "titleblock was not found in layout1"
Else
 'do other stuff here to blkObject
End If
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 01, 2008, 03:27:16 PM
I don't want to go the layout that is selected, i have forced the program to go to paperspace when it loads, but won't need to now with your code but before it would simply go to the last layout that was used in normal draughting and thats why i wanted the current layout to be highlighted in the listbox becuase originally the program only did one layout (the current one). but as with the code you provided i don't have to cycle through the layouts physically, i don't need it anymore, all i need to do is error trap for no layouts selected in the listbox..

but for future reference and my own thirst for knowledge, how would i code the listbox to highlight the current layout?

For some reason also, the code you gave for select all on the listbox won't work anymore, it only selects one - the only alteration to your code was renaming the control and changing its ListStyle property to 1 - fmListStyleOption. it worked fine when i first used it but for some reason it won't now, even if i change the liststyle again..
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 01, 2008, 04:09:40 PM
multiselect must be set to frmMultiSelectMulti or it will fail.

To get the current layout to highlight, while populating the listbox, check to see if the layout name matches the one currently being added. If it does, then highlight. Remember the count of the listbox is -1 from the listbox index.

Code: [Select]
With ListBox1
'populate the listbox
 For Each layout In layouts
   .AddItem layout.Name
'if the current layout matches the layout just added then select it
   If layout.Name = ThisDrawing.ActiveLayout.Name Then
    ListBox.Selected(.ListCount - 1) = True
   End If
 Next

Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 02, 2008, 05:48:22 AM
Again thanks..

Now i need to sort out this Select All checkbox..

I noticed that if i remove the following code you provided:

Code: [Select]
Private Sub LayoutLIST_Change()
ReDim SelectedLayouts(0)
'loop through the listbox..
For X = 0 To LayoutLIST.ListCount - 1
'if an item is selected
    If LayoutLIST.Selected(X) = True Then
    'then increment our array and add it to the array..
        ReDim Preserve SelectedLayouts(UBound(SelectedLayouts) + 1)
        SelectedLayouts(UBound(SelectedLayouts)) = LayoutLIST.List(X)
    End If
Next X
End Sub


...from the Listbox's change event, the Select All code you provided:

Code: [Select]
Private Sub SelectAll_CHK_Click()
For X = 0 To LayoutLIST.ListCount - 1
    LayoutLIST.Selected(X) = SelectAll_CHK.Value
Next X
End Sub

.....works. But of course i need the array set-up from the listbox's change event, so is there any other way to select all entries in the listbox other than the way you first gave?

This is my final hurdle on this program, well for now, i'm sure i'll find other way to improve things on it or add functionality but for now, this is it..
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 02, 2008, 08:37:12 AM
I don't understand what you are trying to accomplish, but the code works as posted. When you select the items using your SelectAll_CHK_Click event, it will fire the LayoutLIST_Change event, not once, but once for each change made.
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 02, 2008, 08:55:43 AM
Your select all code works fine, the way it should do, but not when i have that listbox_change event that loads the array aswell - when that code is in place, the select all code only selects the first item in the listbox, not all entries..

All i want is to have a checkbox that the user can check to select all the layouts (the listbox items) or uncheck to deselect them all..
But......i also need that code you posted for loading all the layoutnames from what has been selected in the listbox into a string array, built into the listbox_change event, so i can loop through them when it comes to performing the main structure of the program..

but the listbox_change event seems to be conflicting with the checkbox_click event and i don't see why, or indeed how to get round it..
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 02, 2008, 09:07:06 AM
Well, I don't know what to tell you unless you give me more than "it doesn't work" .. What version of AutoCAD? Where is the rest of your code?
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 02, 2008, 09:11:35 AM
Here's the program, excuse the code mess, i will tidy my room when i'm done, lol

Try the select all check on the right...

I'm using AutoCAD 2008 btw..
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 02, 2008, 10:21:39 AM
I was able to figure out the problem with your program. You have X set as a global variable (and alot more too), thus when you click the button it changes the value of X before it finishes highlighting.
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 02, 2008, 11:03:09 AM
That's done it, thanks Keith. Yeah i know, as i said, i do need to do some tidying up, but got the main principle for now and it works, so will do some housekeeping when i get a chance. You're a star
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 14, 2008, 04:45:24 AM
Hi,

Thanks for all the help on this one Keith..

Got one final niggle, which can be got around but would like to iron this one out..


Code: [Select]
'Check whether any layout(s) have has been selected..
Dim Item As String
Dim SelectedRD As Boolean

Item = LayoutLIST.List(LayoutLIST.ListIndex)
SelectedRD = LayoutLIST.Selected(LayoutLIST.ListIndex)
If Not SelectedRD Then
    MsgBox "Please select one or more layouts to add the revision to..", vbExclamation, "Revision Details Editor.."
    Exit Sub
ElseIf SelectedRD Then
    'If stuff is selected then continue....
End If

If i use the Select All checkbox to select all the layouts in the list, then when i run the program its fine, but if i deselect one or more of the layouts after Selecting All (so the Select All checkbox value = true but not all items in the listbox are selected) the run the program, then it gets caught in the error trap and won't let the user continue as it must think that nothing has been picked..

Any ideas?
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on April 14, 2008, 08:18:24 AM
Your code is flawed. You are checking the status of only a single layout before proceeding. To resolve that you need to check the status of all the layouts in the listbox before proceeding. You are already building a list of selected layouts in SelectedLayouts, so it makes sense to use that list to do the deed. To that end this should work.

Remember SelectedLayouts should be declared globally as a private variable so your values from one function can be used in another.

Code: [Select]
If UBound(SelectedLayouts) > 0 Then
    'lets do some stuff
Else
    MsgBox "Please select one or more layouts to add the revision to..", vbExclamation, "Revision Details Editor.."
    Exit Sub
End If

Also, to unselect the "Select All" check box, all you need to do is add a line at the end of the LayoutLIST_Change event to compare the UBound value of SelectedLayouts to LayoutLIST.ListCount

Code: [Select]
If LayoutLIST.ListCount = UBound(SelectedLayouts) Then
   SelectAll_CHK.Value = True
Else
   SelectAll_CHK.Value = False
End If

Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on April 15, 2008, 05:05:02 AM
That's worked it, once again again again thanks Keith, you're a star..
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on May 14, 2008, 06:37:07 AM
Hi,

Right, had this one working for a while now and it works just as required, so many thanks to Keith for all his hard work and patience..

With this SELECTALL checkbox and layout listbox, which does as it says on the tin, can i get it select the inverse of whats been selected. Say i have selected all layouts (using the selectall check) then deselected the ones i don't want, so i have a random selection of layouts.....can i add another check or button to SELECT all the currently UNSELECTED layouts in the list and DESELECT all the currently SELECTED layouts in the list - ie: the inverse of the current selection (how many times do i wanna use the word 'select', lol)
Title: Re: Layouts and Listboxes and other L-words..
Post by: Keith™ on May 14, 2008, 08:16:17 AM
I wrote this on the fly, so it hasn't been tested ... you also may have to adjust the variable names:

Code: [Select]
For X = 0 to LayoutList.ListCount - 1
    If LayoutList.Selected(X) = True Then
        LayoutList.Selected(X) = False
    Else
        LayoutList.Selected(X) = True
    End If
Next X
Title: Re: Layouts and Listboxes and other L-words..
Post by: hardwired on May 14, 2008, 09:51:17 AM
spot on again Keith, much obliged :)