I am using Access to create a dynamic report and I would like that on close event the report to be deleted.
Right now, I am creating the report like this:
Set rpt = CreateReport
With rpt
.Visible = True
.Caption = "Calendar View"
.BorderStyle = 1
.AutoCenter = True
.ScrollBars = 0
.Printer.Orientation = acPRORLandscape
.Modal = True
.PopUp = True
.OnClose = "[Event Procedure]"
End With
'extra stuff for report
strName = rpt.Name
DoCmd.Close acReport, strName, acSaveYes
DoCmd.Rename "rptNewName", acReport, strName
DoCmd.OpenReport "rptNewName", acViewPreview, , , acWindowNormal
DoCmd.DeleteObject acReport, "rptNewName"
But, the DeleteObject will throw a error, because the report is still open..
How can I delete the report on close event?
Thank you!
Place the following, just before you line DoCmd.DeleteObject...
Do While Application.CurrentProject.AllReports(sRptName).IsLoaded
DoEvents
Loop
Related
How do you assign a name to a MS Access report created via CreateReport?
Code creates a dynamic report then adds controls to the report. Last, I want to name/save the report as "Student_Scores_Report01" but it appears that CreateReport auto-generates the name for the report as Report1, Report2, etc. I've run into issues where Access creates a "Report1" but it doesn't actually exist, causing the whole project to be corrupted. This is my best guess at working around this but it seems inefficient:
Dim rpt as Report
Set rpt = CreateReport
Dim ReptNmTemp as String
ReptNmTemp = rpt.name
DoCmd.Save acReport, rpt.Name
DoCmd.Close acReport, rpt.Name
DoCmd.Rename "Student_Scores_Report01", acReport, ReptNmTemp
For Each rpt02 In CurrentProject.AllReports
If rpt02.Name = ReptNmTemp Then
DoCmd.DeleteObject acReport, ReptNmTemp
End If
Next
The For...each loop deletes the auto-generated report and avoids the corruption problem. But is there a better way? Thanks in advance.
Instead of looping you could On Error Resume Next or some other error handler.
Dim rpt as Report
Dim ReptNmTemp as String
Set rpt = CreateReport
ReptNmTemp = rpt.name
DoCmd.Save acReport, ReptNmTemp
DoCmd.Close acReport, ReptNmTemp, acSaveYes
DoCmd.Rename "Student_Scores_Report01", acReport, ReptNmTemp
On Error Resume Next
DoCmd.DeleteObject acReport, ReptNmTemp
Or use acDefault, which is actually a default parameter for both Save and Close, which means if parameter is not provided, acDefault will be used.
Dim rpt as Report
Set rpt = CreateReport
DoCmd.Save , "Student_Scores_Report01"
DoCmd.Close , , acSaveYes
When a user has logged in i would like it so that their user name is displayed in a Label in the main menu. here is my code.this at the minute allows the login form to check details entered and compares them to the employees table to allow access to the Home form.
Option Compare Database
Option Explicit
Private Sub ButtonLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.TxtUsername & "'"
If rs.NoMatch Then
Me.LblWronguser.Visible = True
Me.TxtUsername.SetFocus
Exit Sub
End If
Me.LblWronguser.Visible = False
If rs!Password <> Nz(Me.Txtpassword, "") Then
Me.LblWrongpass.Visible = True
Me.Txtpassword.SetFocus
Exit Sub
End If
Me.LblWrongpass.Visible = False
TempVars("EmployeeType") = rs!EmployeeType_ID.Value
DoCmd.OpenForm "Home"
DoCmd.Close acForm, Me.Name
End Sub
after this stage i am stuck as to what the code for the "home" form to display the user that has just logged in (label) this would be the Unbound field seen.
Assuming table structure is similar to below and the label is actually textbox you can use a Dlookup function.
For this scenario, I am going to assume your textbox is called Welcome. You'll probably need to use something like this:
Set rs = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.TxtUsername & "'"
If rs.NoMatch Then
Me.LblWronguser.Visible = True
Me.TxtUsername.SetFocus
Exit Sub
Else
Me.Welcome = rs!UserName
End If
Me.LblWronguser.Visible = False
If rs!Password <> Nz(Me.Txtpassword, "") Then
Me.LblWrongpass.Visible = True
Me.Txtpassword.SetFocus
Exit Sub
End If
Me.LblWrongpass.Visible = False
TempVars("EmployeeType") = rs!EmployeeType_ID.Value
DoCmd.OpenForm "Home"
DoCmd.Close acForm, Me.Name
Note, this would only apply the username to the Welcome textbox. If a name was required, you would need to reference such a column differently, such as Me.Welcome = rs!FirstName or something. Also, since there is a password verification, you probably want to restructure things so that the name would only populate after the password portion has been passed properly.
I have a report that displays another form's recordsource. When I add some record on this form and click for report, this records is not being displayed. How can I achieve displaying what is on screen - allways ? Here is my simple code for report:
Private Sub cmdOpenReport_Click()
DoCmd.OpenReport "MyReport", acViewReport
End Sub
Private Sub Report_Open(Cancel As Integer)
Me.RecordSource = Forms![MyForm].Form.RecordSource
End Sub
You need to close the Report before re-opening it and save the new record.
In the click event of your Open Report button insert the following:
Private Sub OpenReport_Click()
DoCmd.RunCommand acCmdSaveRecord
DoCmd.Close acReport, "Test1", acSaveYes
DoCmd.OpenReport "Test1", acViewPreview
End Sub
Try requerying your Forms Recordset before opening the report:
Private Sub cmdOpenReport_Click()
Me.FilterOn = False
Me.Requery
DoCmd.OpenReport "MyReport", acViewReport
End Sub
I have an answer, I knew It's not so easy (in click event of OpenReport button):
Dim strWhere As String
Me.Dirty = False
With Me.Recordset.Clone
Do Until .EOF
strWhere = strWhere & "," & !ID
.MoveNext
Loop
End With
strWhere = Mid(strWhere, 2)
DoCmd.OpenReport "MyReport", acViewReport, WhereCondition:="ID In (" & strWhere & ")
Answer provided by Leigh Purvis (Access MVP), a BIG thanks once more !!
I am experiencing a problem with vb in access. There is main form (say it parentForm), which has two buttons that trigger two different forms (say it childForm1 and childForm2). Both child forms perform checks on their Load events. If a condition fails, the childForm has to close. The problem is that in childForm1, the code works properly, in the childForm2 something goes completely wrong.
It seems that the close event is totally ignored. After the onLoad event, the process is carried out to the onCurrent event, which shouldn't happen! Below is the code of the onLoad event of childForm2.
Private Sub Form_Load()
On Error Resume Next
Dim db As Database
Dim rst As Recordset
Dim stDocName As String
stDocName = "childForm2"
closeEvent = False
Set db = CurrentDb
If a<> 0 And b<> 0 Then
Set rst = db.OpenRecordset("SELECT * FROM tbl1 WHERE Cust Like '*" & a & "*' AND Cust2 Like '*" & b & "*';")
If (rst.EOF Or rst.BOF) And IsLoaded(stDocName) Then
MsgBox ("No record found!")
rst.Close
SetWarnings = True
closeEvent = True
Me.SetFocus
DoCmd.Close acForm, stDocName, acSaveNo
End If
ElseIf a = 0 And b <> 0 Then
Set rst = db.OpenRecordset("SELECT * FROM tbl1 WHERE Cust2 Like '*" & b & "*';")
If (rst.EOF Or rst.BOF) Then
MsgBox ("No record found!")
rst.Close
DoCmd.Close acForm, stDocName
End If
End If
db.Close
End Sub
Also, I tried to use a global boolean variable (closeEvent in code), which is initialized to False and gets True, when the form must close. This variable is checked in the onCurrent event in order to close the form. However, when i debugged the code, the variable seems to lose its (True) value when passing from onLoad to OnCurrent event!
Any suggestion is more than appreciated.
Thanks in advance,
Maria
Use the Form_Open event instead of the Form_Loadevent.
Then, instead of closing the form (=Docmd.Close) use the built in Cancel argument to cancel the form's opening.
Private Sub Form_Open(Cancel As Integer)
If **condition not met** then
Cancel = True 'this stops the form from opening
End If
End Sub
When my database is opened, it shows a form with a "loading bar" that reports the progress of linking external tables and such, before showing a "Main Menu" form. The Main Menu has code that generates a form programmatically behind the scenes with buttons on it, and when that's done it saves and renames the form, and assigns it as the SourceObject to a subform.
This all works fine and dandy, that is, until I decide to make the buttons actually do something useful. In the loop that generates the buttons, it adds VBA code to the subform-to-be's module. For some reason, doing that makes VBA finish execution, then stop. This makes the (modal) loading form not disappear as there's an If statement that executes a DoCmd.Close to close the loading form when it's done loading. It also breaks functionality that depends on a global variable being set, since the global is cleared when execution halts.
Is there a better way to go about creating buttons that do stuff programmatically, short of ditching Access outright and writing real code? As much as I would love to, I'm forced to do it in Access in case I leave the company so the less tech-savvy employees can still work with it in my absence.
Below are bits and pieces of relevant code, if needed.
Form_USysSplash:
'Code that runs when the form is opened, before any processing.
Private Sub Form_Open(Cancel As Integer)
'Don't mess with things you shouldn't be.
If g_database_loaded Then
MsgBox "Please don't try to run the Splash form directly.", vbOKOnly, "No Touching"
Cancel = True
Exit Sub
End If
'Check if the user has the MySQL 5.1 ODBC driver installed.
Call CheckMysqlODBC 'Uses elfin majykks to find if Connector/ODBC is installed, puts the result into g_mysql_installed
If Not g_mysql_installed Then
Cancel = True
DoCmd.OpenForm "Main"
Exit Sub
End If
End Sub
'Code that runs when the form is ready to render.
Private Sub Form_Current()
'Prepare the form
boxProgressBar.width = 0
lblLoading.caption = ""
'Render the form
DoCmd.SelectObject acForm, Me.name
Me.Repaint
DoEvents
'Start the work
LinkOMTables
UpdateStatus "Done!"
DoCmd.OpenForm "Home"
f_done = True
End Sub
Private Sub Form_Timer() 'Timer property set to 100
If f_done Then DoCmd.Close acForm, Me.name
End Sub
Form_Home:
'Code run before the form is displayed.
Private Sub Form_Load()
'Check if the user has the MySQL 5.1 ODBC driver installed.
'Header contains an error message and a download link
If Not g_mysql_installed Then
FormHeader.Visible = True
Detail.Visible = False
Else
FormHeader.Visible = False
Detail.Visible = True
CreateButtonList Me, Me.subTasks
End If
End Sub
'Sub to create buttons on the form's Detail section, starting at a given height from the top.
Sub CreateButtonList(ByRef frm As Form, ByRef buttonPane As SubForm)
Dim rsButtons As Recordset
Dim newForm As Form
Dim newButton As CommandButton
Dim colCount As Integer, rowCount As Integer, curCol As Integer, curRow As Integer
Dim newFormWidth As Integer
Dim taskFormName As String, newFormName As String
Set rsButtons = CurrentDb.OpenRecordset("SELECT * FROM USysButtons WHERE form LIKE '" & frm.name & "'")
If Not rsButtons.EOF And Not rsButtons.BOF Then
taskFormName = "USys" & frm.name & "Tasks"
On Error Resume Next
If TypeOf CurrentProject.AllForms(taskFormName) Is AccessObject Then
buttonPane.SourceObject = ""
DoCmd.DeleteObject acForm, taskFormName
End If
Err.Clear
On Error GoTo 0
Set newForm = CreateForm
newFormName = newForm.name
With newForm
.Visible = False
.NavigationButtons = False
.RecordSelectors = False
.CloseButton = False
.ControlBox = False
.width = buttonPane.width
.HasModule = True
End With
rsButtons.MoveLast
rsButtons.MoveFirst
colCount = Int((buttonPane.width) / 1584) 'Twips: 1440 in an inch. 1584 twips = 1.1"
rowCount = Round(rsButtons.RecordCount / colCount, 0)
newForm.Detail.height = rowCount * 1584
curCol = 0
curRow = 0
Do While Not rsButtons.EOF
Set newButton = CreateControl(newForm.name, acCommandButton)
With newButton
.name = "gbtn_" & rsButtons!btn_name
.Visible = True
.Enabled = True
.caption = rsButtons!caption
.PictureType = 2
.Picture = rsButtons!img_name
.PictureCaptionArrangement = acBottom
.ControlTipText = rsButtons!tooltip
.OnClick = "[Event Procedure]"
'This If block is the source of my headache.
If Not IsNull(rsButtons!open_query) And rsButtons!open_query <> "" Then
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"Private Sub gbtn_" & rsButtons!btn_name & "_Click()"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"DoCmd.OpenQuery """ & rsButtons!open_query & """"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"End Sub" & vbCrLf & vbCrLf
ElseIf Not IsNull(rsButtons!open_form) And rsButtons!open_form <> "" Then
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"Private Sub gbtn_" & rsButtons!btn_name & "_Click()"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"DoCmd.OpenForm """ & rsButtons!open_form & """"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"End Sub" & vbCrLf & vbCrLf
End If
.height = 1584
.width = 1584
.Top = 12 + (curRow * 1584)
.Left = 12 + (curCol * 1584)
.BackThemeColorIndex = 1
.HoverThemeColorIndex = 4 'Accent 1
.HoverShade = 0
.HoverTint = 40 '60% Lighter
.PressedThemeColorIndex = 4 'Accent 1
.PressedShade = 0
.PressedTint = 20 '80% Lighter
End With
curCol = curCol + 1
If curCol = colCount Then
curCol = 0
curRow = curRow + 1
End If
rsButtons.MoveNext
Loop
DoCmd.Close acForm, newForm.name, acSaveYes
DoCmd.Rename taskFormName, acForm, newFormName
buttonPane.SourceObject = taskFormName
End If
End Sub
There is no need to write code while code is running, especially as you are writing essentially the same code over and over again. All you need do is call a function instead of an event procedure.
In your code above write the OnClick event like this:
If Not IsNull(rsButtons!open_query) And rsButtons!open_query <> "" Then
.OnClick = "=MyOpenForm(""" & rsButtons!open_form & """)"
ElseIf Not IsNull(rsButtons!open_form) And rsButtons!open_form <> "" Then
.OnClick = "=MyOpenQuery(""" & rsButtons!open_form & """)"
End If
Then create these two permanent (non-generated) functions somewhere the form can see them:
Public Function MyOpenForm(FormName as String)
DoCmd.OpenForm FormName
End Function
Public Function MyOpenQuery(QueryName as String)
DoCmd.OpenQuery QueryName
End Function
And ditch the code writing to the module.