Report in the first plan with SUM Field in footer - ms-access

I'm stuck in a Report(Modal window "yes" popup "yes" with 2 Groups) opened by a button in a F_Menu form(Modal window "yes" popup "yes" ).
I am looping in a field(T_OV )in the footer which Results from the sum of the field(Net_Payer) in detail
I motion that everything is fine and the calculation is done if the State opens (Modal window "No" popup "No") and the form F_Menu(Modal window "No" popup "No") with these two codes :
Private Sub ZonePiedPage_Print(Cancel As Integer, PrintCount As Integer)
[T_OV].Value = TotalPage
'Initialisation de la variable pour la page suivante
TotalPage = 0
End Sub
and
Private Sub Détail_Print(Cancel As Integer, PrintCount As Integer)
TotalPage = Nz(TotalPage + [Net_Payer], 0)
End Sub
But in my case, the field (T_OV ) does not display anything
All my work remains dependent on this problem
I ask How to join the file, please?
Thank you very much for all answers
https://1drv.ms/u/s!Ap2VD1yrtJnXhVL5j9wJM6K4ZvF5?e=bT0WV4

Following is example from my report that provides a page record count and page total of a field. Note the difference from your code in use of Nz() function.
Option Compare Database
Option Explicit
Public intPageCount As Integer
Public intPageTotal As Integer
Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer)
' increment variables for each record printed
intPageCount = intPageCount + 1
intPageTotal = intPageTotal + Nz(Me.Qty, 0)
End Sub
Private Sub PageFooterSection_Format(Cancel As Integer, FormatCount As Integer)
'set textboxes in the footer
tbxPageCount = intPageCount
tbxPageTotal = intPageTotal
'reset globals
intPageCount = 0
intPageTotal = 0
End Sub

Related

How do I hide horizontal lines on Access when a particular text box is empty?

I have a report with 5 textboxes each separated by a horizontal line.
The first textbox will always be populated but I would like to suppress the viewing/printing of any of the lines after that if the 2nd textbox is empty.
I've tried this...
Public Function Hide_Lines()
Dim ELRep As Report
Set ELRep = Reports("EL_Report")
If ELRep.Name_2 = Null Then
Set ELRep.Line2.Visible = False
Set ELRep.Line3.Visible = False
Set ELRep.Line4.Visible = False
Set ELRep.Line5.Visible = False
End If
End Function
...but I get a 'Method 'Item' of object 'Reports' failed error.
Is my syntax suspect or am I barking up completely the wrong tree?
Many thanks,
Chas
Cannot compare anything to Null, = Null won't work. Review http://allenbrowne.com/casu-12.html.
Probably a function call is unnecessary complication. Use the report Detail Section OnFormat event with:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
With Me
If IsNull(.Name_2) Then
.Line1.Visible = False
.Line2.Visible = False
.Line3.Visible = False
.Line4.Visible = False
End If
End With
End Sub
or
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
With Me
.Line1.Visible = Not IsNull(.Name_2)
.Line2.Visible = Not IsNull(.Name_2)
.Line3.Visible = Not IsNull(.Name_2)
.Line4.Visible = Not IsNull(.Name_2)
End With
End Sub
or
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Dim x As Integer
For x = 1 to 4
Me.Controls("Line" & x).Visible = Not IsNull(Me.Name_2)
Next
End Sub
Be aware OnFormat event only triggers in PrintPreview or direct to printer not ReportView.

Access VBA: Form timer not showing MsgBox at the intended time

I am trying to get the DB to close after 2 minutes have passed by (for testing purposes I am just making a MsgBox appear after the 2 minutes). To do this, I have a main form called DTForm and a hidden form called Timer. Both forms open on opening the DB but Timer opens in hidden mode.
AutoExec Macro:
1. Open DTForm (the main form)
2. Open Timer (the hidden form)
Module 1:
Option Compare Database
Option Explicit
Public timer_start As Date
Public timer_end As Date
Public timer_diff As Integer
DTForm (users will only see this form)
Option Compare Database
Option Explicit
Public Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
timer_start = Time
timer_end = DateAdd("n", 2, timer_start)
End Sub
Timer (the hidden form):
Option Compare Database
Option Explicit
Public Sub Form_Open(Cancel As Integer)
timer_start = Time
timer_end = DateAdd("n", 2, Time)
End Sub
Public Sub Form_Load()
timer_start = Time
timer_end = DateAdd("n", 2, Time)
End Sub
Public Sub Form_Timer()
timer_diff = DateDiff("n", timer_end, Time)
If timer_diff >= 0 Then
'Application.Quit
MsgBox "timer reached 0"
timer_start = Time
timer_end = DateAdd("n", 2, Time)
End If
End Sub
Update - the problem: So now the problem is the mouse. It looks like just moving the mouse around the form does nothing. However, moving the mouse from the navigation pane to the form and back (in and out) does trigger the mouse movement. This seems really counter-intuitive - why not just consider all mouse movements?
Notes: Added Option Explicit to the tops of both forms and fixed some missing variable declarations.
This seems to be a variable scope issue to me. By default your variables are local.
Unless timer_end is declared as a global or public variable, it is out of scope as soon as you leave the sub where it is defined. So the timer_end in Form_timer is a totally different variable than the one in your MouseMove event (even though they have the same name).
This is one reason why many people put "option explicit" at the beginning of their code as it forces you to declare your variables.
You could also pursue a design strategy where you pass the variable as a parameter instead of making it global or public
If you want to go through with it, the Form_MouseMove event must be in every form, because only the active form receives the MouseMove event.
Note: you actually don't need the timer_start variable at all. You can remove it and keep only:
Public Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
timer_end = DateAdd("n", 2, Time)
End Sub
Or somewhat cleaner:
Public Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Call UpdateTimer()
End Sub
and in your Module1:
Public Sub UpdateTimer()
timer_end = DateAdd("n", 2, Time)
End Sub
in case you decide to change the time interval...
Note:
timer_diff should be a local variable in Timer.Form_Timer(), since it's only used there.
DateDiff("s", timer_end, Time) will return a negative value until the 10 seconds of inactivity, then the condition must be changed to >= and the time interval to 1000 (1 second) 1 millisecond is too fast.
Also to make sure the variables are ok add option explicit clause
Option Compare Database
Option Explicit
Dim timer_start as Variant
Dim timer_end as Variant
Public Sub Form_Open(Cancel As Integer)
timer_start = Time
End Sub
Public Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
timer_start = Time
timer_end = DateAdd("s", 10, timer_start)
Me.Label6.Caption = timer_start
Me.Label8.Caption = timer_end
End Sub
Public Sub Form_Timer()
If DateDiff("s", timer_end, Time) >= 0 Then
MsgBox "timer reached 0"
End If
End Sub

Clear text box on form after a few seconds

I would like to find the best way to have a text box displays a message everytime another control (a button) is pushed. Each time the button is pushed, the message will change and that message should show in my text box. The trick I would like to do is after the user stops pressing the button, that after a certain period (3 seconds) the text box will disappear.. (perhaps the message can be deleted). What is the correct event to use ?
Basically, for each control named 'msgPrincipio' in the code below, i would like that message to appear within the text box for 3 seconds and then disappear:
Private Sub Form_Timer()
Dim intTimerStart As Integer, intTimerUsed As Integer
Dim intCountdown As Integer
On Error GoTo Err_Handle
If Me!msgPrincipio <> "" Then
If intTimerStart > 0 Then
intTimerUsed = CLng((Timer / 60) - intTimerStart)
Else
intTimerStart = CLng(Timer / 60)
End If
If intCountdown > 3 Then
Me!msgPrincipio = ""
End If
intCountdown = intCountdown + 1
End If
Err_Exit: Exit Sub
Err_Handle: Resume Next
End Sub
Dim intTimerStart as Integer, intTimerUsed as Integer
Dim intCountdown as Integer
Sub Form_Timer()
On Error GoTo Err_Handle
If Me!MyBox <> "" Then
If intTimerStart > 0 Then
intTimerUsed = CLng((Timer / 60) - intTimerStart)
Else
intTimerStart = CLng(Timer / 60)
End If
If intCountdown > 3 Then
Me!MyBox = ""
End If
intCountdown = intCountdown + 1
End If
Err_Exit: Exit Sub
Err_Handle: Resume Next
End Sub
You also need to go to the form's design view and set the "Timer Interval" property on the form to an appropriate value. This code assumes 1,000 (1 second).
You almost never want to use Resume Next, but it's good here -- the goal is to pass through this block of code as seamlessly as possible. (Which you can accomplish with simple On Error Resume Next at the start -- but I don't like seeing it in my code that way, not one bit. I do this so I'll easily recognize it's by design, not carelessness.)
New to Access' Form Timer?
Private Sub Form_Timer()
Debug.Print Time ' Update time display.
End Sub
Put this code in the form's VBA module. Return to the form design view and switch to form view. Now go back to VBA and check your Immediate window. You should see evidence the form timer event is kicking. Note the Timer property of the form (found under form properties, design view) must not be blank or zero. It needs an entry to kick.
Using C#
using System.Windows.Forms;
public partial class Form1 : Form
{ private Timer x = new Timer();
public Form1()
{
x.Interval = (6000); //1 second = 1000
x.Tick += new EventHandler(TimerTask);
x.Start();
}
private void TimerTask(object sender, EventArgs e)
{
TextboxName.Text = String.Empty;
}
To set a label content dispear automatically: https://gamespec.tech/how-to-clear-textbox-after-few-seconds-in-c-sharp/#3-set-label-content-and-make-it-disappear-automatically

Is it possible to simulate tri-state checkboxes in Microsoft TreeView Control 6.0 (MSComctlLib.TreeCtrl.2)?

I'm using the Microsoft TreeView Control 6.0 in Microsoft Access. It seems to work very well, except that it doesn't seem to have a greyed out state, indicating that some, but not all child nodes are checked.
I've looked into using my own images to simulate the checkboxes, but if I do this, I then have to remove the real checkboxes or it looks like I have two checkboxes for each item... but then I don't have any checkboxes and I can't work out how to handle a click on the images.
I can find loads of people having the same sort of questions for this control in other languages/uses, but I can't find a solution for Microsoft Access.
I would happy moving over to a different control, if there's something else available that gives me a hierarchical structure with tri-state checkboxes.
After a bit of research and a couple of hours coding, I was able to write a solution myself.
I had to add an ImageList, associate that to the TreeView and add an image of a checkbox for each of the three states. Google Image search saved me some time here :).
'Enumeration for simulated tri-state checkboxes, matching up to the TreeView's associated Image List's Index
Private Enum CheckboxEnum
Unchecked = 1
Checked = 2
Partial = 3
End Enum
'---------------------------------------------------------------------------------------
' Procedure : objTreeView_MouseDown
' Author : Matty Brown
' Date : 19/05/2014
' Purpose : Because TreeView doesn't support tri-state checkboxes, these have to be simulated using images.
'---------------------------------------------------------------------------------------
'
Private Sub objTreeView_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)
Const CHECKBOX_WIDTH As Integer = 195 '195=13px
Dim objNode As Node
Set objNode = objTreeView.HitTest(x, y)
If objNode Is Nothing Then
'Miss
Else
'Find left side of node by moving left one pixel at a time until you fall off the node, then move one pixel to the right
Dim intX As stdole.OLE_XPOS_PIXELS
For intX = x To 0 Step -15
If Not objNode Is objTreeView.HitTest(intX, y) Then
If x <= intX + CHECKBOX_WIDTH Then
'User clicked on the checkbox
Select Case objNode.Image
Case CheckboxEnum.Unchecked:
objNode.Image = CheckboxEnum.Checked
Case Else:
objNode.Image = CheckboxEnum.Unchecked
End Select
'Recursively check child nodes
Call CheckTreeNodes(objTreeView, objNode, objNode.Image)
'Update parent node(s)
Call UpdateParentNodes(objTreeView, objNode)
Else
'User clicked outside of the checkbox
'
End If
Exit For
End If
Next
End If
End Sub
'---------------------------------------------------------------------------------------
' Procedure : CheckTreeNodes
' Author : Matty Brown
' Date : 16/05/2014
' Purpose : Checks or unchecks all of the child nodes for the specified node
'---------------------------------------------------------------------------------------
'
Private Sub CheckTreeNodes(ByRef tv As TreeView, ByRef nodNode As Node, ByVal Value As CheckboxEnum)
Dim lngIndex As Long
'Cascade change to children
If nodNode.Children > 0 Then
lngIndex = nodNode.Child.Index
Call CheckTreeNodes(tv, tv.Nodes(lngIndex), Value)
Do While lngIndex <> nodNode.Child.LastSibling.Index
lngIndex = tv.Nodes(lngIndex).Next.Index
Call CheckTreeNodes(tv, tv.Nodes(lngIndex), Value)
Loop
End If
nodNode.Image = Value
End Sub
'---------------------------------------------------------------------------------------
' Procedure : CountChildNodes
' Author : Matty Brown
' Date : 19/05/2014
' Purpose : Counts how many child nodes are checked or unchecked, so that a parent node can be set correctly
'---------------------------------------------------------------------------------------
'
Private Sub CountChildNodes(ByRef tv As TreeView, ByRef nodNode As Node, ByRef lngChecked As Long, ByRef lngUnchecked As Long)
Dim lngIndex As Long
'Check this node's children
If nodNode.Children > 0 Then
lngIndex = nodNode.Child.Index
Call CountChildNodes(tv, tv.Nodes(lngIndex), lngChecked, lngUnchecked)
Do While lngIndex <> nodNode.Child.LastSibling.Index
lngIndex = tv.Nodes(lngIndex).Next.Index
Call CountChildNodes(tv, tv.Nodes(lngIndex), lngChecked, lngUnchecked)
Loop
Else
'Update totals
Select Case nodNode.Image
Case CheckboxEnum.Checked:
lngChecked = lngChecked + 1
Case CheckboxEnum.Unchecked:
lngUnchecked = lngUnchecked + 1
End Select
End If
End Sub
'---------------------------------------------------------------------------------------
' Procedure : UpdateParentNodes
' Author : Matty Brown
' Date : 19/05/2014
' Purpose : Steps through parent nodes, updating them according to how many checked/unchecked child nodes they have
'---------------------------------------------------------------------------------------
'
Private Sub UpdateParentNodes(ByRef tv As TreeView, ByRef nodNode As Node)
Dim lngIndex As Long
Dim nodParent As Node
Dim lngChecked As Long, lngUnchecked As Long
'If this node has no parents, there's nothing to update
If nodNode.Parent Is Nothing Then Exit Sub
Set nodParent = nodNode
Do While Not nodParent.Parent Is Nothing
Set nodParent = nodParent.Parent
'Reset counters
lngUnchecked = 0
lngChecked = 0
'Count children
Call CountChildNodes(tv, nodParent, lngChecked, lngUnchecked)
'Update parent nodes
If lngUnchecked = 0 And lngChecked > 0 Then
nodParent.Image = CheckboxEnum.Checked
ElseIf lngUnchecked > 0 And lngChecked > 0 Then
nodParent.Image = CheckboxEnum.Partial
Else
nodParent.Image = CheckboxEnum.Unchecked
End If
Loop
End Sub

How do I access the selected rows in Access?

I have a form which includes a data sheet. I would like to make it possible for a user to select multiple rows, click on a button and have some sql query run and perform some work on those rows.
Looking through my VBA code, I see how I can access the last selected record using the CurrentRecord property. Yet I don't see how I can know which rows were selected in a multiple selection. (I hope I'm clear...)
What's the standard way of doing this? Access VBA documentation is somewhat obscure on the net...
Thanks!
I used the technique similar to JohnFx
To trap the Selection height before it disappears I used the Exit event of the subform control in the Main form.
So in the Main form:
Private Sub MySubForm_Exit(Cancel As Integer)
With MySubForm.Form
m_SelNumRecs = .SelHeight
m_SelTopRec = .SelTop
m_CurrentRec = .CurrentRecord
End With
End Sub
Here is the code to do it, but there is a catch.
Private Sub Command1_Click()
Dim i As Long
Dim RS As Recordset
Dim F As Form
Set F = Me.sf.Form
Set RS = F.RecordsetClone
If F.SelHeight = 0 Then Exit Sub
' Move to the first selected record.
RS.Move F.SelTop - 1
For i = 1 To F.SelHeight
MsgBox RS![myfield]
RS.MoveNext
Next i
End Sub
Here's the catch:
If the code is added to a button, as soon as the user clicks that button, the selection is lost in the grid (selheight will be zero). So you need to capture that info and save it to a module level variable either with a timer or other events on the form.
Here is an article describing how to work around the catch in some detail.
http://www.mvps.org/access/forms/frm0033.htm
Catch 2: This only works with contiguous selections. They can't select mutliple non-sequential rows in the grid.
Update:
There might be a better event to trap this, but here is a working implementation using the form.timerinterval property that i have tested (at least in Access 2k3, but 2k7 should work just fine)
This code goes in the SUBFORM, use the property to get the selheight value in the master form.
Public m_save_selheight As Integer
Public Property Get save_selheight() As Integer
save_selheight = m_save_selheight
End Property
Private Sub Form_Open(Cancel As Integer)
Me.TimerInterval = 500
End Sub
Private Sub Form_Timer()
m_save_selheight = Me.selheight
End Sub
I've tried doing something like that before, but I never had any success with using a method that required the user to select multiple rows in the same style as a Windows File Dialog box (pressing Ctrl, Shift, etc.).
One method I've used is to use two list boxes. The user can double click on an item in the left list box or click a button when an item is selected, and it will move to the right list box.
Another option is to use a local table that is populated with your source data plus boolean values represented as checkboxes in a subform. After the user selects which data they want by clicking on checkboxes, the user presses a button (or some other event), at which time you go directly to the underlying table of data and query only those rows that were checked. I think this option is the best, though it requires a little bit of code to work properly.
Even in Access, I find sometimes it's easier to work with the tables and queries directly rather than trying to use the built-in tools in Access forms. Sometimes the built-in tools don't do exactly what you want.
A workaround to the selection loss when the sub form loses the focus is to save the selection in the Exit event (as already mentioned by others).
A nice addition is to restore it immediately, using timer, so that the user is still able to see the selection he made.
Note: If you want to use the selection in a button handler, the selection may not be restored already when it executes. Make sure to use the saved values from the variables or add a DoEvents at the beginning of the button handler to let the timer handler execute first.
Dim m_iOperSelLeft As Integer
Dim m_iSelTop As Integer
Dim m_iSelWidth As Integer
Dim m_iSelHeight As Integer
Private Sub MySubForm_Exit(Cancel As Integer)
m_iSelLeft = MySubForm.Form.SelLeft
m_iSelTop = MySubForm.Form.SelTop
m_iSelWidth = MySubForm.Form.SelWidth
m_iSelHeight = MySubForm.Form.SelHeight
TimerInterval = 1
End Sub
Private Sub Form_Timer()
TimerInterval = 0
MySubForm.Form.SelLeft = m_iSelLeft - 1
MySubForm.Form.SelTop = m_iSelTop
MySubForm.Form.SelWidth = m_iSelWidth
MySubForm.Form.SelHeight = m_iSelHeight
End Sub
There is another solution.
The code below will show the number of selected rows as soon as you release the mouse button.
Saving this value will do the trick.
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
MsgBox Me.SelHeight
End Sub
Use a Global variable in the form, then refer to that in the button code.
Dim g_numSelectedRecords as long
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
g_numSelectedRecords = Me.SelHeight
End Sub
Dim formRecords As DAO.Recordset
Dim i As Long
Set formRecords = Me.RecordsetClone
' Move to the first record in the recordset.
formRecords.MoveFirst
' Move to the first selected record.
formRecords.Move Me.SelTop - 1
For i = 1 To numSelectedRecords
formRecords.Edit
formRecords.Fields("Archived") = True
formRecords.Update
formRecords.MoveNext
Next i
Why not use an array or recordset and then every time the user clicks on a row (either contiguous or not, save that row or some identifier into the recordset. Then when they click the button on the parent form, simply iterate the recordset that was saved to do what you want. Just don't forget to clear the array or recordset after the button is clicked.?
Another workaround to keeping the selection while attempting to execute a procedure - Instead of leaving the datasheet to activate a button, just use the OnKeyDown event and define a specific keycode and shift combination to execute your code.
The code provided by JohnFx works well. I implemented it without a timer this way (MS-Access 2003):
1- Set the Form's Key Preview to Yes
2- put the code in a function
3- set the event OnKeyUp and OnMouseUp to call the function.
Option Compare Database
Option Explicit
Dim rowSelected() As String
Private Sub Form_Load()
'initialize array
ReDim rowSelected(0, 2)
End Sub
Private Sub Form_Current()
' if cursor place on a different record after a selection was made
' the selection is no longer valid
If "" <> rowSelected(0, 2) Then
If Me.Recordset.AbsolutePosition <> rowSelected(0, 2) Then
rowSelected(0, 0) = ""
rowSelected(0, 1) = ""
rowSelected(0, 2) = ""
End If
End If
End Sub
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
rowsSelected
If KeyCode = vbKeyDelete And Me.SelHeight > 0 Then
removeRows
End If
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
rowsSelected
End Sub
Sub rowsSelected()
Dim i As Long, rs As DAO.Recordset, selH As Long, selT As Long
selH = Me.SelHeight
selT = Me.SelTop - 1
If selH = 0 Then
ReDim rowSelected(0, 2)
Exit Sub
Else
ReDim rowSelected(selH, 2)
rowSelected(0, 0) = selT
rowSelected(0, 1) = selH
rowSelected(0, 2) = Me.Recordset.AbsolutePosition ' for repositioning
Set rs = Me.RecordsetClone
rs.MoveFirst ' other key touched caused the pointer to shift
rs.Move selT
For i = 1 To selH
rowSelected(i, 0) = rs!PositionNumber
rowSelected(i, 1) = Nz(rs!CurrentMbr)
rowSelected(i, 2) = Nz(rs!FutureMbr)
rs.MoveNext
Next
Set rs = Nothing
Debug.Print selH & " rows selected starting at " & selT
End If
End Sub
Sub removeRows()
' remove rows in underlying table using collected criteria in rowSelected()
Me.Requery
' reposition cursor
End Sub
Private Sub cmdRemRows_Click()
If Val(rowSelected(0, 1)) > 0 Then
removeRows
Else
MsgBox "To remove row(s) select one or more sequential records using the record selector on the left side."
End If
End Sub