Copy the contents of a listbox to the clipboard

jpl458

Well-known member
Local time
Today, 06:14
Joined
Mar 30, 2012
Messages
1,200
For either Pat or Doc, I know you think I'm, obsessing on this but I truly need it.
I found this code at loops through the list box and puts the contents in the clipboard:

Code:
Dim mySym As String
Dim i As Long
Dim strClipText As DataObject
Dim strInputText As String

For i = 0 To DisplayQrylb.ListCount - 1
mySym = mySym & DisplayQrylb.List(i)
mySym = mySym & vbCrLf
Next


Set strClipText = New DataObject
strInputText = mySym

strClipText.SetText strInputText
strClipText.PutInClipboard

When the 3rd line runs I get this

1668722179205.png

Code:
Dim strClipText As DataObject
IS the line that causes the error. Repairing that is outside the envelope of my experience.
 
You need a reference to Microsoft Office X.0 Object Library or a variant with late binding.

Code:
Sub TXTtoCB()
    Const csText = "hallo welt"
    
    ' bei Verweis auf MS Office X.0 Object Library
    'Dim cb As New DataObject
    
    Dim cb As Object        ' Late Binding

    Set cb = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    With cb
        .SetText csText
        .PutInClipboard
    End With
End Sub
 
I guess the code doesn't actually work.

You are assuming that you KNOW the solution and we just don't understand. You just don't know how to code it. But chances are excellent that the clipboard is not the solution at all. You told us in the other thread that you wanted to put the data into a Word Doc and so I sent you a working example that loads a TABLE in several formats, which is essentially what you've got, into a bookmark. In one variation it also formats the data placed into the bookmark using one of the built in Word table formats. Did you bother to examine the example I posted? It shows you how to transfer both single fields and table data so I know it will solve your problem.
View attachment 104707
Yes I did, and will go back and study again. I have then saved in special folder of their own. The problem is OLE, and some of my users have MACs with Office for MAC, and there is no ACCESS for the MAC, but one user has a work around for that. You are right that I don't know how to code it, but I am trying as hard as I can.
 
There is an emulator involved, which we will be testing shortly.
 
If they don't have an emulator that can run Access and connect to your network, or can connect to a Citrix or RDP server to run the Access app in a browser, you need to find a different solution. Access won't work for you.

PS, you might have thought to mention the "Mac" issue at the beginning.
It was a surprise to me too. I was well into it when I found out. I have find if OLE will work with the emulator, native MAC does not support OLE.
 
Pat, trying to understand your Automate Word example. Here is the contents of the folder I have it in:

1668734504395.png

Here is Pats 2:

1668734582872.png

I have Office 365. I was trying Pats2, but when I opened tool and references, I found no mention of Word to reference.
Sorry for asking, but I need some help getting it going. I've been reading the code.

Thanks again.
 
Pat, got the sample working and I understand the flow. Really cool. Will probably have some questions, but let me play with it first.

Thanks again.
 
You're welcome.
Got a question. I am working back from the Word doc to the ACCESS data, so first I want to make sure I understand creating bookmarks. I have a test document that has the following:

1668792791939.png


I followed the instructions for creating bookmarks and when I open the bookmarks tab I get this

1668794512440.png


But, when I use the tool It can't find the bookmarks in my docx.


1668794173736.png

I clear tables first, then capture bookmarks.
The Document is docx

When I run it against your docx, it worked fine. Can't see what I am doing wrong. I notice that you have< >inside the brackets. Is that important?
Doing this a step at a time. First I want to be able to have the tool find bookmarks in a docx that I have. In the same Preview Letter brings up my document with this note "5941-The requested member of the collection does not exist."
Also you get the data from tables, can the data come from queries? I assume that is true.

Thanks
 

Attachments

  • 1668792935061.png
    1668792935061.png
    12.5 KB · Views: 139
  • 1668793102148.png
    1668793102148.png
    11.8 KB · Views: 140
Last edited:
I haven't worked with this in quite a while. If you could send me the document, Either do it here if it is not secret or pm me. I'll try it and step through the code to see why the tool has a problem. If you create a document and use the names in the table the sample is set up for, do you get the same error? can you run the app to fill your document? In theory,the tool should be able to read any document. That was it's point:)

Or, you could try to step through the code to see what line of code is causing the problem.
If you create a document and use the names in the table the sample is set up for, do you get the same error?

I think that line may show me the way. I just put my own names into the Word document bookmarks.


Once again, thanks, Pat.
 
Last edited:
OK I feel better now:) At some point, I may build a version that is closer to what I use for my client apps because this sample is very inflexible even though it does show the technique. Rather than hard-code field names and bookmark names, it uses tables to map them as well as define what queries/tables to use. I have an insurance app that manages thousands of word documents and the users don't need me to do anything for them to add a new document or even for them to define a new line of business with new data fields. Instead of waiting 3-6 months for IT to come up with modifications, they now use my app and can enter the data to set up a new LOB in a few hours and then as long as it takes to create the word documents that will be used.
I had to spend the AM fixing little, not bugs, productizing issues, while watching football(I'm retired, I'm allowed to do that). I am preparing a document to PM to you that has the guts of what's needed per bookmarks. This is my first time trying this, and I have divorce myself from my preconceived notions about how things Should work.

I have data in tables and I want to have some of that data end up in the proper place in any one of a few different letters. Should be very simple, but I have to mentally sort out the steps in that process. (Learned a log time ago to think before you code ,and in this case before you ask questions). Your explanation above made me feel better as well. I will send you a note when I have everything together.

I can't thank you enough.
 
If you have multiple documents and you don't want to make hard-coding the document filling code your life's work, then you absolutely need to tablize the data to handle the filling.

I have two different methods I use in applications. One is very complicated and gives the user the ability to actually define new data fields. This is still within limits though. the application is used to fill the documents used to create an insurance policy. The company was a startup and was rapidly expanding the types of policies they would write. Policies had common data and they had unique data. It was the unique data fields that the users could define. This data was stored in an ultra-normalized table that stored each data field as a separate row. So the table had the following fields:
RecID (autonumber, PK)
PolicyID (FK to tblPolicies)
FieldID (FK to tblFields)
TextValue

The tblFields contains the definition for a field as well as its name. To provide flexibility, ALL data is entered as text. The tblFields species the data type and even provides a query name if the data should displayed as a combo.

Then there's other tables to connect fields to policyTypes and documents.

The simpler method provides a fixed set of data so if you need to change the data that is used to fill the forms, you need to modify the program since the tables are standard rather than Name/value lists like the complex example.

I've posted pictures of the complex solution multiple times. But here is a picture of the form where you define a new Document and then map fields to bookmarks. For the sake of sanity, I use the fieldname as the bookmark name but sometimes, you need to use the same field in a document multiple times. Notice that AmnestyEndDate is used three times and so has three bookmarks. Bookmark names in a document MUST be unique so I use a numeric suffix.

Since many documents have a similar set of fields, there is a copy option. For this process, you create the new doc header and then use the combo to pick the "from" document. You can obviously do this the other way if you prefer. But I think this ends up being more flexible if you want to merge documents. You can copy the bookmarks from multiple documents. Due to the indexes, only one instance of the book mark will be added. Duplicates will be discarded.

Since this is a small project and all the data can be selected by a single query, there isn't an option to pick a query to associate with the document but you could do that. Some of these documents use those little tables you see in the example. Since there were only three of them and there was little chance of having to make more due to the type of data, I went the hardcode route. If the FieldName is one of the "special" ones, the app opens a query to select the dependent data to build the table and then insert it into the document. As you can see by the example, this process is separate from the main line of filling the form fields.
View attachment 104739

This application, since it was intended to create letters to employees offered the option of a language preference. All the user needed to do was to create whatever versions of the document he wanted and use "_English", "_Spanish", whatever as the suffix. You could of course just create duplicate documents with hard coded language in the names but this seemed cleaner.
Sent you a PM, but it seems that I can't attach the Word doc in the PM. If there is a way to do that let me know. I created a table that looks like your, except the right and left side are switched.
 
Last edited:
Just reread your note (several times, slowly), and I believe you are saying just put the data into a table with one item per line? My instincts tell me that greatly simplifies things, if I am correct.
 
Just reread your note (several times, slowly), and I believe you are saying just put the data into a table with one item per line? My instincts tell me that greatly simplifies things, if I am correct.
since all the dat is different each time it's used, would an array work as well, or would you just delete the table after it is used. Also, if you use tables, how do you create a table with one entry per line with Make Table query? Trying that now.
 
Forget the first part where I described the complex solution that allows users to define new fields. You don't need that. Read the second part where I described the simple solution.

Depending on whether you are printing one document at a time or multiple copies of the same document, you would open a recordset created from a query that either selects ONE record or many records. Then you would loop through the recordset. For each record, you would use GoSub to fill the field. The following code may be more complicated than you need. In my behind the scenes field definition table (which is used as the RowSource for the combo in the form I pasted above), it has a type code that says what type of data you have. I used a combination of bookmarks, formfields, and checkboxes and each is filled differently. The formfield and checkbox controls are the "old" style so I'm not sure the code works with the "new" style. I never checked it. You can try it and let me know. Anyway. It loops through the fields collection of the recordset so make sure you only include fields you want to use.

I think you can format dates and phone numbers in the query and not need to do it in the case below so you can get rid of most of the case.

I extracted this code from a very complicated procedure. I think this is all you need.
Code:
    Dim db              As DAO.Database
    Dim rsFields        As DAO.Recordset
    Dim qdData          As DAO.QueryDef

    Set db = CurrentDb()
    Set qdFields = db.QueryDefs!qFetchFieldNames
        qdFields.Parameters![EnterDataSourceName] = "tblMembers"
        qdFields.Parameters![EnterDocID] = DocumentID
    Set rsFields = qdFields.OpenRecordset(dbOpenDynaset, dbSeeChanges)
''''' You may need a loop here if your query selects more than one record for printing.
    GoSub FillFields

ExitSub:
    Exit Sub

FillFields:
    Do While rsFields.EOF = False
        Select Case rsFields!FieldType
            Case "Memo"
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                Else
                    WordDoc.Bookmarks(rsFields!BookMarkName).Range.Fields(1).Result.Text = rsData.Fields(rsFields!FieldDescription)
                End If
            Case "Ckbox"
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).CheckBox.Value = rsData.Fields(rsFields!FieldDescription)
                End If
            Case "Date"
                If IsDate(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = Format(rsData.Fields(rsFields!FieldDescription), "mmmm dd, yyyy")
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                End If
            Case "Phone"
                If IsNumeric(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = Format(rsData.Fields(rsFields!FieldDescription), "\(###\) 000\-0000")
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                End If
            Case Else
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = rsData.Fields(rsFields!FieldDescription)
                End If
        End Select
    rsFields.MoveNext
    Loop
Return
I will have to puzzle on this for a while. A lot for me to chew on. From reading the code it seems I have to deletes some case and add for name, address, etc.

I will chew, then probably get back with a question or +.

Thanks again
 
I was going to get some other things done first, but I couldn't wait.

1669050916494.png


Worked like a champ. You brows to a directory and get all the bookmarks in all the docs in that directory. Just wondering if there would ever be a need to point at a single document to get it's bookmarks. Just an idle thought. What I did was move my test doc to new folder then pointed the tool at it and pulled the trigger, and out popped the above.

Very cool, indeed

Thanks, yet again
 
Forget the first part where I described the complex solution that allows users to define new fields. You don't need that. Read the second part where I described the simple solution.

Depending on whether you are printing one document at a time or multiple copies of the same document, you would open a recordset created from a query that either selects ONE record or many records. Then you would loop through the recordset. For each record, you would use GoSub to fill the field. The following code may be more complicated than you need. In my behind the scenes field definition table (which is used as the RowSource for the combo in the form I pasted above), it has a type code that says what type of data you have. I used a combination of bookmarks, formfields, and checkboxes and each is filled differently. The formfield and checkbox controls are the "old" style so I'm not sure the code works with the "new" style. I never checked it. You can try it and let me know. Anyway. It loops through the fields collection of the recordset so make sure you only include fields you want to use.

I think you can format dates and phone numbers in the query and not need to do it in the case below so you can get rid of most of the case.

I extracted this code from a very complicated procedure. I think this is all you need.
Code:
    Dim db              As DAO.Database
    Dim rsFields        As DAO.Recordset
    Dim qdData          As DAO.QueryDef

    Set db = CurrentDb()
    Set qdFields = db.QueryDefs!qFetchFieldNames
        qdFields.Parameters![EnterDataSourceName] = "tblMembers"
        qdFields.Parameters![EnterDocID] = DocumentID
    Set rsFields = qdFields.OpenRecordset(dbOpenDynaset, dbSeeChanges)
''''' You may need a loop here if your query selects more than one record for printing.
    GoSub FillFields

ExitSub:
    Exit Sub

FillFields:
    Do While rsFields.EOF = False
        Select Case rsFields!FieldType
            Case "Memo"
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                Else
                    WordDoc.Bookmarks(rsFields!BookMarkName).Range.Fields(1).Result.Text = rsData.Fields(rsFields!FieldDescription)
                End If
            Case "Ckbox"
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).CheckBox.Value = rsData.Fields(rsFields!FieldDescription)
                End If
            Case "Date"
                If IsDate(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = Format(rsData.Fields(rsFields!FieldDescription), "mmmm dd, yyyy")
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                End If
            Case "Phone"
                If IsNumeric(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = Format(rsData.Fields(rsFields!FieldDescription), "\(###\) 000\-0000")
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                End If
            Case Else
                If IsNull(rsData.Fields(rsFields!FieldDescription)) Then
                    WordDoc.FormFields(rsFields!BookMarkName).Result = ""
                Else
                    WordDoc.FormFields(rsFields!BookMarkName).Result = rsData.Fields(rsFields!FieldDescription)
                End If
        End Select
    rsFields.MoveNext
    Loop
Return
Working on code you sent, and will ask one question at a time, trying not to waste your time. Stepping through code slowly.

In this section of the code I have entered names where you say to enter names:

Code:
 Set db = CurrentDb()
    Set qdFields = db.QueryDefs!qFetchFieldNames
        qdFields.Parameters![QryGetDLData] = "tblMembers"
        qdFields.Parameters![Templete1.docx] = DocumentID
    Set rsFields = qdFields.OpenRecordset(dbOpenDynaset, dbSeeChanges)

When it gets to Set qdFields command I get this error

1669065668591.png


Was I correct in adding what I did? Doing a lot of reading re VBA Set and Parameters. But, for me, it's still like looking into a barrel of eels.
In VBA does Set a reference to an object mean get the objects address? (I still think in assembler)
 
Last edited:
do you have a query named qFetchFieldNames?
I am trying to figure out how to create a query that only returns the column names. I think that is what I need. I understand all the code except the setup.

Code:
 Set db = CurrentDb()
    Set qdFields = db.QueryDefs!qFetchFieldNames
        qdFields.Parameters![Suspects] = "tblMembers"
        qdFields.Parameters![TemplateTest] = DocumentID
    Set rsFields = qdFields.OpenRecordset(dbOpenDynaset, dbSeeChanges)
''''' You may need a loop here if your query selects more than one record for printing.
    GoSub FillFields

Suspects is a table with names and addresses, etc. TemplateTest is a docx in Word. I've tried to find what the .Parameters does, but it's vague on the web. I am in unexplored territory here, but trying to find my way through.

Thanks
 
One step at a time. Make the procedure work for a query that selects a single record. Once that works, add the loop. This would have gone a lot easier if you had just used the sample and hardcoded the fields to make your document work since you are a long way from understanding the process. I do not have a working sample I can post so you are getting this piecemeal and essentially I am working privately for you to make this work which was not my intention. I was trying to show you how OLE automation works and tell you how to proceed from there if you had more than the most basic of requirements.

The query here is the one that pulls the list of bookmarks for a specific document. The two tables in the query are the list of all the defined fields and the bookmarks mapped to a specific document. The Parameters provide the criteria. [EnterDocID] is the parameter that specifies which DocID we want from the bookmarks table and [EnterDataSource] is the parameter that specifies which fields we want from the fields table. The two tables are joined on FieldID. this is a partially complete sample so it isn't quite how the next sample database will work but for now it will be OK. The "tblMembers" is hardcoded in the sample code. Replace this with the name of the table or query that will pull the data you want. I think it actually isn't used. I think the recordsource is also created from a hardcoded query. You should see that later in the FillFields GoSub.

You can take a short cut for now and add the FieldName, FieldDescription, and FieldType to tblBookmarks. This will duplicate the data but it simplifies the process until I can build the whole thing in a coherent sample. There is a case statement in some code I posted that shows what the FieldType is used for (formatting the field for Excel). You may even be able to avoid that if you format the field in your query. The problem arises with fields like phone numbers. They are ( or should be) stored as 10 digit strings in the table. but you want them displayed as (xxx) xxx-xxxxx and you do that on forms/reports with a mask. That doesn't apply here so you actually need to format the field to export it to Word or Excel.

As you follow the code in the FillFields you'll see that this is the query that controls the filling because it has the field names.
View attachment 104808
Pat, let me play with this on my own for a while. I've taken too much of your time, and I really appreciate it. I have learned a lot, or, at least something. Let me see if I can get something going on my own, but this last post cleared up things a lot.
One step at a time. Make the procedure work for a query that selects a single record. Once that works, add the loop. This would have gone a lot easier if you had just used the sample and hardcoded the fields to make your document work since you are a long way from understanding the process. I do not have a working sample I can post so you are getting this piecemeal and essentially I am working privately for you to make this work which was not my intention. I was trying to show you how OLE automation works and tell you how to proceed from there if you had more than the most basic of requirements.

The query here is the one that pulls the list of bookmarks for a specific document. The two tables in the query are the list of all the defined fields and the bookmarks mapped to a specific document. The Parameters provide the criteria. [EnterDocID] is the parameter that specifies which DocID we want from the bookmarks table and [EnterDataSource] is the parameter that specifies which fields we want from the fields table. The two tables are joined on FieldID. this is a partially complete sample so it isn't quite how the next sample database will work but for now it will be OK. The "tblMembers" is hardcoded in the sample code. Replace this with the name of the table or query that will pull the data you want. I think it actually isn't used. I think the recordsource is also created from a hardcoded query. You should see that later in the FillFields GoSub.

You can take a short cut for now and add the FieldName, FieldDescription, and FieldType to tblBookmarks. This will duplicate the data but it simplifies the process until I can build the whole thing in a coherent sample. There is a case statement in some code I posted that shows what the FieldType is used for (formatting the field for Excel). You may even be able to avoid that if you format the field in your query. The problem arises with fields like phone numbers. They are ( or should be) stored as 10 digit strings in the table. but you want them displayed as (xxx) xxx-xxxxx and you do that on forms/reports with a mask. That doesn't apply here so you actually need to format the field to export it to Word or Excel.

As you follow the code in the FillFields you'll see that this is the query that controls the filling because it has the field names.
View attachment 104808
Let me try and work things out, based on this last post. I've taken too much of your time already. Thanks again for all your help, I really appreciate it.
 

Users who are viewing this thread

Back
Top Bottom