In Design View of a report I have this
In the fourth column, those two "=SUM([SUM...." text boxes both say "=Sum([SUM660201])". The column name is "SUM660201".
On the Report View however, only the first text box (the one in the detail and not in the page footer, correctly calculates the sum). In the Page view, it says "#Error" rather than "257.71"
I want the sum to be calculated in the Page Footer, not in the Detail. How do I make the sum in the Page Footer Work?
From here
The page footer and header sections, however, do not support calculated controls that use aggregate functions such as Sum
You can however use VBA to calculate page aggregates. The linked MS article explains how. The summary of their instruction is this:
Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer)
If PrintCount = 1 Then
txtPageSum = txtPageSum + ExtendedPrice
txtPageQuantity = txtPageQuantity + Quantity
End If
End Sub
Access increments [the PrintCount] property by one whenever the data for the current section is printed. Because there are times when the Print event for the Detail section for a particular record might be called more than once, checking the PrintCount value ensures that you don't add the same value twice to a page total.
Reset the numbers for the next page print
Private Sub PageHeaderSection_Print(Cancel As Integer, _
PrintCount As Integer)
txtPageSum = 0
txtPageQuantity = 0
End Sub
Again, see the MS help page for more details.
Related
I just learning how to create forms in Microsoft Access 2013 and using VBA programming to control but I'm having an issue I don't quite understand.
I have created a form with a List Box where the source originates from a query that contains the following fields the Query Builder in order from left to right:
|ParentNumber|ParentName|ChildNumber|ChildName|
|------------|----------|-----------|---------|
|------------|----------|-----------|---------|
|------------|----------|-----------|---------|
Some fields from the Query are hidden with a Column Width of 0".
I also have 4 Text Box below the List Box corresponding to the appropriate ParentNumber, ParentName, ChildNumber, and ChildName values.
When I select a record in the List Box, it populates the data to the appropriate Text Box.
When the form first loads, the first row in the List Box is selected:
Private Sub Form_Load()
On Error Resume Next
DoCmd.GoToRecord , , acFirst
Me.List = Me.List.ItemData(0)
End Sub
The issue is that if I select a different row, then close the form, and reopen the form, the first row in the List Box is overwritten with the last selected row before the form is closed.
Even if I start out with any other row selected initially when the form opens, the first row is always overwritten by the last selected row when the form is closed.
The following subroutine handles the update of the Text Box data:
Private Sub List_AfterUpdate()
Dim rowIndex As Integer
rowIndex = Me.List.ListIndex
Me.textBox_ParentNumber = Me.List.Column(3, rowIndex)
Me.textBox_ParentName = Me.List.Column(4, rowIndex)
Me.textBox_ChildNumber = Me.List.Column(6, rowIndex)
Me.textBox_ChildName = Me.List.Column(7, rowIndex)
End Sub
I found a somewhat similar problem to mine, but I tried the suggested solution, which didn't seem to work: MS Access - First record in table is overwritten on form close
I'm completely baffled as to what could cause this based on the code above.
What's my issue?
Thanks.
Few things
Private Sub Form_Load()
'remove this so you can see errors.
'On Error Resume Next
' this goes to the first record of the *form*, not the list.
' you might want this, or not.
DoCmd.GoToRecord , , acFirst
' ItemData returns the data in the *bound column* of the list,
' the data from one specific column. the list is set to that
' data every time the form loads. not what you want; remove it.
'Me.List = Me.List.ItemData(0)
End Sub
This should get rid of the problem. What you want to do next is another question.
Your form should be bound to a record set (table or query).
I had same problem, After hours of verification -
In my case - the problem was that the MainForm , And SubForm (table) - was binded to the same recordset. I just Un-Binded data RS from MainForm.
I'm having this issue where my SSRS Report header will show me the value of next group of the report. I am using the Code route to accomplish this. I have two functions, one to set the Value, and one to retrieve it. This is inside the code section of my report.
Public Shared varInvoiceNum As Integer
Public Function SetInvoiceNum(InvcNum As Integer) as Integer
varInvoiceNum = InvcNum
End Function
Public Function GetInvoiceNum() as Integer
Return varInvoiceNum
End Function
I then have a textbox with an expression that sets the value in the header of the group for Invoice Num. This group only shows Once and cant have it repeating, as it contains address information. In the Report Header is where I call the get function.
The problem occurs when the total section for the report appears on the second page. For whatever the reason, even though the header section in the tablix that contains the Set function call never reappears until the third page. On the Second page the Second Invoice Number will appear. Even though its still apart of the first group. It some how gets set to the next value. Any idea how this might be happening?
EDIT: The Second Invoice number in the batch shouldn't be showing, because the Total section is still apart of the First Invoice group. This is the Issue, there is no error message. It just improperly sets the next variable to the next group when the Set Expression hasn't occurred again.
I've reworded the title and this description because the last one didn't make much sense.
Basically, I have a report that displays business details. Some of these details include:
Business Name
Address
Documents
Clients
When the report is formatted (Print View), the business name and it's corresponding page number are added to a table(BusinessPage). The code for this is placed in the 'On Format' event of the first group header, I have listed the code below:
Dim RST As DAO.Recordset
Set RST = CurrentDb.OpenRecordset("BusinessPage", dbOpenTable)
RST.AddNew
RST![Business Name] = BUSName
RST![Business Page] = Me.Page
RST.Update
RST.Close
CurrentDb.Execute "SELECT DISTINCT * INTO t_temp FROM BusinessPage"
CurrentDb.Execute "DELETE FROM BusinessPage"
CurrentDb.Execute "INSERT INTO BusinessPage SELECT * FROM t_temp"
CurrentDb.Execute "DROP TABLE t_temp"
The table will look something like this:
Business Name Page No
Business 1 3
Business 2 4
Business 3 6 'This indicates that Business 2 spans over two pages as page 5 is skipped'
Business 4 7
In the report header, I have two things:
A cover page
An Index Sub Report/Page
The index page (Sub Report) takes the information from the table(BusinessPage) and lists all of the businesses in the report, along with the page numbers that they start on.
Now that you have an idea of how this works, here is my problem:
The sub report works fine if it only takes up one page. The issue I have is when the sub report lists too many records and it carries over onto the second page. For some reason, access still thinks that the sub report is on one page, even though it's created another page. Despite it thinking that, the footer that contains the code ([Page]) displays correctly. However, the code that displays the total amount of pages ([Pages]) is wrong. At the end of the report, the footer will say something like this:
Page 50 of 49
The other issue I have is that the information that is added to the table is wrong when the sub report exceeds one page. The information added is in assumption that the sub report is still on one page.
For example, when the sub report takes up one page:
Page 1: Cover Page
Page 2: Sub Report/Index
Page 3: Business 1
Sub report will correctly display:
Business 1 Page 3
When the sub report takes up 2 pages:
Page 1: Cover Page
Page 2: Sub Report/Index
Page 3: Sub Report/Index
Page 4: Business 1
The sub report/index page will still display:
Business 1 Page 3
Whereas it should be displaying it as:
Business 1 Page 4
Does anybody have any idea of how I can correct this? I have a feeling it may be because the sub report is in the report header (But I need it there because it will only ever be displayed once at the start of the report). Is there another way to create a secondary report header to test this theory?
Let me know if anybody thinks of any other solutions!
Edit:
I moved the sub report into it's own group/header, away from the Report Header.
This didn't change anything, access still thinks it's displaying on one page even though it's not. I have another hunch that access thinks it's on one page due to the size of the sub report in design view? The sub report in design view will fit on one page before bringing in the data, could this be the issue? How would I go about fixing that?
I was thinking, maybe an if statement to decide how big the sub report turns out, if it's the length of 2 pages, then alter the code to become:
RST![Business page] = Me.Page + 1
This is still quite a shoddy fix though, and I'm not sure how I'd go about writing the if statement to calculate the length of the page
What is happening here (I think):
When the main report is opened, BusinessPage is empty, therefore your index subreport has some minimal height.
Then Access sees you use [Pages], so it has to prepare the whole report, i.e. the Format event for all pages runs, adding the records to BusinessPage. During this, Access still assumes the minimal subreport and assigns the page numbers accordingly.
After that your index is generated, using the original page numbers - which will be wrong if the index covers >1 pages.
So I think you should do:
Before opening the report (or perhaps in Report_Open), prefill the BusinessPage table with all records that will be in there, but with a dummy page number (e.g. 0).
So the index subreport will have its correct height, and the page numbers that are generated in the Format events should be correct.
I am trying to put a number picker in a form in MS Access 2007. Here's an example of what I am trying to make:
I cannot find this in the default form controls, and have tried to make one myself using a listbox. Listboxes can be modified to look just like the number picker above, however the arrows only change the view, of the list, and not the actual selection (that is the value). For example, with the list box, if I have it range from 1 to 3, and default at 1 - when I change it to 2 via the arrows, the value of the listbox does not change, and is still one.
Does anyone know how to get a number picker in Access?
So you want to create a list of numbers and allow users to change the value displayed (AND stored as the control's value) using up and down arrows, such that they select the next or previous in the list.
I would suggest creating a text box and two buttons. Populate an array with the list of values. When a button is clicked it would:
A. Find the position in the array of any value already entered into the text box (eg loaded from a database)
B. Get the next or previous item from the array.
The array is populated as required (probably when the form is opened).
If you just need to allow the user to enter a whole integer number (ie a number spinner) you would do as follows:
Create one using a (locked) textbox and two buttons. Just add a textbox (name it something like txtValue) and two buttons (btnUp and btnDown), then add code like this to the Click event of those buttons:
Private Sub btnUp_Click()
Me.txtValue = Nz(Me.txtValue, 0) + 1
End Sub
Private Sub btnDown_Click()
Me.txtValue = Nz(Me.txtValue, 0) - 1
End Sub
You could add if statements to limit the data being entered
Or you can use a 3rd party control.
http://www.fmsinc.com/microsoftaccess/controls/components/spin-button/index.html
There are probably more, but be aware that using these sorts of controls in Access is unsupported, and there is no guarantee moving forward that they will work in Access. You're far better off using the native methods described earlier.
I have a lookup listbox which is programmed to allow the user to find a specific record/help topic from the list and view it. Now when the list box is used the where clause locks in the record and the first, previous, next, last buttons freeze up and you cannot use them to go to a record. Is there a way to free up the functionality of the buttons to navigate through the records along with the where clause to select.
Here is the code that operates the listbox selections:
Private Sub List35_AfterUpdate()
Dim myTopic As String
myTopic = "Select * from FormsHelpTable where ([ID] = " & Me.List35 & ")"
Me.Form.RecordSource = myTopic
Me.Comment.Requery
End Sub
I believe since the where clause locks in the selection in the box it does not allow navigation from other controls to interfere. What might be a way around this?
You get the runtime error:
You can't go to specified record.
It appears not to be reading the other record in the source table named Help once it updates using the listbox.
Instead of changing the recordset (this is the 'pool' of records which the form could display), you just need to go to the record the user selects from the listbox.
Method 1 (probably the easiest way if your listbox is in the same order as the records of your form)
Use this code:
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
End Sub
You need to ensure that:
The recordset of the form is ordered the same as the listbox. So, for example, you could order both by ID, or by Title.
Note that the +1 comes from the fact that the ListIndex starts at 0, whereas the record indexes start at 1.
Method 2
Ensure each record's Title is unique (set No Duplicates on this field).
Change your listbox to return the Title of the record, rather than it's ID.
Then use this:
Private Sub lstSelect_AfterUpdate()
Me.Title.SetFocus
DoCmd.FindRecord Me.lstSelect
Me.lstSelect.SetFocus
End Sub
Things to note:
It works by searching the field with focus for the string specified. That's why we have to SetFocus on the Title textbox on our form.
We could use ID instead, (which would mean we could have duplicate titles if we wanted), but then we would have to have an ID control on the form to SetFocus to. You can't hide this control either, because it needs to have focus whilst using FindRecord.
Update: Method 1 with reverse-selection
Add an Event Procedure in the Form_Current event, with this code. Then update the code in the lstSelect_AfterUpdate procedure as shown after.
Private Sub Form_Current()
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Note that, depending on how your lstSelect is set up, it may be Column(1, Form.CurrentRecord - 1) instead. Read on for details!
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Explanation of new lines:
The Form_Current event fires every time we go to a new record. We need to look at the index of the record (ie. the position of it in the recordset), which we get by using Form.CurrentRecord. We then want to make the listbox select that record. However, we can't use me.lstSelect.ListIndex as before, because that is a read-only property (we can access it to read it, but we can't set it).
Therefore, we use me.lstSelect.Column(colNum,rowNum) instead, where we specify a column number and a row number. If your listbox has two columns (eg. ID and Title), we want to choose the second column. The index starts at 0, so we would use a value of 1. If, like my lstSelect, you only have one column (Title) then we use 0. Note: it doesn't matter if a column is hidden (ie. has width 0). It still 'counts'.
The row number is Form.CurrentRecord - 1. Remember that the forms recordset index starts at 1, but the index of our listbox starts at 0; hence the - 1.
So why do we need a duplicate of this new row in the AfterUpdate event? Try and comment it out to see what happens if we don't put it in. It's has to do with the Form_Current event firing after we use the listbox.
I fixed this issue with a union clause in the SQL lookup code. The UNION ALL clause and the following union on the table used in the other part had allowed all the records to be used.