(Currently using Access 2003) Within my project I have a subform, frmSub, that holds the results of a query, located within a form (frmMain).
frmSub is a subform control which contains a query instead of a form (its SourceObject property is set to "Query.qrySearch")
Using various run time counters, the query orders the results with the 'best' at top. The user can then manually select down which ever results they require, or take all the results.
What I'd like to do is provide a way to open the results in Excel (either the user selection or all the results if no selection is made). Ignoring the likely more frequently used 'create temp export .xls file' method for the now, I'm currently looking at a copy/paste method, mimiking the ctl-C/V way the user currently uses.
I have placed an ‘Open in Excel’ button in frmMain.
In the frmSub's Exit event I look at .SelHeight, returning >0 if a selection is made…
If Me.frmSub.Form.SelHeight > 0 Then
DoCmd.RunCommand acCmdCopy
Else:
DoCmd.RunCommand acCmdSelectAllRecords
DoCmd.RunCommand acCmdCopy
End If
Behind the ‘Open in Excel’ button on frmMain I have…
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
With xlApp
.Workbooks.Add
.ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
.Cells.Select
.Cells.EntireColumn.AutoFit
.Visible = True
.Range("a1").Select
End With
Set xlApp = Nothing
Call EmptyClipboard
Call EmptyClipboard calls an api based routine that clears the clipboard.
While I realise that using the clipboard this way is likely not best practice, I’m not sure if that thought is universal if a reasonable use could be identified (It’s not expected that the user would be particularly disadvantaged here)
Problem
While the above works well there are issues with using the Exit event since it fires not only on clicking the ‘Exit to Excel’ button – and an Export to Excel, here, causes issues if the clipboard is empty.
Is there a way to determine if it was the ‘Exit to Excel’ button that initiated the sub form’s Exit event – and trap this in that the Exit event’s code? The only events I seem to have access to in frmSub is On Exit and On Enter.
If any copy/paste method would likely remain problematic then I could look at exporting to a tmp .xls file.
With some more time to work on this I’ve rearranged things, I think, for the better. In particular, the Exit event is now only used to store the datasheet’s selection parameters, thus shifting the Copy stage into the ‘Export to Excel’ button…
frmSub Exit event includes…
tmpSelHeight = Me.frmSub.Form.SelHeight
tmpSelTop = Me.frmSub.Form.SelTop
tmpSelLeft = Me.frmSub.Form.SelLeft
tmpSelWidth = Me.frmSub.Form.SelWidth
Behind the ‘Open in Excel’ button on frmMain there is now included…
If IsProcessRunning("excel.exe") Then
If MsgBox("Excel is currently running: click Yes to view in new Excel instance", vbYesNo, "") = vbNo Then Exit Sub
End If
If tmpSelHeight > 0 Then
Form! frmSub.SetFocus
Me. frmSub.Form.SelHeight = tmpSelHeight
Me. frmSub.Form.SelTop = tmpSelTop
Me. frmSub.Form.SelLeft = tmpSelLeft
Me. frmSub.Form.SelWidth = tmpSelWidth
DoCmd.RunCommand acCmdCopy
Else
Form! frmSub.SetFocus
DoCmd.RunCommand acCmdSelectAllRecords
DoCmd.RunCommand acCmdCopy
End If
Me. frmSub.Form.SelHeight = 0
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
With xlApp
.Visible = True
.Workbooks.Add
.ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
.Cells.Select
.Cells.EntireColumn.AutoFit
.Range("a1").Select
End With
Set xlApp = Nothing
Call EmptyClipboard
AppActivate "Microsoft Excel"
While things appear stable enough…
I’m still manipulating the clipboard though this is not expected to be an issue.
I could later look at using any existing Excel instance.
I could still consider exporting to a .xls file, or store in temp table & linking table to Excel, as alternative methods.
Related
I currently have a Microsoft Access Database (file format is 2007-2016) that we use to track open orders and print all the required documents. I have created a word document that pulls information from this database using MailMerge. This document works flawlessly by itself. Meaning that if I actually double click the document it opens correctly asking me if I want to pull the information from the database. The issue is that if I open it via a command button in the database I the document opens but I will not get the MailMerge dialog asking if I want to pull the information.
Here is the code I am using at the moment to open the document.
Private Sub Print_Click()
If IsNull(Me.DateShipped.Value) Then
Me.DateShipped = Date
End If
DoCmd.RunCommand acCmdSaveRecord
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Open("F:\Database\merge\INDIVIDUAL.docx")
Set wrdApp = Nothing
Set wrdDoc = Nothing
DoCmd.RunCommand acCmdSaveRecord
Any help will be appreciated.
Thank you
Joel
I am using Microsoft Access 2013 to create a database where I have a form that the default view is read-only to prevent accidental editing. I am currently trying to include a button to enable editing for the current record only. I tried using DoCmd.OpenForm to open the record in editable mode (since I am using that command elsewhere to open specific records), but it seems like it can not open a record within the same form with that command.
I thank you in advance for any advice on how to solve this issue.
You cannot edit anything else than the current record.
Use this code line:
Me.AllowEditions = True
But it doesn't make much sense as you could just open the form this way.
I learned this from the first VBA book I ever read (Access 97 VBA for Dummies, I think), and I have never seen anyone use the Tag property since, which has no other purpose than for you to find something to use it for. Enter "Lockable" in the tag property for any control (text box, combobox etc.) that you want to protect. Add a button named btnEdit to your form.
When you enter a record, the Form Current event will unlock the controls if it is a new record, and lock the controls if it is an existing record.
The button will then unlock to allow edits, and re-lock once the record is exited. I've found this to be very effective in preventing inadvertent edits.
Private Sub Form_Current()
Dim ctlCurr As Control
'Lock the record if it is not new. Prevents inadvertent edits.
If Me.NewRecord = False Then
For Each ctlCurr In Me.Controls
If ctlCurr.Tag = "Lockable" Then
ctlCurr.Locked = True
End If
btnEdit.Enabled = True
Next
End If
'Unlock a new record for editing.
If Me.NewRecord = True Then
For Each ctlCurr In Me.Controls
If ctlCurr.Tag = "Lockable" Then
ctlCurr.Locked = False
End If
Next
btnEdit.Enabled = False
End If
End Sub
Private Sub btnEdit_Click()
Dim ctlCurr As Control
'Unlocks a record for editing. Requires the operator to make the decision to edit.
If Me.NewRecord = False Then
For Each ctlCurr In Me.Controls
If ctlCurr.Tag = "Lockable" Then
ctlCurr.Locked = False
End If
Next
End If
End Sub
I'm writing contents of tables from access to excel(Opening the excel file from access) After writing it i'm trying to save all workbooks in the appXL application. For that i'm making DispalyAlerts false before saving and trun on back after saving. After writing contents to excel i'm closing the access. After writing ,when i'm trying to close the excel, it is not giving any alerts like Do you want to save the contents?
My vba code
Sub Writexl()
Dim appXL As Excel.Application
Dim wb As Excel.Workbook
StrwbPath="C:\temp\sample.xls"
Set appXL = CreateObject("Excel.Application")
With appXL
Set wb = .Workbooks.Open(StrwbPath)
.Visible = True
End With
'here code for writing contents
'save workbook after writing
appXL.Application.DisplayAlerts = False
For Each w In appXL.Application.Workbooks
w.Save
Next w
appXL.Application.DisplayAlerts = True
DoCmd.Quit acQuitSaveAll
Application.Quit
End sub
You are setting the DisplayAlerts to the Application's Applicaiton
appXL.Application.DisplayAlerts = True
is conceptually equivalent to
Excel.Application.Application.DisplayAlerts = True
So the property is being set on the parent application to Excel.
Try
appXL.DisplayAlerts = True
After writing ,when i'm trying to close the excel, it is not giving
any alerts like Do you want to save the contents?
As #David Zemens says, why would it display a message to save all changes when you've already saved everything. Have you tried changing a cell and then exiting Excel?
EDIT: Changed as I have a different issue with the same code
2nd Edit: Adding additional code that seems to be casuing the issue
I have created a vba program in access that aggregates data from a number of external sources and write the results into a new table. Ideally when I run the program I want to wipe out all of the data that is currently in the table and replace it with my new data. I am currently currently deleting all of the data in the table... then writing my new data
Here is the code for reference
Function getTestFixtures(FixtureName As String) As Recordset
Dim db As Database
Set db = OpenDatabase(GetDBPath & "TestFixtures.xlsx", False, False, "Excel 12.0;HDR=Yes;")
If db Is Nothing Then
MsgBox "Can't find the file!", vbExclamation, ThisWorkbook.Name
Exit Function
End If
Set getTestFixtures = db.OpenRecordset("Select * from [" & FixtureName & "$]")
End Function
The recordset created above is modified and the output data is placed in a dictionary and passed to this function.
Sub Write_OTDC_Data(POlist As Dictionary)
Dim Rst As Recordset
DoCmd.SetWarnings False
DoCmd.runsql "Delete * from [OTDC Results]"
DoCmd.SetWarnings True
Set Rst = CurrentDb.OpenRecordset("OTDC Results")
With Rst
For Each key In POlist.Keys
.AddNew
For i = 0 To 9
.Fields(i).value = POlist(key)(i)
Next
.Update
Next
.Close
End With
End Sub
My Problem is that I get the following error if I try to change anything after running both of the above procuedures.
Running either in isolation does not generate the error.
I'm unsure whether this question is still unresolved. In case it's not, I have some suggestions for you to try, but not a lot of confidence they will cure the problem.
Try DoCmd.TransferSpreadsheet to import the sheet's data into a scratch table instead of using OpenDatabase with the workbook.
In your MsgBox, I wonder whether ThisWorkbook.Name means anything to an Access application. Aside from that, I would check whether the workbook exists, then open it (or import the sheet from it) only if the file is found.
If Len(Dir(GetDBPath & "TestFixtures.xlsx")) = 0 Then
'not found
Else
'use it
End If
Actually I'm unclear why you don't get an error from OpenDatabase if the workbook file doesn't exist. And that makes me suspicious of DoCmd.SetWarnings False Never, ever turn SetWarnings off. Doing so suppresses important information. And it is completely unnecessary. Set a DAO.Database object variable to CurrentDB(), then use this instead:
dbObjectVariable.Execute "Delete from [OTDC Results]", dbFailOnError
Add an error handler to deal with any problems dbFailOnError exposes.
Finally, this bears repeating because it's so important. NEVER turn SetWarnings off.
I am really new to programming access. I converted an old 97 access db to access 2007 and it has been working fine for awhile. Today I go into it and was snooping around in design view and looking at the code. I didn't change anything. Just looked. When I went to run the code I kept getting the "Not a valid bookmark" error. Just to be sure I opened up the old program I converted and all the code is the same the line that is giving me the problem is the
Me.Bookmark = pos
The following is the whole routine.
Thanks in advance.
Private Sub ProductID_AfterUpdate()
Dim pos As Variant
Me![UnitPrice] = Me![ProductID].Column(2)
Me![ProductName] = Me![ProductID].Column(1)
Me![GLAcct] = Me![ProductID].Column(3)
DoCmd.DoMenuItem acFormBar, acRecordsMenu, acSaveRecord, , acMenuVer70
pos = Me.Bookmark
Me.Requery
Me.Bookmark = pos
End Sub
Edit: I already tried compact and repair.
You will need to change this code as it is out of date for quite some time. I am not sure why it worked in the first place, because the bookmarks will have changed after updating, saving and requerying. I have commented the requery line, because it does not seem to serve a useful purpose, if you wish to update the combo, requery that. If you wish to find a record after an action, save the unique ID to a variable and find it. DoMenuItem is deprecated, you can use RunCommand instead, in this case, however, Me.Dirty=false will save.
Private Sub ProductID_AfterUpdate()
Dim pos As Variant
Me![UnitPrice] = Me![ProductID].Column(2)
Me![ProductName] = Me![ProductID].Column(1)
Me![GLAcct] = Me![ProductID].Column(3)
Me.Dirty=False
'pos = Me.Bookmark
'Me.Requery
'Me.Bookmark = pos
End Sub
To requery a form and return to the same record, do this:
Dim lngPKValue As Long
With Me.RecordsetClone
lngPKValue = Me!ID
' Me.Dirty = False is unnecessary, as the Requery saves the data
Me.Requery
.FindFirst "[ID]=" & lngPKValue
If Not .NoMatch Then
Me.Bookmark = .Bookmark
End If
End With
Now, where you put this code depents. I don't quite see in the original code why there's a need to requery, as the updates have been done to the record you're already on, so you're not really accomplishing anything by requerying and returning to the record you started on. But there are circumstances in which you'd want to do that (e.g., in an ordered recordset where you've edited values that will change the place of this particular record in the sorted result), and the above is the way to do it.
If it's necessary, you'd probably want to turn off painting of the form (Me.Painting = False, the Me.Painting = True once you've set the bookmark) or of the application (Application.Echo = False/True) so the screen doesn't flicker and you don't see the requerying and navigating. But be sure you add an error handler, since if an error happens while screen painting is turned off, your user may end up stuck and unable to continue.