Setting the Data Source for a Report - ms-access

I'm trying to make a button in an Access form which will run a couple queries and then take the resultant recordsets and put them into reports. I have gotten to the point where the button will call the module, it creates the proper recordsets, and then it creates the reports. However, the reports are blank, they don't have the data in them from the recordsets. I think my problem is that I haven't properly assigned the data source of the reports but I can't figure out how to if that is the issue.
Private Function showReport(sectionHeading As String, SQL As String, recordset As ADODB.Recordset)
Dim textBox As Access.textBox ' textbox control
Dim label As Access.label ' label control
Dim report As report ' hold report object
Dim controlTop As Long ' holds top value of control position
Dim controlLeft As Long ' holds left value of control position
Dim title As String 'holds title of report
Dim i As Integer 'iterator
i = 0
title = sectionHeading
controlLeft = 0
controlTop = 0
Set report = CreateReport
report.Width = 8500
report.Caption = title
Set label = CreateReportControl(report.Name, acLabel, _
acPageHeader, , "Title", 0, 0)
label.FontBold = True
label.FontSize = 12
label.SizeToFit
For Each fld In recordset.fields
Set textBox = CreateReportControl(report.Name, acTextBox, _
acDetail, , fld.Name, controlLeft + 1500, controlTop)
textBox.SizeToFit
Set label = CreateReportControl(report.Name, acLabel, acDetail, _
textBox.Name, fld.Name, controlLeft, controlTop, 1400, textBox.Height)
label.SizeToFit
controlTop = controlTop + textBox.Height + 25
i = i + 1
Next
Set label = CreateReportControl(report.Name, acLabel, _
acPageFooter, , Now(), 0, 0)
Set textBox = CreateReportControl(report.Name, acTextBox, _
acPageFooter, , "='Page ' & [Page] & ' of ' & [Pages]", report.Width - 1000, 0)
textBox.SizeToFit
report.RecordSource = SQL
DoCmd.OpenReport report.Name, acViewPreview
recordset.Close
Set recordset = Nothing
Set report = Nothing
End Function

I'd say you are missing a line like
report.RecordSource = "the query that fills <recordset>"
But I'm pretty sure that there must be a better way to achieve your goal than creating a new report from scratch.
And it's error-prone to name your variables like their data types (label, report, ...)
Edit
Are you sure your SQL is valid? Alternatively, you can try saving it as query and pass the query name.
I did a little test, it should work principally. r_tbProduct has an empty recordsource when I run this:
Dim rep As Report
DoCmd.OpenReport "r_tbProduct", acViewDesign
Set rep = Reports!r_tbProduct
rep.RecordSource = "SELECT * FROM tbProduct WHERE ID >= 6"
DoCmd.OpenReport "r_tbProduct", acViewPreview
It shows the correct data.
Again, I strongly suggest you rename your variables.
Dim report As report
is just asking for problems.

Related

Creating Group-Level in Dynamic Report (MS Access)

I need to create a dynamic (on the fly) report, because the number and names of fields will change frequently. I have it all worked out except I cannot figure out how to create a group header based upon a field name.
Here was my first try, which returns "The number you used to refer to the form or report section is invalid."
Dim rpt as Report
dim txtNew as Access.Textbox
set rpt = CreateReport
With rpt
.Width = 8500
.RecordSource = "IS_Subscales_GB_Final"
End With
Set txtNew = CreateReportControl(rpt.Name, acTextBox, acGroupLevel1Header, , "FriendlyName01", 0, 0)
txtNew.FontBold = True
txtNew.FontSize = 16
txtNew.SizeToFit
DoCmd.OpenReport rpt.Name, acViewPreview
So I next tried to use CreateGroupLevel, but this returns the error "You can't call this function when the Group, Sort, and Total Pane is open."
Dim rpt as Report
dim txtnew as Access.Textbox
Dim vargrplvl As Variant
set rpt = CreateReport
With rpt
.Width = 8500
.RecordSource = "IS_Subscales_GB_Final"
End With
vargrplvl = CreateGroupLevel(rpt.Name, "FriendlyName", True, False)
rpt.Section(acGroupLevel1Header).Height = 400
Set txtNew = CreateReportControl(rpt.Name, acTextBox, acGroupLevel1Header, , "FriendlyName01", 0, 0)
txtNew.FontBold = True
txtNew.FontSize = 16
txtNew.SizeToFit
DoCmd.OpenReport rpt.Name, acViewPreview
Any guidance would be appreciated.
I made multiple mistakes but also, Access has a quirk where it unexpectedly throws the 2451 error ("You can't call this function when the Group, Sort, and Total Pane is open.")---this happens only if the last time you were in Design view for a report, you had the Group, Sort, and Total Pane open. Access saves that setting so you either need to go back into a report in Design view and turn the panel off, or use an error handler to work around it. So here is a learning lesson coming from the whole ordeal:
Dim rpt as Report
Dim vargrplevel As Variant 'holds grouping level of report
Dim txtNew as Access.Textbox ' textbox control
Dim lblNew As Access.Label ' label control
set rpt = CreateReport 'creates a report object
with rpt
.width = 8500 'sets width of report
.RecordSource = "IS_Subscales_GB_Final" ' your table or query
end with
'start setting your controls on the report using CreateReportControl, i.e.:
Set lblNew = CreateReportControl(rpt.Name, acLabel, acDetail, , , 2700, 0, 270, 315)
lblNew.Caption = "O"
lblNew.FontSize = 12
lblNew.FontBold = True
'To add a group level to the report, it MUST be in acViewDesign!
DoCmd.OpenReport rpt.Name, acViewDesign
On Error GoTo ErrorHandler
'if the Group, Sort, and Total pane was left "on" then this next line will throw error 2451
vargrplevel = CreateGroupLevel(rpt.Name, "FriendlyName01", True, False) 'Creates a group header, named "FriendlyName01"
rpt.Section(acGroupLevel1Header).Height = 400 'optional; sets the header height
Set txtNew = CreateReportControl(rpt.Name, acTextBox, acGroupLevel1Header, , "FriendlyName01", 0, 0) 'This actually inserts the field into the header as textbox control
txtNew.FontBold = True
txtNew.FontSize = 16
DoCmd.Save acReport, rpt.Name
Exit Sub
ErrorHandler:
If Err.Number = 2154 Then
RunCommand acCmdSortingAndGrouping 'turns off the Sorting and Grouping pane
Resume
Else
Debug.Print "Error in creating report header (EH01- " & Err.Number & ")"
Exit Sub
End If
Cheers.

How to create a ListBox with checkboxes in a Microsoft Access Form?

I'm new to Microsoft Access and would like to create a ListBox (or ListView) with checkboxes, however I can't find any native way for doing so.
My intention is to display a list of values and have some of the values checked depending on what value is selected in a ComboBox on the form.
Please note that I'm needing such a control for a form and not a table (for which there's this "multivalued lookup field"). (Besides if there's a way to create a subform with a table with just the multivalue-column that reacts to what's selected in the ComboBox.)
An ordinary list box with the "Multi Select" property set to "Simple" doesn't display checkboxes.
I also can't see the "ListStyle" property described here.
Maybe it's somehow possible to display two columns in the ListBox of which the first is rendered as checkbox?
You can use the ListView control. It is located under ActiveX Controls, the full name is Microsoft ListView Control, version 6.0.
It has a separate set of properties: right-click -> ListViewCtrl object -> Properties, in there is the Checkboxes property.
To fill the listview with data, see e.g. ACC: Sample Function to Fill a ListView Control
More info: Using the ListView Control
Edit
To comfortably work with the Listview object model, set a reference to Microsoft Windows Common Controls 6.0 = C:\Windows\SysWOW64\MSCOMCTL.OCX on my Windows7 64bit.
Edit 2
I use a TreeView with checkboxes. Each Node has a Checked property, that checks or unchecks its checkbox. Where the Treeview has Nodes, the Listview has ListItems, but they have a Checked property too.
Simplified code for Treeview (without hierarchies):
Dim oTree As TreeView
Dim oNode As Node
Dim RS As Recordset
Set oTree = Me.myTreeView.Object
oTree.Nodes.Clear
Set RS = DB.OpenRecordset("My query to fill the treeview")
Do While Not RS.EOF
Set oNode = oTree.Nodes.Add(key:=RS!foo, Text:=RS!bar)
oNode.Checked = (RS!someValue > 0)
RS.MoveNext
Loop
RS.Close
You can't modify a listbox of Access like that, but you can customize a subform in datasheet view to mimic such a listbox.
To display more or less fixed values, create a small local table to be bound by the form and fill it with the values you need.
So got it working now with the help of Andre's answer:
First, as the ListView is dependent on the currently selected item of a table I'm populating it via the Form_Current event of the table. (Simply by Call Forms.Item("MainForm").PopulateListView)
Here's the working PopulateListView method (note that you need to reference Microsoft Windows Common Controls 6.0 first):
Public Sub PopulateListView()
On Error GoTo ErrorHandler
Dim intToCount As Integer
Dim intCount1 As Integer
Dim intCount2 As Integer
Dim intToCount2 As Integer
Dim intCount12 As Integer
Dim intCount22 As Integer
Dim NewLine As Object
Dim db As Database
Dim rs As Recordset
Dim colNew As Object
Dim s As String
' Clear the ListView control.
Forms![MainForm].[SubForm].Form.[ctlListView].ListItems.Clear
Forms![MainForm].[SubForm].Form.[ctlListView].ColumnHeaders.Clear
' Set Variables.
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT A, B, IsChecked . . .")
' Set Column Headers.
Set colNew = Forms![MainForm].[SubForm].Form.[ctlListView].ColumnHeaders.Add(, , "A", 2000)
Set colNew = Forms![MainForm].[SubForm].Form.[ctlListView].ColumnHeaders.Add(, , "B", 4000)
' Set Total Records Counter.
rs.MoveLast
intToCount = rs.RecordCount
rs.MoveFirst
' Loop through recordset and add Items to the control. Twice as a workaround to sort by checkbox.
For intCount1 = 1 To intToCount
If (rs(2).value = 1) Then
If IsNumeric(rs(0)) Then
s = Trim(Str(rs(0).value))
Else
s = Trim(rs(0).value)
End If
Set NewLine = Forms![MainForm].[SubForm].Form.[ctlListView].ListItems.Add(, , s)
If IsNull(rs(1)) Then
NewLine.ListSubItems.Add Text:=""
Else
NewLine.ListSubItems.Add Text:=rs(1).value
End If
NewLine.Checked = True
End If
rs.MoveNext
Next intCount1
' Set Total Records Counter.
rs.MoveLast
intToCount2 = rs.RecordCount
rs.MoveFirst
For intCount12 = 1 To intToCount2
If (rs(2).value = 0) Then
If IsNumeric(rs(0)) Then
s = Trim(Str(rs(0).value))
Else
s = Trim(rs(0).value)
End If
Set NewLine = Forms![MainForm].[SubForm].Form.[ctlListView].ListItems.Add(, , s)
If IsNull(rs(1)) Then
NewLine.ListSubItems.Add Text:=""
Else
NewLine.ListSubItems.Add Text:=rs(1).value
End If
End If
rs.MoveNext
Next intCount12
Exit Sub
ErrorHandler:
' Err 3021 = no current record. Err 2455 = happens at necessary first call of method and couldn't catch in code.
If Err = 91 Or Err = 3021 Or Err = 2455 Then
Resume Next
Else
If Err <> 94 Then
' Otherwise display the error message.
MsgBox "Error: " & Err.Number & Chr(13) & Chr(10) & Err.Description & vbCrLf & "(PopulateListView)"
End If
End If
End Sub
Then for saving I'm using this:
For Each Item In Forms![MainForm].[SubForm].Form.[ctlListView].Object.ListItems
If Item.Checked = True Then
'Use Item here
End If
Next

Access Form's textbox not showing value

I have an unbound textbox in form f_FeuilleBleue. In my code, I give it a certain value;
Debug.Print strAHNS '00 0AA 00-100 F TX-01
Form_f_FeuilleBleue.txt_AHNS = strAHNS
If I put a stopping point on the next line, the immediate window shows that
?Form_f_FeuilleBleue.txt_AHNS
answer: 00 0AA 00-100 F TX-01
However, I still see it as blank in my form. There is no data to be read!
How do I fix this? Is it an issue with screen updating? (I have nothing setting it to off) Maybe form updating? (I have a msgBox in the BeforeUpdate event but it doesn't go in that event)
EDIT - additional info:
When I open the form, there is no problem. I can change the value in the form or by code. However the issue only happens when the form is opened from a menu-style form. Code below. Even after the opening sub finishes, the textbox won't update (visually - it does in value). After testing I see that the Change and the Update event are NOT launched when changing the value of the textbox from another sub (Private subs may be the cause?) But why is it continuing to not show the values even after the subs end?
Could be very, very relevant to read but I'm not sure what to make of it: Obtaining textbox value in change event handler
Here is the code that opens the form:
Private Sub Command7_Click()
Dim strAHNS As String
Dim strquery As String
strAHNS = Replace(Mid(Me.Combo_Dessin2, InStr(Me.Combo_Dessin2, "=") + 1), "=", " ")
strquery = "[ID] = (SELECT Max([ID]) FROM [Feuilles])"
Debug.Print strquery
If (PremierAffichage) Then
DoCmd.OpenForm FormName:="f_feuillebleue", WhereCondition:=strquery
Else
MsgBox "Le projet ou dessin n'a pas été trouvé."
End If
End Sub
Function PremierAffichage() As Boolean
Dim rsFeuilles As DAO.Recordset
Dim rsProjets As DAO.Recordset
Dim strContrat As String
Dim strProjet As String
Dim strDessin As String
Dim sqlquery As String
Dim strAHNS As String
Dim strGroupe As String
Dim strMachine As String
If IsNull(Me.Combo_Dessin2) Or IsNull(Me.Combo_Projet) Or Me.Combo_Dessin2.Value = "" Then
PremierAffichage = False
Exit Function
End If
strProjet = Me.Combo_Projet
strAHNS = Me.Combo_Dessin2
strMachine = Mid(strAHNS, 4, 3)
strGroupe = Mid(strAHNS, 8, 2)
Debug.Print strProjet & " ** " & strAHNS & " ** " & strMachine & " ** " & strGroupe
sqlquery = "SELECT [AHNS], [Contrat], [No Projet], [EP (groupe)], [Type machine], [Mois] FROM [Feuilles]" 'WHERE [AHNS] = '" & strAHNS & "'"
Set rsFeuilles = CurrentDb.OpenRecordset(sqlquery)
sqlquery = "SELECT [Projet HNA] FROM [Projets] WHERE [Projet AHNS] = '" & strProjet & "'"
Set rsProjets = CurrentDb.OpenRecordset(sqlquery)
Debug.Print strAHNS '========================================--------
Form_f_FeuilleBleue.txt_AHNS = strAHNS ' this works in .value but not showing the result
DoEvents ' any changes from there on don't update the value visually
' ==========================================------
If rsProjets.RecordCount > 0 Then
rsFeuilles.AddNew
rsFeuilles![Contrat] = rsProjets![Projet HNA]
rsFeuilles![No Projet] = strProjet
rsFeuilles![AHNS] = strAHNS
rsFeuilles![Mois] = MonthName(Mid(Date, 6, 2))
If strMachine Like "[A-Z][A-Z][A-Z]" Then
rsFeuilles![Type machine] = strMachine
rsFeuilles![EP (groupe)] = strGroupe
End If
rsFeuilles.Update
PremierAffichage = True
End If
rsProjets.Close
Set rsProjets = Nothing
rsFeuilles.Close
Set rsFeuilles = Nothing
End Function
Assign your value to the active form instance (the open form) instead of to the form's class.
So assuming the open form's name is f_FeuilleBleue and you want to assign that value to the form's txt_AHNS control ...
'Form_f_FeuilleBleue.txt_AHNS = strAHNS
Forms!f_FeuilleBleue!txt_AHNS = strAHNS
Reference the form by its name as a member of the Forms collection.

access : populate textbox separately with VBA

In Acces I have a continuous form with independant textbox.
I try to fill it using vba for each record find in the query result, but this fill all the textbox with the same value.
This is my Form
Private Sub Form_Open(Cancel As Integer)
Dim WO As String
WO = Forms![Maintenance input formulaire]![Maintenance input sous formulaire].Form![WONumber]
query = "select comment from SystemAircraftStatus where SystemID = " + CStr(Me.SystemID) + " and WO = '" + WO + "';"
Debug.Print (query)
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset(query)
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Me.Texte54.Value = rs.Fields("comment") 'PROBLEME : est appliqué a tous les enregistrements
End If
End Sub
and this is the VBA code, only the first result (with "autre") have a comment.
Is there a solution to fill each textbox separately ?
The reason why it fills all the textboxes with one value: It is a continous
form and the textbox is unbound.
The textbox has to be bound to a value in the recorset of the form in order to show different values.
I suggest you use the recordset object to bind the textbox to a value in the recordset of the form. Like this:
Sub Form_Open(Cancel As Integer)
dim qry as string
qry = _
"select WO, comment from SystemAircraftStatus where SystemID = " + CStr(Me.SystemID) + " and WO = '" + WO + "';"
me.recordset = qry
End Sub
You need to select the two values directly in your SQL query for the recordset object.
Then you use the properties of the textbox to bind it to the value in the query.
Best regards

How to change color for part of the text in a particular field in Access?

In Access, I have a table which contain a field like this:
Part Number
A/B/C
A/B/R
T/Y/V
D/A/I
I want to change the color of the all the third part to red. So in this case C,R,V,I will be colored red. But I can't do change the color of part of the text field in Access 2007. If I use Font Change under Home tab it change the Font of entire Table. I'm so disappointed about Microsoft. Is there any way to change the color would be great :D You can recommend VBA , Macro in Form, Query, Report ...
P/S: I use Access 2007
if you can use an Access report, you can add a TextBox to the report. In the textbox, you can have a formula like this:
="<font color=""blue"">" & [ColumnA] & "</font> <u>" & [ColumnB] & "</u>"
See Access Rich-Text: Which subset of HTML is supported? for more details.
ok I think the only way is to export automatically to Excel. Finally I can do this
Private Sub CommandExport_Click()
Dim db As Database
Dim rec1 As Recordset
Dim xlFile As Object
Dim xlWorkBook As Object
Dim xlActiveWkb As Object
Dim xlActiveSheet As Object
Dim iCols, iRows, flag As Integer
Set db = CurrentDb
Set xlFile = CreateObject("Excel.Application")
Set xlWorkBook = xlFile.Workbooks.Add
Set xlActiveWkb = xlFile.Application.ActiveWorkBook
xlFile.Visible = True
xlActiveWkb.Sheets.Add
xlActiveWkb.Worksheets(1).Name = "My_Report"
Set xlActiveSheet = xlActiveWkb.Worksheets("My_Report")
Set rec1 = db.OpenRecordset("Report")
For iCols = 0 To rec1.Fields.Count - 1
xlActiveSheet.Cells(1, iCols + 1).Value = rec1.Fields(iCols).Name
If rec1.Fields(iCols).Name = "FS Number" Then
flag = iCols
End If
Next
xlActiveSheet.Range(xlActiveSheet.Cells(1, 1), xlActiveSheet.Cells(1, rec1.Fields.Count)).Font.Bold = True
xlActiveSheet.Range(xlActiveSheet.Cells(1, 1), xlActiveSheet.Cells(1, rec1.Fields.Count)).Interior.ColorIndex = 15
xlActiveSheet.Cells(2, 1).CopyFromRecordset rec1
xlActiveSheet.Columns("A:AD").EntireColumn.AutoFit
iRows = 1
rec1.MoveFirst
While Not rec1.EOF
xlActiveSheet.Cells(iRows + 1, flag + 1).Characters(InStr(rec1![FS Number], "*")).Font.ColorIndex = 3
iRows = iRows + 1
rec1.MoveNext
Wend
Set xlSheet = Nothing
Set xlWorkBook = Nothing
Set xlActiveWkb = Nothing
rec1.Close
db.Close
Set rec1 = Nothing
Set db = Nothing
End Sub
The magic is here
xlActiveSheet.Cells(iRows + 1, flag + 1).Characters(InStr(rec1![FS Number], "*")).Font.ColorIndex = 3