MS Office Forum / Excel / New Users / October 2006
Critique of code
|
|
Thread rating:  |
Greg - 16 Oct 2006 21:22 GMT Hi,
I consider myself a dabbler in Word VBA and a begginer (is there anything less skilled than that :-)?) with Excel.
With my technical level established, a user in the Word VBA groups asked how to populate a dropdown field in a Word document with data from Excel and then populate other fields in Word with Excel data based on the item selected in the dropdown.
First of all you can't have a dropdown field in Word that contains more than 25 items so a Word UserForm is required.
I thought I would have a go at figure out this problem.
I created auser form (named UF) contain one listbox and one command button.
I call the userform with:
Sub CallUF() Dim myFrm As UF Set myFrm = New UF myFrm.Show Unload myFrm Set myFrm = Nothing End Sub
I created a Excel file named: C:\myWorkbook1 The spreadsheet has 3 columns headed: "Name" "Age" "Address" I named the excel range containing the data "mydatabase"
Next I populated the listbox from the spreadsheet column 1 using the Userform Initialize event.
'First, you need to set a reference in your project to the Microsoft DAO 3.51 '(or 3.6) Object Library.
Private Sub UserForm_Initialize() Dim db As DAO.Database Dim rs As DAO.Recordset Set db = OpenDatabase("C:\MyBook1.xls", False, False, "Excel 8.0") Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`") While Not rs.EOF Me.ListBox1.AddItem rs.Fields(0).Value rs.MoveNext Wend rs.Close db.Close Set rs = Nothing Set db = Nothing End Sub
In the document, I created bookmarks "Name" "Age" "Address" where I wanted the data to appear. I used the Command Button click event to process the UserForm Listbox selection and populate the data in the document:
Private Sub CommandButton1_Click() Dim db As DAO.Database Dim rs As DAO.Recordset Dim oNameRng As Word.Range Dim oAgeRng As Word.Range Dim oAddressRng As Word.Range Dim oBM As Bookmarks Dim i As Long Set db = OpenDatabase("C:\MyBook1.xls", False, False, "Excel 8.0") Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`") Set oBM = ActiveDocument.Bookmarks Set oNameRng = oBM("Name").Range Set oAgeRng = oBM("Age").Range Set oAddressRng = oBM("Address").Range i = Me.ListBox1.ListIndex oNameRng.Text = Me.ListBox1.Text oBM.Add "Name", oNameRng rs.Move (i) oAgeRng.Text = rs.Fields(1).Value oBM.Add "Age", oAgeRng oAddressRng.Text = rs.Fields(2).Value oBM.Add "Address", oAddressRng Me.Hide End Sub
Like I said, I am no expert with Excel and while it appears to work in this simplified example it may actually be a real dog's breakfast.
I appreciate any comments that would expain inefficiencies in my method or explanations of a better method.
Thanks.
Bob Phillips - 16 Oct 2006 23:36 GMT > Hi, > [quoted text clipped - 49 lines] > Set db = Nothing > End Sub Why bother with DAO, just open a new instance of Excel from within Word
Private Sub UserForm_Initialize() Dim xlApp As Object Dim xlWB as Object Dim xlWS as Object Dim cRows As Long
Set xlApp = CreateObject("Excel.Application") Set xlWB = xlApp.Workbooks.Open(("C:\MyBook1.xls") Set xlWS = xlWB.Worksheets(1) cRows = xlWS.Range("myDatabase").Rows.Count - xlWS.Range("myDatabase").Row + 1
> In the document, I created bookmarks "Name" "Age" "Address" where I > wanted the data to appear. I used the Command Button click event to [quoted text clipped - 31 lines] > I appreciate any comments that would expain inefficiencies in my method > or explanations of a better method. then just load the listbox direct
Dim i As Long
With Me.ListBox1 For i = 1 To cRows .AddItem xlWs.Range("myDatabase").Cells(i,1) .List(.ListCount - 1, 1) = xlWs.Range("myDatabase").Cells(i,2) .List(.ListCount - 1, 2) = xlWs.Range("myDatabase").Cells(i,3)
End With
Bob Phillips - 16 Oct 2006 23:56 GMT Forgot to tidy-up
Set xlWS = Nothing Set xlWB = Nothing xlApp.Quit Set xlApp = Nothing
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> > Hi, > > [quoted text clipped - 111 lines] > > End With Greg Maxey - 17 Oct 2006 00:10 GMT Bob,
Thanks for the comments. This gives me some things to ponder.
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> Forgot to tidy-up > [quoted text clipped - 121 lines] >> >> End With Pete_UK - 17 Oct 2006 00:37 GMT So, a "dabbler" in Word VBA is also a MVP !! What does that make the rest of us ?? <bg>
Pete
> Bob, > [quoted text clipped - 131 lines] > >> > >> End With Greg Maxey - 17 Oct 2006 01:13 GMT Pete,
When I consider what I know with what there is to be known then regardless of the letters after my name I am still a dabbler ;-)
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> So, a "dabbler" in Word VBA is also a MVP !! What does that make the > rest of us ?? <bg> [quoted text clipped - 136 lines] >>>> >>>> End With RagDyer - 17 Oct 2006 01:45 GMT When you put it that way (consider what I know with what there is to be known), then there can *only* be dabblers in this world.
It should be ... "consider what I know, with what others know, of what there is to be known", and then you MVP's are definitely *not* dabblers!<vbg>
 Signature Regards,
RD
--------------------------------------------------------------------------- Please keep all correspondence within the NewsGroup, so all may benefit ! ---------------------------------------------------------------------------
> Pete, > [quoted text clipped - 141 lines] >>>>> >>>>> End With Greg Maxey - 17 Oct 2006 02:15 GMT Pete/RD
It would be rude for me to ignore your compliments. Thank you.
I think most MVPs, Word and others, would say that the MVP program is as sucessuful as it is because of the collective contributions of the individual MVPs.
I have had no formal training in VBA. While I plow my way through workable solutions to many problems, I don't really understand the "object model, or the difference between a method, variable, procedure etc. Despite the continued efforts of true masters "Classes" is still a dark territory. For those reasons and others, I say "dabble. ;-)
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> When you put it that way (consider what I know with what there is to > be known), then there can *only* be dabblers in this world. [quoted text clipped - 153 lines] >>>>>> >>>>>> End With Bob Phillips - 17 Oct 2006 09:03 GMT You can be a Word MVP without ever touching VBA, the award is given for community support which could be all within the front-end of Word.
Ditto Excel.
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> When you put it that way (consider what I know with what there is to be > known), then there can *only* be dabblers in this world. [quoted text clipped - 146 lines] > >>>>> > >>>>> End With Greg Maxey - 17 Oct 2006 03:18 GMT Bob,
Ok. Thanks for showing me the direct method. I didn't really want to populate 3 listboxes in a user form. I only wanted to populate the one listbox with the data in the "Name" column adn then fillin the the appropriate bookmark in the document with the item selected in the list box and the other bookmarks with the related data.
Here is the command button click code I used:
Private Sub CommandButton1_Click() Dim xlApp As Object Dim xlWB As Object Dim xlWS As Object Dim cRows As Long Dim oNameRng As Word.Range Dim oAgeRng As Word.Range Dim oAddressRng As Word.Range Dim oBM As Bookmarks Dim i As Long Set xlApp = CreateObject("Excel.Application") Set xlWB = xlApp.Workbooks.Open("E:\My Documents\Excel Files\WordLinkedSpreadsheet.xls") Set xlWS = xlWB.Worksheets(1) Set oBM = ActiveDocument.Bookmarks Set oNameRng = oBM("Name").Range Set oAgeRng = oBM("Age").Range Set oAddressRng = oBM("Address").Range i = Me.ListBox1.ListIndex oNameRng.Text = Me.ListBox1.Text oBM.Add "Name", oNameRng oAgeRng.Text = xlWS.Range("mySSRange").Cells(i + 2, 2) oBM.Add "Age", oAgeRng oAddressRng.Text = xlWS.Range("mySSRange").Cells(i + 2, 3) oBM.Add "Address", oAddressRng Set xlWS = Nothing Set xlWB = Nothing xlApp.Quit Set xlApp = Nothing Me.Hide End Sub
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> Forgot to tidy-up > [quoted text clipped - 121 lines] >> >> End With Bob Phillips - 17 Oct 2006 09:04 GMT Greg,
I didn't populate 3 listboxes, I populated 3 columns in one listbox. If you just want name then just add that column. If you want to retrieve all 3 columns but not show them, use the code as I show, but set the columncount of the listbox to 1.
Taking a quick look at your code, I don't see you populating the ListBox.
I presume you aren't there, so what is still needed?
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> Bob, > [quoted text clipped - 163 lines] > >> > >> End With Bob Phillips - 17 Oct 2006 09:18 GMT Greg,
I just knocked up a working example
Private Sub CommandButton1_Click() Dim oNameRng As Word.Range Dim oAgeRng As Word.Range Dim oAddressRng As Word.Range Dim oBM As Bookmarks Dim i As Long
Set oBM = ActiveDocument.Bookmarks Set oNameRng = oBM("Name").Range Set oAgeRng = oBM("Age").Range Set oAddressRng = oBM("Address").Range i = Me.ListBox1.ListIndex oNameRng.Text = Me.ListBox1.Value oBM.Add "Name", oNameRng oAgeRng.Text = Me.ListBox1.List(Me.ListBox1.ListIndex, 1) oBM.Add "Age", oAgeRng oAddressRng.Text = Me.ListBox1.List(Me.ListBox1.ListIndex, 2) oBM.Add "Address", oAddressRng Me.Hide End Sub
Private Sub UserForm_Initialize() Dim xlApp As Object Dim xlWB As Object Dim xlWS As Object Dim cRows As Long Dim i As Long
Set xlApp = CreateObject("Excel.Application") Set xlWB = xlApp.Workbooks.Open( _ "E:\My Documents\Excel Files\WordLinkedSpreadsheet.xls") Set xlWS = xlWB.Worksheets(1) cRows = xlWS.Range("myDatabase").Rows.Count - _ xlWS.Range("myDatabase").Row
With Me.ListBox1 For i = 1 To cRows .AddItem xlWS.Range("myDatabase").Cells(i, 1) .List(.ListCount - 1, 1) = xlWS.Range("myDatabase").Cells(i, 2) .List(.ListCount - 1, 2) = xlWS.Range("myDatabase").Cells(i, 3) Next i End With
Set xlWS = Nothing Set xlWB = Nothing xlApp.Quit Set xlApp = Nothing
End Sub
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> Greg, > [quoted text clipped - 175 lines] > > >> > > >> End With Greg Maxey - 17 Oct 2006 10:52 GMT Bob,
Showing my lack of experience and knowledge here I am sure. I had to revise your initialize code a bit or else I was getting the spreadsheet column heading included in my listbox:
So I was seeing:
Name Joe Bill
Instead of: Joe Bill Bob
Changed to this:
Private Sub UserForm_Initialize() Dim xlApp As Object Dim xlWB As Object Dim xlWS As Object Dim cRows As Long Dim i As Long Set xlApp = CreateObject("Excel.Application") Set xlWB = xlApp.Workbooks.Open( _ "E:\My Documents\Excel Files\WordLinkedSpreadsheet.xls") Set xlWS = xlWB.Worksheets(1) cRows = xlWS.Range("mySSRange").Rows.Count - _ xlWS.Range("mySSRange").Row + 1 ' Added the "+ 1" ************************ With Me.ListBox1 For i = 2 To cRows 'Changed your 1 to a 2 ********************************** .AddItem xlWS.Range("mySSRange").Cells(i, 1) .List(.ListCount - 1, 1) = xlWS.Range("mySSRange").Cells(i, 2) .List(.ListCount - 1, 2) = xlWS.Range("mySSRange").Cells(i, 3) Next i End With Set xlWS = Nothing Set xlWB = Nothing xlApp.Quit Set xlApp = Nothing End Sub
Am I missing something in the setup of the spreadsheet that would normally exclude the heading row?
Another question related to my first method.
If I use this line in the command button click macro:
oNameRng.Text = Me.ListBox1.Value
instead of
oNameRng.Text = 'Me.ListBox1.Text
Then when I select the first item in the Listbox I sometimes get an error "Invalid use of null" It doesn't happen every time and in fact isn't happening now so I can't give you the exact error code. It never happened if I stepped through the code. I used .Text rather than .Value in my code as a result of this oddity. Any possilbe explanation?
Thanks so much for taking the time to assist.
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> Greg, > [quoted text clipped - 234 lines] >> > >> >> > >> End With Greg - 17 Oct 2006 13:12 GMT Bob,
It is Runtime Error 94: Invalid use of Null.
I feel like a dolt. The problem is self inflicted and has nothing to do with the first item in the list. It is caused by not physically selecting an item and occurs in both methods.
Sorry if I confused anyone.
> Bob, > [quoted text clipped - 327 lines] > >> > >> > >> > >> End With Bob Phillips - 17 Oct 2006 13:53 GMT If the range includes the header, then it will be picked up when you iterate through the list to get the values. The solution, as you identified, is to start at row 2, or else re-define the range name to exclude the header.
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> Bob, > [quoted text clipped - 301 lines] > >> > >> > >> > >> End With Greg - 17 Oct 2006 15:04 GMT Bob,
Thanks for clearing that up.
Greg
> If the range includes the header, then it will be picked up when you iterate > through the list to get the values. The solution, as you identified, is to [quoted text clipped - 354 lines] > > >> > >> > > >> > >> End With Greg - 17 Oct 2006 16:08 GMT Bob,
I concede that your direct method works, but am still stuck on something trying to understand how the DAO method works.
If I have mydatabase range defined as:
Name Age Address Bill 25 Ohio Joe 30 New York Mary 35 New Jersey
That is a range spanning A1:C4
and run this code:
Sub test() Dim db As DAO.Database Dim rs As DAO.Recordset Set db = OpenDatabase("C:\myBook1.xls", False, False, "Excel 8.0") Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`") While Not rs.EOF MsgBox rs.Fields(0).Value rs.MoveNext Wend rs.Close db.Close Set rs = Nothing Set db = Nothing End Sub
While Not rs.EOF process returns:
Bill Joe Mary
Unlike the direct method that you have shown me and even with my column header "Name" within the defined range "mydatabase," the While Not rs.EOF seems to skip the first row of the range.
I assume that skipping the first RS in the defined range must have something to do with how this line is constructed:
Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`")
I got this code from the Word MVP FAQ site. http://word.mvps.org/FAQs/InterDev/XLToWordWithDAO.htm
There is no explanation of that line in the article and I can find no explanation in the VBA help file either. Especially related to the "*."
Can you enlighten?
Thanks
> If the range includes the header, then it will be picked up when you iterate > through the list to get the values. The solution, as you identified, is to [quoted text clipped - 354 lines] > > >> > >> > > >> > >> End With Bob Phillips - 17 Oct 2006 16:54 GMT Can't help you there, don't use DAO. ADO, yes, DAO, no.
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> Bob, > [quoted text clipped - 411 lines] > > > >> > >> > > > >> > >> End With Greg - 17 Oct 2006 17:10 GMT Bob,
Thanks just the same. This issue is buried pretty deep in this string (or thread whatever they are called) and I think I will ask about it as a new separate question.
> Can't help you there, don't use DAO. ADO, yes, DAO, no. > [quoted text clipped - 446 lines] > > > > >> > >> > > > > >> > >> End With David F Cox - 17 Oct 2006 19:51 GMT > Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`") rs.movefirst '? I am really rusty, but I vaguelly recall doing this
> While Not rs.EOF > MsgBox rs.Fields(0).Value > rs.MoveNext etc
> Bob, > [quoted text clipped - 432 lines] >> > >> > >> >> > >> > >> End With Greg - 17 Oct 2006 20:19 GMT David,
Thanks for the effort. I tried that as well as rs.moveprevious.
For whatever reason, the code is convinced that "Bill" is the first record in the set ;-(
> > Set rs = db.OpenRecordset("SELECT * FROM `mydatabase`") > [quoted text clipped - 441 lines] > >> > >> > >> > >> > >> > >> End With Bob Phillips - 18 Oct 2006 00:05 GMT Greg,
Just re-read this thread. Name will never be returned as it is being read as the column name, not part of the dataset. If you want the column name, you have to use
rs.Fields(1).Name
etc.
 Signature HTH
Bob Phillips
(replace somewhere in email address with gmail if mailing direct)
> Bob, > [quoted text clipped - 411 lines] > > > >> > >> > > > >> > >> End With Greg Maxey - 18 Oct 2006 00:28 GMT Thanks Bob!
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> Greg, > [quoted text clipped - 450 lines] >> > > >> > >> >> > > >> > >> End With Greg Maxey - 17 Oct 2006 10:21 GMT Bob,
Sorry I only sent you the Command_Button code. I did populate the listbox in the initialize code. I will look over your recent code closer as I am sure it will work better than my method. Thanks again.
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> Greg, > [quoted text clipped - 176 lines] >> >> >> >> End With
|
|
|