Situation:
I download Attachments from Outlook and import them into Access tables based on a few criteria.
For example, I download following files:
SenderA_A_Timestamp.csv, SenderA_B_Timestamp.csv, SenderB_C_Timestamp.csv, SenderC_A_Timestamp.csv and loads more.
Now I have made a form where the user can, for example, select all type C CSV-Files since a date or just all types, since a certain date.
Cluster, Hosts and Volume represent the File types. The datetime indicates when it was updated last. Cl_Import, Hosts_Import and Volume_Import are the import specification needed for the different files.
Problem:
I now want to add a new type, for example, under Volume and want to have it stay there when I open the Form the next time.
Software:
-Microsoft Access 2016
-SQL queries
-Outlook 2016
-VBA
Create a table called SwitchboardItems.
Add these fields:
ItemNumber (Numeric, Primary Key)
ItemText (Text)
Command (Numeric)
Argument (Text)
ItemNumber should be sequential (use AutoNum if you want).
ItemText is the text as it will appear on the form.
Command indicate what to do when the button is pressed.
Argument is anything pertinent to that option (such as the file name to be opened).
Create a blank Continuous form.
The Record Source is:
SELECT * FROM SwitchboardItems WHERE [ItemNumber]>0 ORDER BY [ItemNumber];
ItemNumber 0 is the heading for the menu so is ignored in the record source.
Turn Data Entry, Allow Additions, Allow Deletions, Allow Edits and Allow Filters to No on the Data tab in the form properties
Add a command button and a textbox to the Detail section of your form.
Give the button the name of Option1 and the textbox OptionLabel1.
The Control Source for the textbox is ItemText.
Add a label to the Form Header name it Label1.
Add the below code to the Form_Open event. It places the menu heading in the form header:
Private Sub Form_Open(Cancel As Integer)
Me.Label1.Caption = DLookup("ItemText", "SwitchboardItems", "[ItemNumber]=0")
Me.Requery
End Sub
Add this code to the form module:
Private Sub Option_Click()
Select Case Command
Case 1
'Add code to set references to Excel, etc...
'Dim wrkbk As Object
'Set wrkbk = workbooks.Open([Argument])
Case 2
MsgBox [Argument]
Case 3
DoCmd.OpenForm [Argument], acNormal
Case 4
DoCmd.OpenReport [Argument], acViewNormal
Case 5
Case 6
DoCmd.Close
Case 7
DoCmd.OpenQuery [Argument]
Case 8
End Select
End Sub
Each Case statement reflects the Command value in the SwitchboardItems table and you should code what you want each to do (open workbooks, close the database, run SQL, etc).
Finally, add this code to the click events for the Option1 textbox and command button:
Private Sub Option1_Click()
Option_Click
End Sub
Private Sub OptionLabel1_Click()
Option_Click
End Sub
Your finished form will look similar to this (I've clicked Other_Import button which displays a message box as Command is 2):
NB: There's a lot more you could add to this - the last updated time as an extra field in the table for example.
Related
I've been curious as to how to accomplish something like this:
tblProject
id
1
2
tblSample
id projectID sampleNumber
1 1 1
2 1 2
3 1 3
tblTests
id testName
1 test1
2 test2
3 test3
tblTestResults
id testID projectID sampleID testResults
1 1 1 1
2 2 1 1
3 3 1 1
I want to output the following into a datasheet:
projectID sampleID testID test1 test2 test3
1 1 1 entry entry entry
1 1 2 entry entry entry
1 1 3 entry entry entry
Test1, Test2, and Test3 are names from tblTests. Is there a way to automatically update the entered items underneath the test name columns? Pivoting will not allow edits. The solutions I came up with are workarounds:
1) Output the pivot into a listbox, double clicking it will load a form that has the tests.
2) Use a gridview. Load the headers: projectID, sampleID, and test names. In an array, keep track of the test name column and which testresult id it belongs to. AFter update, manually update the field.
Is there a better method?
Thank you
Starting with Access 2002, Microsoft upgraded Access forms to substantially improve their ability to present data in a pivot-table format. These capabilities build on features initially introduced in Access 2000 for Office Web Components.
Programmatically creating a pivot table
Before starting to program pivot tables for Access forms, you need a reference to the Office Web Components library (owc10.dll). In Access 2002/2003, the library file is available in the \Program Files\Common Files\Microsoft Shared\Web Components\10 path. In Access 2002, the Microsoft Office XP Web Components item doesn't appear in the References dialog box. Therefore, you must know the path to the library file (owc10.dll) so that you can browse to it when specifying a reference.
Creating a pivot table programmatically for an Access form can require several steps:
First, you need to create a form that will hold your pivot table. You can do this with the CreateForm method.
Next, you'll typically want to change the default name assigned to the form by the CreateForm method. This practice lets your Access form name reflect its role in an application.
Finally, you need to configure the active view for a pivot table on an Access form so that it organizes the data to display into appropriate row, column, and filter axes. You do this by assigning column names from an Access table or query to axes for the active view of a pivot table.
The Office Web Components object model uses terms such as RowAxis and ColumnAxis to designate axes for an active view. Any data to be organized belongs on the DataAxis of an active view. You can designate multiple columns of data as belonging to row, column, filter, and data axes.
Creating a pivot table based on a table
The Access file with the samples for this article is available to download here. The file contains a form, named frmPVTDesigner, with five buttons. The top button, labeled Make Orders PivotTable, creates a simple pivot table based on the Orders table imported from the Northwind.mdb file. The pivot table (see the left pane in this [image]2) categorizes OrderID by ShipCountry. The code behind the button saves the pivot table in the pvtOrders form. After invoking the click event procedure for the button, you need to delete the pvtOrders form before you can re-run the click event procedure (or change the code in the event procedure so that it saves the new form with a different name).
With a pivot table like the one in the left pane this [image]2, an analyst can display a count of the number of orders for each ShipCountry. The right panel in this [image]2 shows that there are 16 orders with a ShipCountry column value of "Argentina". Users can generate this subtotal by right-clicking the OrderID column heading in the pivot table and choosing AutoCalc > Count. In addition, by clicking the Hide Details button on the PivotTable toolbar, users can elect to suppress the display of the individual OrderID values so that just the counts appear.
By calling three other procedures, the Click event procedure for the top button creates a form for the pivot table, assigns the custom name pvtOrders to the form, and configures the pivot table. The application uses a couple of module-level variables, strFormName and strRecordSource:
Sub CreatePivot()
Dim strFormName As String
Dim strRecordSource As String
Private Sub cmdOrdersPivotTable_Click()
Dim strDefaultName As String
strRecordSource = "Orders"
strDefaultName = CreatePivotTable
strFormName = "pvtOrders"
If (AssignPivotTableName(strDefaultName, _
strFormName)) = False Then
Exit Sub
End If
ConfigureOrdersPivotTable
End Sub
The CreatePivotTable function procedure called from this code creates a new form with a RecordSource property setting equal to strRecordSource, one of the two module-level variables. You must assign a record source for a form before attempting to configure a pivot table on the form. The CreatePivotTable procedure assigns a value to the form's DefaultView property so that the form opens with a PivotTable view when a user opens the form from the Database window. This DefaultView setting doesn't impact how the OpenForm method of the DoCmd object opens the form.
The CreatePivotTable routine returns to the cmdOrdersPivotTable_Click routine the name of the new form. This name has the format Formn, where n is an integer value. After CreatePivotTable saves the form's settings and closes the form, cmdOrdersPivotTable_Click passes the default form name and a custom form name to AssignPivotTableName, which is another one of my functions. This function assigns a new custom name to the form for the pivot table unless the custom form name already belongs to another form in the database file. A For...Each loop searches through the members of the AllForms collection to determine whether another existing form already has the name for the new form. When the new custom form name already belongs to an existing form, the function procedure deletes the form created by CreatePivotTable and returns a value of False to indicate that it didn't rename the form. In this situation, cmdOrdersPivotTable_Click terminates the application. Otherwise, the AssignPivotTableName procedure successfully renames the new form and returns a value of True to cmdOrdersPivotTable_Click:
Function CreatePivotTable() As String
Const acFormPivotTable = 3
Dim frm1 As Access.Form
Set frm1 = CreateForm
frm1.DefaultView = acFormPivotTable
frm1.RecordSource = strRecordSource
CreatePivotTable = frm1.Name
DoCmd.Close acForm, CreatePivotTable, _
acSaveYes
End Function
Function AssignPivotTableName _
(strDefaultName As String, _
strFormName As String) As Boolean
Dim acc1 As AccessObject
AssignPivotTableName = True
For Each acc1 In CurrentProject.AllForms
If acc1.Name = strFormName Then
MsgBox "Choose a form name other " & _
"than '" & strFormName & "' that " & _
"does not match an existing form."
AssignPivotTableName = False
DoCmd.DeleteObject acForm, strDefaultName
Exit Function
End If
Next acc1
DoCmd.Rename strFormName, acForm, _
strDefaultName
End Function
After the application creates a form and assigns a custom name to it, the ConfigureOrdersPivotTable procedure assigns columns from the form's RecordSource setting to axes of the active view for the pivot table on the form. CreatePivotTable and AssignPivotTableName can be reused when creating any form for a pivot table, but the procedure for configuring a pivot table will typically be unique for each pivot table.
The configuration procedure initially opens the form for which it specifies a pivot table. Next, it uses a With...End With statement to point at the ActiveView object for the PivotTable object on the form. Inside the With...End With statement, the procedure successively assigns columns (in this case, ShipCountry and OrderID) to a PivotFieldset object (fst1). The code inside the With...End With statement inserts the PivotFieldset in an axis for the ActiveView object. ConfigureOrdersPivotTable assigns the PivotFieldset with the ShipCountry column to the RowAxis property of the ActiveView and the PivotFieldset with the OrderID column to the DataAxis property of the ActiveView:
Sub ConfigureOrdersPivotTable()
Dim fst1 as PivotFieldset
'Open form in PivotTable view and set
'a reference to the form
DoCmd.OpenForm strFormName, acFormPivotTable
Set frm1 = Forms.Item(strFormName)
'Set PivotTable fieldsets
With frm1.PivotTable.ActiveView
Set fst1 = .FieldSets("ShipCountry")
.RowAxis.InsertFieldSet fst1
Set fst1 = .FieldSets("OrderID")
.DataAxis.InsertFieldSet fst1
End With
'Close form with its PivotTable view
DoCmd.Close acForm, frm1.Name, acSaveYes
End Sub
See:
More information on this example is available at the Source.
MSDN: Form.PivotTable Property (Access)
Stack Overflow: Edit pivot table contents in Access
I prefer in such kind cases to use temporary tables. Copy pivot data to temp table and return back edited data after clicking Save button, few simple queries will do the job
My management wants an access database that can have a way to control which users can see specific fields on a form. For example, if a manager logs in, a form will display the performance rating field. For any other user, the performance rating field will not be visible.
So far the below are some of my options:
1) Use VBA to detect the User Name of the access application and if its Manager's name, then the textbox is visible.
2) Use a username reference table that requires users to login. Users with special access will have the textbox visible.
3) Have a special little button on the form that, if someone clicks, will load a small password dialog and then set the text visible.
Which option would be the most difficult to implement?
The idea of using a Login form for user specific information is something that is available all over the internet. I would suggest a combination of all three of your ideas would be just the perfection solution.
For either of the two methods you have (1 & 2) you first need a Table that will hold the information. The table does not need to be complex (at least not right away). The table should be of the following structure,
tbl_Employees
-------------
EmpID - Auto Number - PK
EmpNam - Text
EmpUserName - Text
EmpPassword - Text - Input Mask (If required)
IsManager - Yes/No - Default - No
Then you will have to create a Form, a basic form that will have three controls, two Text Boxes and one Button. The first text box is where you will enter the Employee User name and the second for Password. Finally a button, behind which the magic happens. The code (simplified) behind the button would be something along the lines of.
Private Sub LogInBtn_Click()
On Error GoTo errOccured
Dim eQryStr As String, empRS As DAO.Recordset
eQryStr = "SELECT EmpID, EmpUserName, EmpPassword, IsManager FROM tbl_Employees WHERE EmpUserName = '" & Me.UserNameTxt & "'"
Set empRS = CurrentDb.OpenRecordset(eQryStr)
If empRS.RecordCount <> 0 Then
If Me.PwdTxt = empRS!EmpPassword Then
If empRS!IsManager Then
DoCmd.OpenForm "ManagerForm"
Else
DoCmd.OpenForm "EmployeeForm"
End If
Me.Visible = False
Else
wrongEntry "Password"
End If
Else
wrongEntry "User Name"
End If
exitOnError:
Set empRS = Nothing
Exit Sub
errOccured:
wrongEntry "User Name/Password"
Resume exitOnError
End Sub
Private Sub wrongEntry(entityStr As String)
MsgBox entityStr & " is incorrect (OR) omitted, please check again.", vbCritical
End Sub
As you can see, I have used
(a) A Recordset object than a simple DLookup. I prefer recordset object, you can use a DLookup, but you have to make sure you handle Null (if the criteria is not met).
(b) A separate Form for Managers and Employees. I imagined there would be a lot more on a managers form that is not available on a Employee form. If you do not wish to go this way, but use one form you can, but you need to inform the opening form of who is logging in - Using the OpenArgs property of the OpenForm method.
Just if you feel to simply avoid all the hassle and use an Password box, to get the access of the TextBox. Simply follow the instructions on this thread - Password Box - A variant of Input Box. Then create a button on the form you currently have, then on click of the button, you simply code the following.
Private Sub AllowAccessButton_Click()
If Call_Password_Box = "yourPassword" Then
Me.yourHiddenTextBox.Visible = True
Else
MsgBox "Sorry you are not authorised to vies this information (OR) Incorrect Password", vbCritical
End If
End Sub
PS: The Hidden text control should be set to invisible, preferable in the Form current event.
I hope this helps.
I've implemented option nr 1 and 2, they we're quite easy to build.
option nr 3 seems equally difficult.
The question within my work environment would be which option would be low in (account)maintenance and which would demand little effort from the users.
From that view option nr.1 has been more successfull.
(And i would rather build different forms in stead of turning the view setting of field ON/OFF)
We have an Access 2010 database that acts as a front-end to a MS SQL database. When we edit data in the form there is a procedure that needs to run in order to properly save certain data back to SQL.
Our DB programmer added a "Save Button" to do this. But that causes another problem - there are multiple ways in Access by which to save a form -
Navigate to the next record
Click on the Confirmation bar on the left
Create a new record
Search for a new record
Use commands in the ribbon
Is there any way to attach a procedure the actual save action so that no matter how a person moves to a next form that the procedure gets run?
[update]
Here is the code behind the scenes: the first sub is attached to the "Save" Button. Of course, the second is attached to the form BeforeUpdate.
Private Sub SaveRecord_Click()
'From NAME form
Form_BeforeUpdate False
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
'used by NAME form
[Last_Update] = Now
'*********************
Save_Record
'*********************
MName_ID = Me.Name_ID
Me.Undo
Cancel = True
If Not IsNull(MName_ID) Then
Jump_to_Name_ID MName_ID, True
Else
End If
End Sub
I guess I just don't understand what the button is for.
So I installed an MS Access 2010 trial and finally managed to figure out a way to solve your problem. It includes data macros and a hidden gem that took me quite a while to find.
Here's how you run VBA when a table changes:
Create an ordinary module (haven't tried class modules) with public functions:
Module name: EventHandlers
Public Function InsertEvent(ByVal id As Integer)
MsgBox "inserted: " + CStr(id)
End Function
Open the table that, when modified, should run VBA and go to "Table" in the ribbon.
Click on "After Insert"
In the "Add New Action"-select box, choose SetLocalVar (or select it from the Action Catalog).
In the Name-field, insert the name of the module (in this case, EventHandlers, as we created earlier)
In the Expression-field, write the name of the function: InsertEvent([id]) (where [id] is an actual column in the table you're adding a data macro for)
Save and close
Whenever something is inserted to the table, a messagebox will be shown with the id.
You could do the same with the update event. The function could be something like this:
Public Function UpdateEvent(ByVal oldValue As String, ByVal newValue As String)
MsgBox oldValue + " changed to: " + newValue
End Function
and the data macro would be
Action: SetLocalVar
Name: EventHandlers
Expression: UpdateEvent([Old].[your_column_name];[your_column_name])
Note: Executing DoCmd.RunSQL with update, insert or delete will execute data macros and THEN ask the user if he or she actually WANTS to update/insert/delete the row. If the user clicks cancel, nothing is changed but your data macro executed anyway. If you haven't already, you should probably disable this check before implementing data macros.
Well, I was not able to use Mr. Sommer's solution because it was not possible to add an event handler to a linked table on account of their being read-only. But, I did work out a simple procedure that seems to work well enough.
So, I was actually already using the BeforeUpdate event, so I'm catching the right event here - this is the event that traps the save, whether it be on change of navigation or the save-record bar on the left. However, there were a few issues that resulted from using Application.Echo False to keep Access from posting back the old data to the control whilst the Me.Undo takes place.
So we use cancel=true to prevent the BeforeUpdate event from doing its normal processing, and we use Me.Undo to prevent Access from trying to save data to the linked tables.
Private Sub Form_BeforeUpdate(Cancel As Integer)
Cancel = True
[Last_Update] = Now
'*********************
Save_Record '-->This will save the data back to SQL
'*********************
MName_ID = Me.Name_ID
Application.Echo False 'don't show the undo in the controls
Me.Undo
If Not IsNull(MName_ID) Then 'used for the navigation buttons
Jump_to_Name_ID MName_ID, True
Else
End If
Application.Echo True 'turn the control refresh back on
Me.Repaint
End Sub
I have an Access 2002 database/application where my clients can enter multiple information about their own clients, including a code which follow some rules.
However, when they view these information after they have been entered, I need to hide every characters in this code except for the 4 last characters. However, the agent needs to be able to edit this code if it needs to be modified.
So basically, I have 3 phases possible:
First time information are filled, empty data. The field must show the characters entered.
At a later date, the code must be hidden in some way to show only the last 4 characters. It can be with * or simply the last 4 characters, but the user must not be able to see what is before these.
The agent edit the code, the code must then be properly modified in the database. The characters must be shown.
I tried to show only the 4 last characters, however my database gets modified... So the code gets cut in the database.
I wrote the following function to obscure sensitive data. Its primary use is to discourage shoulder surfing. I'm not sure if it will meet your particular needs, but it is simple, straightforward and may help others who stumble upon this question.
'Use to hide data in sensitive fields (e.g., BirthDate, PhoneNum, SSN)
'Usage: Ctl OnEnter property: =ObscureInfo(False, Form.ActiveControl)
' Ctl OnExit property: =ObscureInfo(True, Form.ActiveControl)
' Form Open property: =ObscureInfo(True, [BirthDate], [HomePhone], [SSN])
Function ObscureInfo(HideIt As Boolean, ParamArray Ctls() As Variant)
Dim Ctl As Variant
For Each Ctl In Ctls
If HideIt Then
If IsNull(Ctl.Value) Then
Ctl.BackColor = vbWhite
Else
Ctl.BackColor = Ctl.ForeColor
End If
Else
Ctl.BackColor = vbWhite
End If
Next Ctl
End Function
Wow - I'm shocked that this hasn't been answered sufficiently. The best answer is to use an unbound text box in your form instead of a bound one. First you'll need to make your unbound text box populate the actual field. You'll do that in the AfterUpdate event.
Private Sub UnboundTextBox_AfterUpdate()
[MyField] = Me.UnboundTextBox
End Sub
Then you'll need to set an OnCurrent event to populate your unbound text box with the protected view whenever the agents view the record:
Private Sub Form_Current()
Me.UnboundTextBox = String(Len([MyField])-4, "*") & Right([MyField], 4)
End Sub
However, you also want to let your agents edit or view the full code later, if necessary. The best way to do this would be to set the OnEnter event for your unbound text box to pull the whole field value, so the agent can see and edit it - effectively the reverse of your OnUpdate event.
Private Sub UnboundTextBox_Enter()
Me.UnboundTextBox = Nz([Field1]) 'The Nz deals with Null errors
End Sub
I've used this with a field displaying SSN's and it works like a charm.
I have a form in an MS Access database which lists Orders with an Order Number with one order per page. At the bottom of the form there is a button which opens another form, to add an item for the order.
I am trying to use vb in MS Access to take the order number and automatically put it in a field in the details form for the new item. I have tried different ways but using OpenArgs seems to be recommended. But the detail form won't open and I get run-time errors.
Here are the details of the problem - advice will be much appreciated:
The forms and field concerned are:
Form with orders is frmPedidoAvifiFind
Form with order-lines for one order is frmPedidoAvifi-dtlAdd (a separate form for adding details but not for viewing existing ones).
Field on both forms for Order Number is PedidoAvifiNo. This is a numeric field in both tables which are linked by a one-to-many relation via this field.
Main form: Button bring up detail form, code as follows:
Code on main form button:
Sub AddDetails_Click()
Dim strDocName As String
strDocName = "frmPedidoAvifi-dtlAdd"
' Open frmPedidoAvifi-dtl form in data entry mode and store PedidoAvifiNo in the form's OpenArgs property.
DoCmd.OpenForm strDocName, , , , acFormAdd, , [frmPedidoAvifiFind]![PedidoAvifiNo]
End Sub
Detail form: On Open property
Private Sub Form_Open()
If Me.OpenArgs <> vbNullString Then
Me.PedidoAvifiNo = Me.OpenArgs
End If
End Sub
Test 1: select an order number on main form so that record shows.
Press button to add orderline. - run-time error '2465' can't find the field "|" referred to. Debug highlights the DoCmd line.
Test 2:
Change openform line to:
DoCmd.OpenForm strDocName, , , , acFormAdd, , Me.PedidoAvifiNo
result: - run-time error 2501 the openForm action was canceled.
Thank you,
Mike Gunner
Reus, Spain
The error you are getting means that you have misspelled the name of the control PedidoAvifiNo.
When you type Me. intellisense will give you a list of available fields, see what you have that is similar to PedidoAvifiNo, or check the properties. It can be very easy to switch one letter and not notice.
As for the second part, you should use the Load event, rather than the Open event on frmPedidoAvifi-dtlAdd, because the controls are not yet available in the Open event.