PDA

View Full Version : Message Box and Verify selection in a multiselect listbox issues.



daustin
09-21-2012, 07:06 AM
I have Word 2010 runing on Win7. I am new to VBA and I am haveing trouble with two things:
First: this code returns two message boxes everytime Me.txtFireCredit.value = 0;
Private Sub CKFire1_Click()
If Me.txtFireCredit.Value = 0 Then
MsgBox "You have selected 0 credit hours for Fire. If you wish to change this please do so on the Course Information Page."
CKFire1.Enabled = False
CKFire1.Value = False
GoTo NrmFire1
Exit Sub
End If
NrmFire1:
If CKFire1.Value = False Then
Fire1.Visible = False
ElseIf CKFire1.Value = True Then
Fire1.Visible = True
End If
End Sub

Second, I have a list box in a frame that is enabled by the check boxes above name goes CKFire1 = Fire check box, Fire1 = Fire Frame with a list box, LBFire1 = listbox inside the frame. I am having no problems getting the frames to show up but i can not make the check box enable again if noting is selected in the list box: here is the code :

Private Sub CKBld1_Click()
Dim i As Integer
Dim j As Integer
If Me.txtBldCredit.Value = "0" Or Me.txtBldCredit.Value = "00" Then
MsgBox "You have selected 0 credit hours for Building. If you wish to change this please do so on the Course Information Page."
CKBld1.Enabled = False And CKBld1.Value = False And Bld1.Visible = False
GoTo NrmBld1
Exit Sub
End If
NrmBld1:
For i = 0 To LBBld1.ListCount - 1
If LBBld1.Selected(i) Then j = j + 1
Next i
If j > 0 Then
CKBld1.Enabled = True
CKBld1.Locked = False
ElseIf j = 0 Then
CKBld1.Enabled = False
CKBld1.Locked = True
End If
If CKBld1.Value = False Then
Bld1.Visible = False
ElseIf CKBld1.Value = True Then
Bld1.Visible = True
End If
End Sub

Thank you in advace, this has been bothering me all morning

Frosty
09-21-2012, 12:21 PM
Have you stepped through all of the code? You need to use breakpoints and then work with the form... seeing what events are firing and when, especially if you're changing values. You're not showing enough code to actually do more than guess.

But it's always a dangerous practice to change values of controls within their own events. It's fine if you want controls to have relationships... but I wouldn't typically use the _Click event of a checkbox control to change the value of that same checkbox control to False. If I want that kind of behavior, then the control should already be disabled (probably based on the value of the txtFireCredit, using the _Change event, _AfterUpdate or something else.


Private Sub CKFire1_Click()

If Me.txtFireCredit.Value = 0 Then
MsgBox "You have selected 0 credit hours for Fire. If you wish to change this please do so on the Course Information Page."
'this kind of data validation should be in the _Change event of the txtFireCredit,
'rather than here. If your workflow requires additional validation, then it should
'happen when you dismiss your form entirely (like pressing the OK button)
CKFire1.Enabled = False
CKFire1.Value = False
End If

'this code is fine and makes sense-- create relationship of the value of this control to another
If CKFire1.Value = False Then
Fire1.Visible = False
ElseIf CKFire1.Value = True Then
Fire1.Visible = True
End If
End Sub


As for the second part-- I don't know what you mean, I'm sorry. I don't understand the question well enough. Can you restate?

I think you might want to build a separate routine in the form called "ValidateData" and consolidate all of this functionality in terms of displaying message boxes based on values, and enabling/disabling certain controls. From there, you can call that ValidateData subroutine from various events (especially when you might decide the _AfterUpdate or _OnExit events are better for a specific control than the _Change or _Click event.

daustin
09-21-2012, 12:53 PM
Thank you for the reply. When I say I am new, I really mean new. I have no training in VBA and am teaching myself how to write the code from scratch and reviewing forums. I know this pratice is dangerous but this is for a side project and I can take my time.
The bolded text, seems to have fixed the second issue: Private Sub CKBld1_Click()
Dim i As Integer
Dim j As Integer

If Me.txtBldCredit.Value = 0 Then
MsgBox "You have selected 0 credit hours for Building. If you wish to change this please do so on the Course Information Page."
CKBld1.Enabled = False
CKBld1.Value = False
GoTo NrmBld1
End If
NrmBld1:
If CKBld1.Value = False Then
Bld1.Visible = False
ElseIf CKBld1.Value = True Then
Bld1.Visible = True
End If
For i = 0 To LBBld1.ListCount - 1
If LBBld1.Selected(i) Then j = j + 1
Next i
If j > 0 And CKBld1.Locked = True Then
MsgBox "You have " & j & " items selected. You must deselect all the the chapters in the building code box before you can close it.", vbExclamation
End If
End Sub
Private Sub LBBld1_Change()
Dim i As Integer
Dim j As Integer
j = 0
For i = 0 To LBBld1.ListCount - 1
If LBBld1.Selected(i) Then j = j + 1
Next i
If j = 0 Then CKBld1.Locked = False
If j > 0 Then CKBld1.Locked = True
End Sub
I am still having the same trouble with the message box appearing twice.I would really like the message box to appear when the user clicks the check box if no hours are entered in the txtfirecredit field. The bolded text above works well it just repeats twice, i.e. you have to click ok two times to get the box to dissapear.

I have this code for the txtFireCredit _Change:
Private Sub txtFireCredit_Change()
On Error GoTo Err_Fire
Dim pSpan
If Not IsNumeric(Me.txtFireCredit) Then
If Len(Me.txtFireCredit) > 1 Then
Me.txtFireCredit.Text = Left(Me.txtFireCredit.Text, Len(Me.txtFireCredit.Text) - 1)
Else
Me.txtFireCredit.Text = ""
End If
Exit Sub
End If
If Len(Me.txtFireCredit) > 0 Then
Me.txtFireCredit.Text = Left(Me.txtFireCredit.Text, 2)
End If
If Val(Me.txtFireCredit) > 12 Then

Me.txtFireCredit.Text = Me.txtCourseHours.Text
End If
lngFireCredit = Me.txtFireCredit
If lngFireCredit > Me.txtCourseHours Then
MsgBox "You can not have more hours for a certificate than requested for the class"
Me.txtFireCredit = Me.txtCourseHours
ElseIf Me.txtFireCredit < 0 Then
Me.txtFireCredit = 0
End If

'Resets the Check boxes if the value changes
CKFire1.Enabled = True
CKFire1.Value = False
Exit Sub
Err_Fire:
Me.txtFireCredit = 0
Resume
End Sub

Thanks again for your help

Frosty
09-21-2012, 01:02 PM
Try setting a breakpoint (F9) on a couple of the related events. When you click on controls in your user form, you'll be able to establish what events are firing when.

Forget the rest of the coding within your events, you just need to increase your understanding of when events fire (and what events).

Many many events fire when you "click" a checkbox on a userform. Whether you're using all of those events is a different thing, but without you posting the user form, I would suggest creating a dummy userform, with a couple of controls, and then creating all the events you can for those controls. Put a single msgbox line like "Click Fired" and "Change fired" and "After Update fired" etc... so you can see the order of events.

Then try putting in changing the value of the same control or an associated control, and see how many times the events fire.

It requires some patience and some learning, but you'll get there. You can really spin yourself in circles if you start changing values of controls within their own events, so you may need create work-arounds.

For example, you could utilize a private boolean variable to the user form to get around the double-firing issue specifically for the message box, but this would be a real kluge, and you'd just run into the same issue over and over again.

It would be better to learn how the events are firing and when. Then you'll start to learn which ones are best for the end-user experience you desire. It's not always going to be the _Click event (for example, the Click event for a checkbox ignores the end-user entering the checkbox via the TAB key and then changing the value via the SPACE bar).

Frosty
09-21-2012, 01:16 PM
I can give you easy answers, but especially as you are new and learning this all, it would be better to avoid developing bad habits (and by that, I mean, not knowing what events are appropriate to what task, and thus always relying on the wrong event and a bunch of code simply because you chose the wrong event to do what you wanted to do).

The easy answer to the double messagebox is simply this... declare a private variable at the top of your form, like this (not in any procedure, but right near where Option Explicit is -- if you *don't* have Option Explicit at the top of your user form, you should).

Dim bAlreadyFired As Boolean

And then in the routine where you do the messagebox, you simply do...

If Me.txtBldCredit.Value = 0 Then
If bAlreadyFired = False Then
msgbox "yada"
End If
bAlreadyFired = True
Else
bAlreadyFired = False
End If


But that is a really klugey workaround, and the more you end up having to use private variables to avoid multiple firings of events, the more likely it is that you are simply coding work-arounds to your lack of knowledge, rather than increasing your own knowledge.

Make sense?

Incidentally, I'm pretty sure there are easier ways to do what you're doing in LBBld1_Change.

The .ListIndex property of a list control will be -1 if nothing is selected (even on multi-select listboxes). So that code could be simplified to

If LBBld1.ListIndex = -1 Then
CKBld1.Locked = False
Else
CKBld1.Locked = True
End If

fumei
09-21-2012, 04:58 PM
Just a point...

Me.txtFireCredit.Value = 0

.Value is whatever ANY control uses for default. If you mean to use what text value is in the control, use .Text, rather than .Value.

Me.txtFireCredit.Text = "0"

OR

Clng(Me.txtFireCredit.Text) = 0

Most of the time using .Value for a control is fine, but I think it is better to be explicit. If you mean to use .Text, then use .Text.

daustin
09-25-2012, 02:13 PM
Thank you both for your assistance. I have the form working the way that I would like with one exception. When the user selects an item from the list box, then changes the corresponding credit hours to 0 the list box locks until the user deselects all the items in the list box. I would like it to hide the list box and lock the check box one the list box selected count is 0.

Or,is there a way to automatically do this when the user changes the credit hours to zero?


Your suggestions on placing the conformation in the _change() property worked out well.
Is there a better way to code the verification? Right now only the first 3 buttons for each(Building, Fire, Mechanical, Plumbing and Electrical) work like they are supopsed to.
Are there any suggestions/nudges in the right direction to make the coding look a bit neater.

Please remember I have no formal computer language training other than Fortran, and that was about 10 years ago. Only working on this for about a week.

fumei
09-25-2012, 11:00 PM
I would say you are doing quite admirably, and you certainly are showing you are willing to listen and make some effort. Good on you.

Unfortunately I can not open your docm file to see your code. So I am afraid you are going to have to deal with Frosty...you are in excellent hands.

daustin
09-26-2012, 05:57 AM
Fumei that is not a good thing, is it something with the document?

This is meant for a lot of people to look at and use.

Any thoughts on why someone couldn't open the document?

Frosty
09-26-2012, 11:53 AM
Fumei can't read it because he doesn't have Word 2007 or Word 2010. Not because the file is corrupt.

However... you have a reference in that .docm file which is not a standard reference. You are using controls from the Microsoft Window Common Controls 2-6.0. I don't have that mscomct2.ocx on my computer. I attempted to load it and had an issue. I glanced at your form, but it is massively complex and would require a lot of time to glance through a lot of code, since I can't actually run it.

You may also have this issue with other users, if you are using a non-standard .ocx which is not typically distributed via Windows 7.

So... you have some pretty big decisions to make:
1. Where did you get this code? You didn't code this in the last week. Why are you using these special controls? Can you accomplish what you want without using mscomct2.ocx?

2. Can you provide a simplified mock-up document which has a userform that approximates what you want to have happen?

Otherwise, I'm afraid you can only get the most generalized help in terms of helping you solve your problem.

I also suspect you're going to have distribution problems of this macro, because of the reference problem.

How do you want to proceed? The best generalize help I can give you I've already given: start putting in break points at your various events to see when they fire. Sort out what you want to happen when, and try to avoid having events of specific controls change the values of those controls.

Typically... you select an option, and then you display/lock/disable/unlock/enable other controls... not change values of other controls (unless it is the context of disabling and setting a value at the same time).

daustin
09-26-2012, 12:30 PM
I have removed the
Microsoft Window Common Controls 2-6.0. I don't have that mscomct2.ocx from the controls and everything is working.
My issues at the moment are:

I would like it to hide the list box and lock the check box one the list box selected count is 0.
Or,is there a way to automatically do this when the user changes the credit hours to zero?
I can't for the life of me figure out how to start my save buttons yet. one thing at a time.I have also zipped it and put it into 97-03 template form. If anyone else was having trouble with it.

I wrote most of my code, well wrote one section then copied and pasted it. I used websites, to figure somethings out, like the phone number, spin buttons and long list. Greg Maxey has one, I can not currently post links since this is only my 4th post. I used that one for the phone number, some of the spin buttons and how to do the long list.

Thanks again for the help.

Frosty
09-26-2012, 03:22 PM
Greg is a regular poster on this board, so you don't need to post a link to his website.

To me, the biggest design flaw you have is the massive amount of copied code and controls you have in your form. It's a design flaw because it is a really unwieldy/unscalable solution. It's also a problem because you've copied a structure which you haven't fully fleshed out.

There are a number if quibbles I have about your overall form design (what's with the blue "tab here" text everywhere? But mostly I think the solution begins here: get rid of all the extra copied pages that are the 2-12 stuff. Simplify your form and code so that we can chat about how this will work.

Set up your tab orders, figure out what controls are supposed to be associated with other controls. Right now this thing is too complex to actually discuss. You've painted yourself into a corner, developmentally. I think you need to take a step back and nail down some conceptual approaches. One step backward to take two steps forward, kind of thing.

daustin
09-26-2012, 06:37 PM
Thanks for the input. I will start a simpler one tomorrow. Now that I have an understanding on how to call the pages. It makes much more sense to work on a small form to figure out the few issues I have left.

Guess I got over enthusiastic about getting most of it to work. I lost sight of the little things.

Just an FYI the blue 'Tab Key' text was to let the user know they could hit the tab key. Was it to much?

Frosty
09-26-2012, 07:25 PM
I don't know your end-users, so I can't tell you what is too much and what isn't. But since the TAB key as a way to progress through forms has been around for awhile, I think it's probably too much. For those who don't know that already, they're probably going to be looking at the mouse and back to the screen and then back to the mouse as they move from place to place on the form ;)

For the other... it looks like you've got three main pieces of info to gather:
1. Curriculum info
2. Contact info
3. Course(s) info

I would really hash out those three things, get it all working just for a single course, and then it shouldn't be too tough to add multiples. I think you're probably going to want to use a main form and a sub form.

Main criteria to figure out (and maybe you already know these answers, but it's not apparent to me in perusing the form)

1. What are all of your limiters (i.e., if a 1 hour curriculum, can't have more than 1 60 minute course... if you haven't selected building, don't show building chapters list)
2. Where do you want the information saved (both in-progress, which is possible, and after the end-user has completed the form).
3. How does the end-user modify the data entry?
4. How are you planning on deploying this to these people... and by extension, how do you plan to upgrade when you have an issue which needs to be corrected?

That should be a good way to get you started. And stay in .dot format, that way Fumei (and others) may be able to weigh in a bit more easily.

Cheers!

fumei
09-26-2012, 08:43 PM
Holy crap. That is a complicated form for very experienced VBA programmers. There are some convoluted series of logic gates. Good grief.

It will take me some time to try and work through it...so I will reiterate comments Frosty made. Get rid of the extraneous pages for now. Better yet make a simple version.

Answer Frosty's four questions.

Yikes. This is very ambitious, but good for you.

daustin
09-28-2012, 01:39 PM
Okay, I have simplified the form a bit. 4 pages instead of 14.

To answer your questions:

Main criteria to figure out (and maybe you already know these answers, but it's not apparent to me in perusing the form)

1. What are all of your limiters (i.e., if a 1 hour curriculum, can't have more than 1 60 minute course... if you haven't selected building, don't show building chapters list)
2. Where do you want the information saved (both in-progress, which is possible, and after the end-user has completed the form).
3. How does the end-user modify the data entry?
4. How are you planning on deploying this to these people... and by extension, how do you plan to upgrade when you have an issue which needs to be corrected?


The only real limiters are just that- if they have not selected building it should not show. It is set now that they are able to go back and change the values which in turn enables or disables the check boxes for the buildng list. A 1 hour ciriculum however can have each of the courses in it, building,fire,electrical, mechanical and plumbing.
We would like the information to save while in progress and at the end (last module save button) save the document as CourseTitleSponsorNumberDate, and tell the user the title and where it was saved.
This one is a little tricky for me as, I thought the only method of entry was the user form. We would like the user to be able to open the saved document and edit the data at their will.
The deployment will be through internet download. Updates will be posted to the internet.okay in this simplified one, Ithink some of the 'cluter' comes from my lack of vba knowledge , I have added in functions for some of the code that was repeated in the buttons.

'Makes the module pages visible
Private Function ModVisible()
Dim x As Integer
Dim y As Integer
x = MultiPage1.Pages(0).txtChours.Value
For y = 0 To x + 1
Me.MultiPage1.Pages(y).Visible = True
Next y
End Function
'Rsets the module pages if the course hours change
Private Function ModReset()
Dim x As Integer
Dim y As Integer
x = MultiPage1.Pages(0).txtChours.Value
For y = (((x + 2) - 2) + 2) To 3
Me.MultiPage1.Pages(y).Visible = False
Next y
End Function

I have also solved the problem i had earlier

Or,is there a way to automatically do this when the user changes the credit hours to zero?

The red text fixed that:
'Disables the check boxes if 0 building credits are selected:
If Me.txtBldC = 0 Then
y = 0
Me.CKB1.Enabled = False
Me.CKB2.Enabled = False
' Checks to see if anything is selected in the Building chapter list box for Module 1:
If CKB1.Locked = True Then
x = 0
If y = x Then
MultiPage1.Value = 2
j = 0
For i = 0 To LBB1.ListCount - 1
If LBB1.Selected(i) Then j = j + 1
Next i
If MsgBox("You have " & j & " chapters selected in Module 1 under the Building Code." _
& " Click 'OK' to clear the selected chapters.", vbOKCancel) = vbOK Then
For i = 0 To LBB1.ListCount - 1
LBB1.Selected(i) = False
Next i
CKB1.Value = False
CKB1.Enabled = False
Else:
CKB1.Locked = False
CKB1.Enabled = True
Building1.Visible = True
Me.txtBldC = 0
End If
End If
End If
' Checks to see if anything is selected in the Building chapter list box for Module 2:
If CKB2.Locked = True Then
x = 0
If y = x Then
MultiPage1.Value = 3
j = 0
For i = 0 To LBB2.ListCount - 1
If LBB2.Selected(i) Then j = j + 1
Next i
If MsgBox("You have " & j & " chapters selected in Module 2 under the Building Code." _
& " Click 'OK' to clear the selected chapters.", vbOKCancel) = vbOK Then
For i = 0 To LBB2.ListCount - 1
LBB2.Selected(i) = False
Next i
CKB2.Value = False
CKB2.Enabled = False
CKB2.Locked = False
Else:
CKB2.Locked = False
CKB2.Enabled = True
Building2.Visible = True
Me.txtBldC = 0
End If
End If
End If
End If

I think some of the problem is that I(beleive that I) need so many variables. I would love to write some functions that could take away from some of the code. I tried all day to get this working, thinking this small one would lead me to the larger ones:
Private Function NextVisible()
'Makes the next button invisible if the next page in the set is not visible.
Dim MyArray(1 To 3) As String
MyArray(1) = Me.cmdNextBtnMod1
MyArray(2) = Me.cmdNextBtnMod2
MyArray(3) = Me.cmdNextBtnMod3
Dim y As Variant
Dim x As Integer
Dim z As Variant
For x = 2 To 4
For y = LBound(MyArray) To UBound(MyArray)
z = "Me.cmdNextBtnMod" & y
If Me.MultiPage1.Pages(x).Visible = False Then
MsgBox z
z.Visible = False
ElseIf Me.MultiPage1.Pages(x).Visible = True Then
MsgBox z
z.Visible = True
End If
Next y
Next x
'original, this works in the code trying to get rid of these lines
'If Me.MultiPage1.Pages(3).Visible = False Then
' Me.cmdNextBtnMod1.Visible = False
'Else: Me.cmdNextBtnMod1.Visible = True
End If
End Function
I am begining to think that you can not make a variable and use it as an object. It would always fail here: z.Visible = False , told me that I need an object but the msgbox read what it needed to say?/shrug

I have a habit of taking really big bites, but I didnt think the code was that complex just a lot of var's and pages. Which is why I started looking into the replacing an object with a variable in a loop.

It's the weekend, the Glenlivet Nardurra, will clear my head and back at it Monday morning.

Frosty
09-28-2012, 04:50 PM
It's obvious you have programming experience. I think the main problem is that you don't have object-oriented programming experience. The problem, in a nutshell, is that this will be far far easier to accomplish (and modify later) if you start exploring a totally different data structure (and thus, a bit of a different user interface).

Before I really look at your code, I just want to explore the concept of UDTs with you, to see if this seems useful.

You have an instructional course, the details of which you are asking the end-user about. That course has a name, as well as several other properties. For explanation purposes, I'm going to keep it simple.

Right now, you think you need to dimension individual variables for each possible course (this is why you think you need so many variables), because you think you need to create a userform with as many pages as you might allow total number of courses, and thus all of those extra controls (since controls have to have unique names).

I know these aren't the actual variables, but this for demonstration purposes.

Dim strCourseName1 As String
Dim strCourseLocation1 As String
Dim strCourseName2 As String
Dim strCourseLocation2 As String
Dim strCourseName3 As String
Dim strCourseLocation3 As String

etc.

However, you don't need to do this. Not in your main CallUF routine, nor in your CEForm.

There are several better approaches to this. I'm going to explain the one that is easiest to explain, although it is not the one that I would use myself.

You can use a UDT ("User Defined Type") as a repository for all of the information you have about a course.

Here's a brief demo of populating a couple of UDT instances, as well as adding them into an array. I've purposefully mixed and matched the start value of 1 and 0 so that you can see that it doesn't matter (although I wouldn't leave this kind of inconsistency in the final product, this is just for demonstration).

You should step through this code, as well as make sure to view the Locals Window and the Immediate Window within the VBA Editor (under the view menu):

Public Type ptInstructionalCourse
CourseName As String
CourseLocation As String
End Type
Sub DemoUDTs()
Dim oMyCourse As ptInstructionalCourse
Dim i As Integer
Dim aryUDTs() As ptInstructionalCourse

'initialize our array
ReDim aryUDTs(0)

With oMyCourse
For i = 1 To 2
Select Case i
Case 1
.CourseName = "Course 1"
.CourseLocation = "Course Location 1"
Case 2
.CourseName = "Course 2"
.CourseLocation = "Course Location 3"

Case Else

End Select
'add it to the array
ReDim Preserve aryUDTs(i - 1)
aryUDTs(i - 1) = oMyCourse
Next
End With

For i = LBound(aryUDTs) To UBound(aryUDTs)
Debug.Print aryUDTs(i).CourseName
Next
End Sub


The other two approaches, which I think I mentioned previously, would be to create a custom class (serving the purpose of the UDT) and add that class to a collection (serving the same purpose of the array). *OR* you could simply utilize a separate user form for the purposes of getting the individual course info (where you are using additional pages on the main userform), and add the actual instances of the userform to a collection. This last is the most complicated to explain, but is the way I would approach it.

This is simply a re-organization of the way you're thinking about holding this data. Trust me when I say that if you do something like the above, a *LOT* of the rest of the coding will end up seeming easy.

Where to go from here: I think you should investigate using two separate simple forms with no pages-- just two simple user forms: 1 which gathers generic info (Pages 1 and 2 of your existing form), and another which gathers info about a specific course (Page 3 of your existing form). I would forget about the output, for the moment.

Don't need all this Next/Previous stuff... you just need some add/edit/remove buttons associated with the Course Names displayed in a list box on the main form. And then you can select a particular course, click the Edit button, and an instance of your "SpecificCourseInfo" subform pops up with the right settings, based on your UDT.

Can you give that a whirl? I know this feels like overly simplistic major steps backwards, but it will help in the end.

Enjoy the Glenlivet and the weekend!

fumei
09-28-2012, 05:54 PM
Jason,
*OR* you could simply utilize a separate user form for the purposes of getting the individual course info (where you are using additional pages on the main userform), and add the actual instances of the userform to a collection. This last is the most complicated to explain, but is the way I would approach it.
you would have individual userforms (in a collection) for each course? Interesting. Yes, I would enjoy watching you explain that...

It is actually a - or could be - an very efficient method to the problem. Depending on the number of courses involved, how you handle the data flow would be most, hmmmm, amusing.


And I will sip my vintage (1948!) Armagnac...I only have about a sixth of the bottle left. So sad. Mind you, it has taken me almost two years to get through that much.

Frosty
09-28-2012, 07:25 PM
Well, userforms are just classes. And they already hold all the data you care about. So rather than an array of UDT middle men or a collection of custom class middlemen, you just have a collection of individual instance userforms.

It's a hard thing to explain because the locals window would be so messy... But it's the most efficient way of doing it. Userform to hold the individual data, collection to hold as many as you need, and a regular procedure to grab the data and dump into a document. Maybe some autotext boilerplate stored so that the course info can be easily repeated, although we haven't discussed output yet.

But that is a tough series of concepts to explain without already understanding UDTs, I think.

gmaxey
09-28-2012, 10:25 PM
Jason,

Sounds interesting, but I can't seem to be able to implement it. I've got a form with two text boxes "Course" and "Location." I display it for as many times as the user want to add courses. I'm trying to add each userform to a collection a they are completed. It seems that as each new form is added to the collection it makes a dog's breakfast out of the one preceeding it. Thereofore I am only able to output the last form added.

What am I missing? Thanks.

ub GetCourseInfo()
Dim oFrmInput As UserForm1
Dim oObj As Object
Dim bIWantSomeMoIWantSomeMo As Boolean
Dim oCol As Collection
Dim i As Long
Set oCol = New Collection
bIWantSomeMoIWantSomeMo = True
Do While bIWantSomeMoIWantSomeMo
Set oFrmInput = New UserForm1
oFrmInput.Show
oCol.Add (oFrmInput)
If MsgBox("Do you wnat to add another course?", vbYesNo, "Add Course") = vbNo Then
bIWantSomeMoIWantSomeMo = False
End If
Loop
Debug.Print oCol.Count
'For i = 1 To oCol.Count
' Set oObj = oCol(i)
' Debug.Print oObj.Item(0).Text
' Debug.Print oObj.Item(1).Text
'Next i
Set oObj = oCol(oCol.Count)
Debug.Print oObj.Item(0).Text
Debug.Print oObj.Item(1).Text

End Sub

Frosty
09-28-2012, 10:52 PM
Hmm, I'll have to double check my own proof of concept. I used a for each loop to iterate through the collection to check that the values were different, and I assume your form's okay button is just a me.hide, so... I don't know. Just in reading the code, you've approached it generally the same way I did. Let me check tomorrow... Maybe it's not so straight forward as I thought.

Or maybe there's something funky about using an object variable? Did you check the locals window to examine your collection, and see if the collection seemed to have different items there?

gmaxey
09-29-2012, 05:35 AM
Jason,
Actually I didn't have an OK button just the two text boxes and killing the instance of the form with the "X," but it doesn't seem to matter. Adding the the "OK" button with me hide has the same result.

When the first item is added to the collection. It is in fact a form object, it appears as Item 1 with two items itself. However when the next userform is added to the collection, it seems to destroy the first usererm. The collection gets a new item 2 (which has two items) but Col item one is dead. Still there but with no itmes itself.

gmaxey
09-29-2012, 06:17 AM
Let me revised that a bit. It does seem to matter. Killing the userform makes all the difference. I've added the OK button to hide the form and changed the code as shown and it seem to work nicely.

Sub GetCourseInfo2()
Dim oFrmInput As UserForm1, oObjForm As Object
Dim bIWantSomeMoIWantSomeMo As Boolean
Dim oCol As Collection
Dim lngIndex As Long
Set oCol = New Collection
bIWantSomeMoIWantSomeMo = True
Do While bIWantSomeMoIWantSomeMo
Set oFrmInput = New UserForm1
oFrmInput.Show
oCol.Add oFrmInput
If MsgBox("Do you wnat to add another course?", vbYesNo, "Add Course") = vbNo Then
bIWantSomeMoIWantSomeMo = False
End If
Loop
For Each oObjForm In oCol
Debug.Print oObjForm.Item(0).Text
Debug.Print oObjForm.Item(1).Text
Set oObjForm = Nothing
Next oObjForm
lbl_Exit:
Exit Sub
End Sub


I'm assuming the set oObjForm = Nothing
is taking then killing the form instance right?

Thanks. Very interesting approach.

Frosty
09-29-2012, 09:36 AM
Actually, I think it's the use of the Red X without adjusting the QueryClose event of the userform. Clicking the Red X is basically the same as triggering an unload. I don't think your oObjForm = Nothing is actually killing the instance inside the collection, just the use of that variable in that loop.

The following works just fine for me... userform with a single text box called txtTest and a single command button called cmdOK.

Sub FormsInACollectionDemo()
Dim colForms As Collection
Dim f As UserForm1
Dim i As Integer

Set colForms = New Collection
'create as many instances of the form, as long as user is filling in data
Do
Set f = New UserForm1
f.Show
If f.txtTest.value <> "" Then
colForms.Add f, f.txtTest.value
End If
Loop Until f.txtTest.text = ""

'iterate throught yhe collection one way
For i = 1 To colForms.Count
Set f = colForms(i)
Debug.Print f.txtTest.text
Next

'and another way
For Each f In colForms
Debug.Print f.txtTest.text
'try these different items... don't see to have an effect on the collection
'Unload f
'Set f = Nothing
Next
End Sub

And within my userform, I have the following events (which it may be helpful for anyone exploring this and the order of events)...

Private Sub UserForm_Initialize()
Debug.Print "Initialize"
End Sub
Private Sub cmdOK_Click()
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Debug.Print "QueryClose"
If CloseMode = 0 Then
Debug.Print "Red X pressed"
'change Cancel value, to avoid the unload
Cancel = 1
'wouldn't normally put a hide here... I'd normally put a cmdCancel_Click
'but this is a form without a cmdCancel button, so this will do
Me.Hide
ElseIf CloseMode = 1 Then
Debug.Print "Unloading the form"
End If
End Sub
Private Sub UserForm_Terminate()
Debug.Print "Terminate"
End Sub

Notice you'll get a bunch of terminate events at the end of the procedure (when the collection gets garbage collected), but you'll only trigger the QueryClose event if you hit the Red X or you use Unload in the calling routine. Setting the form object to nothing doesn't trigger a query close, just a terminate... and it seems that it doesn't even do that if you set the form object to nothing within a for each loop (the iterator becomes nothing, but the item in the collection is still there).

Frosty
09-29-2012, 09:40 AM
I was re-evaluating my approach to forms based on someone else's post recently, and so I re-learned some stuff I used to know, and learned some new stuff I don't think I ever knew (the differences between Unloading a form and setting a form variable to nothing).

In any event-- regarding the OP... some of the above may be useful as well, if you're interested in exploring something other than the array/UDT approach.

gmaxey
09-29-2012, 10:24 AM
Jason,

This is all very interesting. In fact, I've been tinkering with a practical example: http://dl.dropbox.com/u/64545773/Dummy%20Insurance%20Application.dot

The template also has some examples in the code module using the UDT/Array and Class/Collection methods.

Thanks.

daustin
10-01-2012, 09:48 AM
Okay while I am wrapping my head around this new approach I have just one question, posed a few ways.

In the original coding, while it is very cumbersome, the user can see the information that they have entered, go back and edit it as well. How can this be accomplised using collections and arrays?
Can the input be shown visually? Can it be reacalled if the user has entered 4 'modules' since the mistake.

If the user enteres the information for 12 modules, exits the userform then realizes there is a mistake, do they have to reenter all the information again to correct the one mistake on the last module.

Not trying to insult the end users of our products but, they will most likely have to edit something, and they will only realize it after they have entered all the information and are ready to send it off.

Regardless of the answer(s), I will look more into the UDT, collection and arrays.

Thank you all for your input.

Frosty
10-01-2012, 10:25 AM
Daustin,

Yes, you can do all of the above and more. You can store the data wherever you want, display it whenever you want and recall it whenever you want.

There is nothing intrinsic about strVar1 and strVar2 being easier to display or not than aryStrings(1) and aryStrings(2). It's simply a question of how you organize the data. And obviously an array is a heck of a lot easier to add an additional item to, rather than having to go back to the code and add strVar3.

That's the only conceptual lesson here... everything else is actually relatively easy, with the bonus being that as long as you get 1 "lesson" right (I hate to use "modules" since that can get confusing in terms of coding), you can have 3 "lessons" or 12 "lessons" or 50 "lessons" -- it's just a question of how you display them.

In fact, you *could* actually display your form exactly the same way, if that was your desired manner of doing the input (horizontal pages up to a maximum of 12), the difference behind the scenes would be that you don't actually individual controls on individual pages... you simply use the "page change" event to store the data from the controls and then clear out the data of the controls (if you're going forward). If you were going backward, then you would retrieve the previously stored data and put those values into the controls.

However, I wouldn't recommend this UI design, but ultimately you are the decider of how you want your user interface to work, since you are the one that determines what is best for your end-user's.

The only thing I'm saying you absolutely should not do, is the analogy of having:
strVar1 As String
strVar2 As String

when you can have:

aryStrings() As String

Now, you don't *have* to explore the UDT/Collection/Arrays/Classes stuff too much, we can help. I would just say that if you can separate out your two forms and simplify them further so that you aren't using pages (can always bring them back), then it will be relatively easy to help. Don't worry about navigation or any of that, just the data you want to capture from the end-user in a logic order.

Frosty
10-01-2012, 11:22 AM
And you can take a look at Greg's template, as that seems to (in my cursory overview) be doing some of what we're talking about here.

I think you just need a proof of concept out of this thread, which you can then start to do designing on.

But, if I were project managing you as a programmer, I would say the development order would be something along these lines:
1. Create your frmMain as the user form which grabs all relevant data from the end-user, but no class-specific data.
2. Create your frmClass as the user form which captures all relevant data about a specific class.
3. Create a function which takes all data from frmMain and dumps it into a table at the top of a document, with the first row containing the title "Main Data" -- make sure this function checks to see if a table with the first row containing "Main Data" already exists in the document, and if so, it wipes out all rows by the first one, and repopulates with new data.

4. Create a function which takes all data from frmClass and dumps into a table with the name of the Class (whether the name is "Module1" or whatever else). Make sure it works just like the Main Data function, in that it checks to see if that table already exists.

5. Create a function which grabs data from the Main Data table and populates frmMain with it.

6. Create a function which, when passed a specific "Class Data" table, populates the frmClass with the relevant data.

That's sort of how I'd approach... from there, it will be trivial to adjust your main form to allow you to "navigate" between existing classes, delete classes, etc etc. You wouldn't be obligated to storing your data in Word tables, but it would help you visualize the functionality. From there, you could decide to store the data in Document Variables instead of actually in the document. It really depends on how you want your end-users to interact with the document/macro template

daustin
10-01-2012, 12:25 PM
Thanks, I beleive that I have a better understanding of what you are talking about now. I did this after my last post and it makes sense, I will look at greg's stuff tomorrow.

The way this one is now, when you add a 'lesson' it opens infront of the previous 'lesson'. I have the check buttons working now, will mess with the hours tomorrow. try to disable the check boxes depending upon what the user selects as the hours for each course, i.e. building, fire, etc.


Thanks again, this is acutally fun. I really get a kick out of learning something new.

Frosty
10-01-2012, 01:59 PM
That's really great progress. Couple of quick comments:

1. Turn on Option Explicit as a default (this is under Tools > Options > Editor). The default is to have Auto Syntax Check turned on, and Require Variable Declaration turned off. You should change these to have Auto Syntax Check turned off, and Require Variable Declaration turned on. The first one will stop the constant squawking from VBA that you've typed something wrong, the second will add Option Explicit to the top of all of your code modules. Option Explicit requires you to explicitly declare variables. It saves you from doing something like this:
Dim strMyString As String
strMString = "Hello I'm a totally different variable"
Also -- get used compiling your project often. This is a habit I do as much as saving my work while coding. It's under the Debug menu, but I always add that particular command to a toolbar.

2. I've made a couple of modifications to your project. I wouldn't incorporate this with what you're doing yet, but I think you can begin to see how it would go.

3. The QueryClose events are very important, because otherwise an end-user can mess everything up with a Red X.

4. Set the Cancel property on any Cancel buttons to True-- this allows the end-user to hit the ESC key to essentially get out of the form.

gmaxey
10-01-2012, 03:33 PM
Jason/Daustin,

Just trying to keep a pratical example simple: https://dl.dropbox.com/u/64545773/Dummy%20Insurance%20Application.dot

Note: I'm not using a "Cancel" button because it plays havoc with the text field Exit procedure which is intended to validate and require and entry. I did discover that even if the user "X" and kills the form and the oCol.Add statemenet errors the count in the oCol is still upticked. Seems odd.

Frosty
10-01-2012, 03:57 PM
I haven't had a chance to look at your latest, Greg, but you don't need a cancel button necessarily. You do, however, need to know why the form is now hidden. Since I don't like using Unload in my form code, I typically set up a public constant in my calling module a la
Public USERFORM_CANCEL As String = "Cancelled"
And then in the cancel button (or directly in QueryClose) set the .Tag property of the form to that constant a la
Me.Tag = USERFORM_CANCEL

From there, in my my main routine I check the .Tag property if the userform to determine whether I should do anything with the form. Relying on error trapping won't work, as the form won't be unloaded via the Red X if you chance the Cancel parameter of the QueryClose event.

gmaxey
10-01-2012, 04:35 PM
Jason,

Add I haven't really had the chance to flush it out. If fact that eye that you and I have sometimes discussed is casting its gaze on me right now.

Never to match styles ;-), I frequently use Unload, but I like your idea of a public Kill_Cancel variable.

If you kill the form, won't the .Tag property die along with it?

The lastest variation of the simplified example: https://dl.dropbox.com/u/64545773/Dummy%20Insurance%20Application.dot

fumei
10-01-2012, 08:54 PM
Generally, and assuming I give the user a graceful way to Cancel out if they wish, I tend to disable the user being able to use the "X".

I think using "X" is an UNgraceful way out.

fumei
10-01-2012, 08:54 PM
Generally, and assuming I give the user a graceful way to Cancel out if they wish, I tend to disable the user being able to use the "X".

I think using "X" is an UNgraceful way out.

fumei
10-01-2012, 08:54 PM
Generally, and assuming I give the user a graceful way to Cancel out if they wish, I tend to disable the user being able to use the "X".

I think using "X" is an UNgraceful way out.

fumei
10-01-2012, 08:55 PM
What the heck happened there??????

Frosty
10-02-2012, 10:53 AM
Fumei, that looks to me like you're spamming. We'll have to report you to the administrators. ;)

Why do you think hitting the Red X is an ungraceful way to exit a userform? The Red X is ubiquitous in the Microsoft environment, and anyone with a computer generally knows that clicking a Red X is a "get me out of here" function. If we could *hide* the Red X in Word VBA (the way you can in Access, if I recall correctly), I could go along with hiding it, but since we can't hide it... I'd rather not have a button which simple appears not to work over programming it to work the way a user would expect it to work (do *something* rather than *nothing*).

My philosophical approach to User Interface design is to, whenever possible, approximate the functionality and design of built-in microsoft dialogs. And the two most basic userforms I come back to are the Format Paragraph dialog (a modal form) and the Insert Cross References dialog (a modeless form). I also like the Find dialog in its approach to the "More" button concept (turning a simple form into a complex form for some uses).

The more similar a custom userform is to a built-in dialog, in terms of functionality, the less you have to explain to a trained user (and untrained users will need the explanation anyway-- with the added bonus that if they learn the custom dialog, then they will be closer to knowing how built-in dialogs work). And even though we can tell users not to click on the Red X, they will still do it... if only because we may not have an opportunity to "train" them away from this behavior.

And thus my argument has always been that a visible Red X should always work just like a Cancel button. But either making it work like a Cancel button or disabling it still requires custom coding (by putting code for the QueryClose event).

What is your argument for disabling the functionality of it? Habit? Or something more?

Frosty
10-02-2012, 11:10 AM
Greg:

I think the argument for using the form to unload itself can go both ways. My argument against having the form unload itself goes something like this:
1. Forms need to be called by something (the "calling routine").
2. Garbage collection in a single place is always easier to deal with that garbage collection in multiple places.
3. Except for modeless forms, I like to minimize the amount of "doing" code in a userform, preferring to simply have "get user input" code in the userform, and have "doing" code in the calling routine. Modeless forms obviously have to unload themselves, since the calling routine doesn't stop processing, but even then I just have to make a slight adjustment to allow the Red X to be used the same as the Cancel button (which, on a modeless dialog, I typically name "Done").

The following code assumes the following: userform with a single button called cmdCancel. The .Cancel property of that button is set to True.

When that userform is a modal userform, this would be my "standard" code.
Calling Routine -- modal dialog

Sub DemoFormUsage()
Dim f As UserForm2

Set f = New UserForm2
f.Show
With f
If .Tag = "USER CANCEL" Then
GoTo l_exit
End If
'do stuff, using the info gathered in the userform
End With
l_exit:
Unload f
End Sub

Form code - modal dialog

Option Explicit
Private Sub cmdCancel_Click()
Debug.Print "Cancel click"
Me.Tag = "USER CANCEL"
Me.Hide
End Sub
Private Sub UserForm_Initialize()
Debug.Print "Initialize"
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Debug.Print "QueryClose"
'point the Red X to the cancel button, so all exits of the form are the same
If CloseMode = vbFormControlMenu Then
Cancel = 1
cmdCancel_Click
End If
End Sub
Private Sub UserForm_Terminate()
Debug.Print "Terminate"
End Sub

Calling Routine - modeless dialog

Sub DemoFormUsage()
Dim f As UserForm2

Set f = New UserForm2
f.Show
End Sub

Form code - modeless dialog

Option Explicit
Private Sub cmdCancel_Click()
Debug.Print "Cancel click"
Unload Me
End Sub
Private Sub UserForm_Initialize()
Debug.Print "Initialize"
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Debug.Print "QueryClose"
'point the Red X to the cancel button, so all exits of the form are the same
If CloseMode = vbFormControlMenu Then
cmdCancel_Click
End If
End Sub
Private Sub UserForm_Terminate()
Debug.Print "Terminate"
End Sub
The main difference between the Red X and the cmdCancel_Click event is the order in which they happen (if you click the Red X, QueryClose happens and then cmdCancel_Click happens, if you click Cancel or ESC, cmdCancel_Click happens, and then QueryClose is triggered during the garbage collection of the Unload method-- or if you simply exit the calling routine). But they both, I *believe* are relatively "graceful" exits of the userform, from the end-user perspective.

EDIT: yes, the .Tag property disappears when the form is completely unloaded... but the order of when the form is unloaded can get a little screwy in the Modeless example above, if the Red X is pressed (which triggers QueryClose followed by cmdCancel_Click, followed by the end of QueryClose, followed by Terminate) -- this may be the kind of scenario Fumei is talking about with an ungraceful exit. I'm not sure why Microsoft designed it this way, but my approach only encounters the strangeness of this design in modeless dialogs, which are considerably less common.

gmaxey
10-02-2012, 12:06 PM
Jason,
I all seems sound and I think if I look around, I'll probably find som old projects where I have done something very similiar.

My problem is that I am unorganized and often do the same thing a half a dozen ways :-(.

What do you think about:

cmdCancel.Value = True
instead of
cmdCancel_Click

I've seen it done both ways.

Frosty
10-02-2012, 12:18 PM
Half a dozen ways of doing the same thing isn't a bad thing... then we all get to learn something. "Fresh eyes" is what I call it.

I didn't know that setting the .Value of a command button is the same as clicking it (which I tested, and it seems to be).

I guess the only "problem" with cmdCancel.Value = True is that it won't cause a Compile error if the command button exists on the form, but you've forgotten to actually add the Click event. Obviously compile errors are "better" than run-time errors, generally speaking. But in this case, it would be pretty obvious at some point during development that you were missing something so essential to the form as cmdCancel_Click.

fumei
10-02-2012, 01:16 PM
I mis-spoke. I did not mean disable really, I meant act like a Cancel button. In that clicking the X causes a controlled exit (rather than an abrupt I'm outta here regardless of whatever havoc it may cause).

Which is not always the case for any Windows X.

Frosty
10-02-2012, 01:22 PM
Ahh... then you and I agree.

My response, then, was directed towards scenarios where I have seen the Red X be commandeered so that it either is disabled (clicking it effectively does nothing, from the end-user's perspective) or that clicking it generates a msgbox to the effect of "You must click the Cancel button to close this form" -- both of which I've always thought were less graceful than simply redirecting the functionality to the actual cancel button.

gmaxey
10-02-2012, 01:40 PM
The former I don't mind. The latter annoys the living daylights out of me. I also don't mind and often simply make it go away. In fact the example posted at the moment does just that but I think I'm going to change that and do it like wev'e been discussing here. That really is probably best.

gmaxey
10-02-2012, 03:07 PM
Jason/Gerry

It should come as no surprise, but when I see something that interests me as this topic has, I will usually publish something about it:

http://gregmaxey.mvps.org/word_tip_pages/repeating_item_lists.html

Hardest part was crafting a title. Still don't know if I am happy with what I've chosen.

The piece on the class object with private propeties is probably a little weak. Truth is, I don't know that much about them.

Thanks for all of your inputs here and DAustin I didn't mean to take over your thread. Hope you don't see it that way.

Frosty
10-02-2012, 03:24 PM
Greg: the page looks fantastic... and it is a great summary of all the various things described in this thread.

Daustin: If you're getting stuck on your own project, I would highly recommend taking a look at Greg's link. The final demo of two userforms is exactly what I've been recommending (so of course, I think it's brilliant *grin*)

fumei
10-02-2012, 03:39 PM
Hmmmmm. I have to agree that "Repeating Item List" is weak, or rather, not fully descriptive. I do not know what to replace it with, but I do have to say your samples of what you mean by "repeating item list" is good.

Multiple Similar Items?

I agree that. for most, the use of the word "class" scares the crap of them.

Hmmmm.

Good article though. I will keep a copy of the link handy, as it is a great (ahem) user friendly introduction.

fumei
10-02-2012, 03:51 PM
So you are going to UNhide the close X?

gmaxey
10-02-2012, 04:02 PM
Gerry,

I did in the the final demonastration code. However, in the practical example code project both forms have the "X" button hidden as Jason must have overlooked ;-).

I did this on purpose so people looking at the demo pack documents can see both techniques.

Thanks for you input. In Word 2013, MS calls the new content controls "Repeating Section" and they basically add a new row to a table with controls that match the controls in the previous row. The purpose of course is provide data fields so a user can repeat and create the next list item, section, row, or whatever one wants to call it.

I give up on a better name for now as the eye beginning to cast its gaze in my direction.

Thanks.

Frosty
10-02-2012, 04:18 PM
I didn't actually download and check the code from your page, but it's nice to see that I'm wrong about not being able to hide the Red X in Word VBA user forms. I don't want to get too used to being right all the time, hehe. ;)

Still, that sure is a lot of work to hide that button (private declares, a subroutine which gets passed a dialog object, and then calling that subroutine in any initialize event of a form you don't want to have the Red X in). But, I'm definitely going to keep that code around if I ever need it, so thank you! That seems like it could be a (short) tip page in and of itself...

How to Hide the Red X in Custom UserForms

daustin
10-03-2012, 01:43 PM
Okay, glad I could spark a conversation in which everyone learns something.

I learned something important. Do not show any one a prototype project until you are sure you want to go that direction.

So with that said and after 10 people (4 of which have nothing to do with this at all, but feel that they are ever so important) have given input. We finally have a form with that 95% of the parties involved (not sure why they are involved) can agree to. Oh and I am the 5%, because I liked the two form one with no pages.
So the stipulations were:
"We liked the pages, what happened to the pages. Give us the pages!"
"It must and I mean must fit on a 800 x 600 resolution. Some of our users do not know how to change that setting!"
"This one is too tall and to cluttered, I liked the first one."

So attached is what was agreed upon. Now I have had a frustrating two days so not too much has been done.

I like the idea of removing the red X, question regarding that. I have put that code in for the frmMod, it works if you just run that form but does not work if the from is called by the information form. I am lost on that one.

The forms now have the function of the previous iteration. I am stuck on crossing the forms with variables.
This code would tell the user if something in the listbox was selected:
If CKB1.Locked = True Then
x = 0
If y = x Then
MultiPage1.Value = 2
j = 0
For i = 0 To LBB1.ListCount - 1
If LBB1.Selected(i) Then j = j + 1
Next i
If MsgBox("You have " & j & " chapters selected in Module 1 under the Building Code." _
& " Click 'OK' to clear the selected chapters.", vbOKCancel) = vbOK Then
For i = 0 To LBB1.ListCount - 1
LBB1.Selected(i) = False
Next i
CKB1.Value = False
CKB1.Enabled = False
Else:
CKB1.Locked = False
CKB1.Enabled = True
Building1.Visible = True
Me.txtBldC = 0
End If
End
I tried something along the lines of
If frmMod.CKBuilding.Locked = True Then
j = 0
For i = 0 To LBB1.ListCount - 1
If frmMod.LBBuilding.Selected(i) Then j = j + 1
Next i
If MsgBox("You have " & j & " chapters selected in Module 1 under the Building Code." _
& " Click 'OK' to clear the selected chapters.", vbOKCancel) = vbOK Then
For i = 0 To frmMod.LBBuilding.ListCount - 1
frmMod.LBBuilding.Selected(i) = False
Next i
frmMod.CKBuilding.Value = False
frmMod.CKBuilding.Enabled = False
Else:
frmMod.CKBuilding.Locked = False
frmMod.CKBuilding.Enabled = True
frmMod.BuildingFrame.Visible = True
Me.txtBuildingHours = 0
End If
End
but it would lock up, before I even entered a number for building hours.

I will look at Greg’s stuff tomorrow. I glanced at it today, it is only one form but follows the same input pattern that I am going for now.

A nudge in the right direction for verifying things across forms would be great.

Frosty
10-03-2012, 02:51 PM
Haven't had a chance to look at any of this code (nor will I, at least for today), but I just wanted to make sure you know that the actual design of the form is totally immaterial to the construction and organization of your data.

Please don't go back to the "pages" implementation you had before... you can easily give a "pages" look without having to implement it the way you did.

The only thing this design spec forces is that you can't store a bunch of individual sub-forms into a collection -- you'll need to use either a UDT/Array combo or a Class/Collection combo.

I would look over Greg's page before you start copying/pasting a bunch of controls.

daustin
10-04-2012, 01:53 PM
I understand that now, another afternoon wasted just trying to get the exact same thing that I had before.

I did separate the pages out into user forms. I was looking at the verification that Greg used in his forms, tried implementing that into mine with good success other than the boxes connected to the spin buttons, when you open that form the ok button is enabled, and locks when you enter the box I thought I set to unlock it.

Will work some more on it tomorrow.

If either of you gets a chance to look at these two trials any comments/ criticism you have would be appreciated.

gmaxey
10-08-2012, 11:06 AM
daustin,

The "ok" button is enabled because you never evaluated it in the Initialize event to disabled it. In the function you wrote to validate it, there is no mention of the state of the spinbuttons or the text fields they affect.

daustin
10-11-2012, 02:04 PM
Okay took a break. Back at it this afternoon, thanks for the spot gmaxey, fixed the enable issue there. I took most of the verification stuff out of the code for the moment since I run this constantly to see how it works.
Finally got the forms talking to each other, just not the way I intended.
Two major things:
·The course info form is the main data entry. I have it set to remove items from the list if the user lowers the number of credit hours after adding CE modules. Which it does it just leaves the last items which I thought I had it remove by stepping backwards in the for loop.
·The addmodule form shows the list of all the CE modules added by the user. There is a delete button on this form, it does delete the module then rename the rest of the modules. however the program then fails when the user tries to edit a module.
I believe that both of these issues have something to do with the way the collection items are named. [/font]
Again just a nudge in the right direction would be appreciated.

I did look at the class stuff, and maybe I haven't grasped it fully yet but I think this is the best option (for my skill level) at the moment.