Check which tab is clicked / Active in a MS Access form - ms-access

I have created a form in MS Access 2011 in which there are a tab control on top named TabCtl18 in which 3 tabs are page1, page2, page3.
Under the page1 tab there are another 3 other tabs page11, page22, page33, under three tabs there are 3 reports respectively
Now I want that when a user clicks on pdf icon it check which tab has clicked and print that report.
My Code :
Private Sub cmdPrintReportPDF_Click()
If TabCtl18.TabIndex = 0 Then
If tab_graph.TabIndex = 0 Then
DoCmd.OpenReport "Graph_report", acViewNormal
DoCmd.OutputTo acOutputReport, "Graph_report"
DoCmd.Close acReport, "Graph_report"
End If
Else
If tab_graph.TabIndex = 2 Then
DoCmd.OpenReport "Graph_Report_FieldShifts", acViewNormal
DoCmd.OutputTo acOutputReport, "Graph_Report_FieldShifts"
DoCmd.Close acReport, "Graph_Report_FieldShifts"
End If
End If
End Sub

Based on issue highlighted by #David, here is the way to check name of the TabPage selected.
if tabControl1.Pages(tabControl1.Value).Caption = "TabPageName" then
'Do Something
end if
Moreover, You can use this code in Tab Control Click Event to check which Page is active.

The Value (which is the default) property of the tab control is the index of the page with the focus. It starts with zero.
If TabCtl18.Value = 0 Then
'this must be the first page

Similar to #adarsh marecha, but I suggest using the TAG property of the page - using index may not work as intended if the page order gets changed. Also, tabs names can get changed too, which may mean the code fails.
If you set the TAG property to the required value it is likely only you will use it, and it will thus be less likely to fail due to DB changes.
So my code becomes:
With Your_Form
If !tabControl.Pages(!tabControl.Value).Tag = "Your tag" then
'Do Something
End if
End With

Related

MS-Access: Populate modal form from custom type

I am trying to display an error form, populated with text from a custom type object, as a MS-Access version of the fantastic answer on this Excel question.
The problem I run into is that I want to wait for a user response/confirmation on this error form, so it must be (as far as I am aware) a modal form and therefore I cannot just open the form and immediately populate it.
I have tried to find a way of doing in Access what was done in Excel; load the form, populate the form then display the form, but this doesn't seem possible since Access' event order is Open->Load->...
I have also tried looking for a way to open as a normal form, populate and then 'modalise' the form but could not find a way to do this.
Does anyone know of a way to achieve this function? Or is there an alternative to modal forms to pause execution awaiting user input?
A modal form is VERY different from a dialog form.
Modal forms do NOT cause the calling code to halt, but a dialog form does.
(do not confuse the two types of forms).
To “get back” a user response from a dialog form, simply set the form visible = false in place of a close form command. This will KICK the dialog form out of dialog mode, and your calling code now continues and the calling code is “free” to examine any values the user typed in or say choose from combo boxes, or check boxes, or whatever.
So your code block will look like this:
Private Sub Command0_Click()
Dim f As String
Dim strT As String
f = "formB"
DoCmd.OpenForm f, , , , , acDialog
If CurrentProject.AllForms(f).IsLoaded Then
' grab any values entered by user, or whatever buttons hit
strT = Forms(f).Text1
' etc. etc. etc. - grab values from that form
' don't forget to close the form
DoCmd.Close acForm, f
Else
' user canceled the form
' code goes here for user hitting your cancel button or "x"
End If
End Sub
And in your dialog form, the “ok” button, or “close” button simply goes:
Me.visible = False
If the user hits your cancel button, that code would be:
Docmd.Close acForm
So if the user hits “cancel” or even the “X” in the upper right corner, you consider and assume the user “bailed out”. When they do this, the form will be closed.
So the code after the dialog part simply checks if the form is STILL open (because your “ok” button does a visible = false).
And since the form is STILL open, then you are free to grab the values of ANY control – say user text typed into a text box, values from a combo box, check box, or whatever.
When user is done the calling code is free to examine or grab any value(s) from that form.
Edit - 2nd solution to allow "setting" of values.
This code will work:
Private Sub Command0_Click()
Dim f As String
Dim strT As String
f = "formB"
DoCmd.OpenForm f
Forms(f).Text1 = "Hello" ' set values on form
' now WAIT for user
Do While CurrentProject.AllForms(f).IsLoaded
If Forms(f).ok = True Then Exit Do
DoEvents
Loop
If CurrentProject.AllForms(f).IsLoaded Then
If Forms(f).ok = True Then
MsgBox "value return = " & Forms(f).Text1
Else
MsgBox "user cancel"
End If
DoCmd.Close acForm, f
Else
' cancel code goes here
MsgBox "user cancel"
End If
End Sub
The code for the OK button on the form B is now:
Me.Visible = False
Me.ok = True
And you need a public var "ok" in form B.
eg this:
Option Compare Database
Option Explicit
Public ok As Boolean
So the cancel button in form B can simply close the form. (you can close the form - but don't set ok = True)

Access Form Bring Text Box in Front of Listbox?

This application is Access 2010, with a SQL backend.
I have a form, which has a tab control, with 2 pages. 1 page has 1 listbox and the other has 2 listboxes. I use some code, on change of the tab control, to determine the active page, and set the listbox(es) row source(s) for the one(s) on the active page, and clear it out on the inactive page. This takes a sec and the listboxes look yucky while this is happening.
To prevent the user from seeing this, I made a text box, with a colored background and the control source ="Please Wait One Moment..."
with like 48 font. On load of the form, this textbox is visible = false. On click of the tab control, the text box is to be made visible, and it is big enough to cover then entire tab control. It does cover the tab control, but I can still see the listboxes through the text box. The text box has a back color and is not transparent. I tried right-clicking the listboxes in design view and choosing Position - Send to Back, and right-clicking the textbox and choosing Position - Send to Front.
This doesn't seem to work. Is anyone familiar with this issue? Figuring someone has tried a trick like this.
The meat of my code is all functioning properly, for this on change of the tab control. I have this code at the beginning:
DoCmd.Hourglass True
Me.txtPleaseWait.Visible = True
Me.Repaint
Application.Echo False
Debug.Print Me.txtPleaseWait.Visible
and this at the end:
Application.Echo True
Me.txtPleaseWait.Visible = False
Me.Repaint
Debug.Print Me.txtPleaseWait.Visible
DoCmd.Hourglass False
Debug.Print "got to end of resting form state"
Does that make sense?
Should I handle this differently?
Thank you.
Edit
I found that listboxes have a higher zorder than textboxes, so I changed my textbox to a listbox. I still see the listboxes from the tab control, through the listbox I'm using to cover them up.
Is there a control that would better cover these and could have this "intermission" type message show, while the listboxes are being set and unset?
I researched different aspects of this, and found the listbox has a higher zorder than text boxes, which is position front or back relative to other objects. I tried just doing this onload of the form, and there wasn't time to hide anything. It just waited to load the form, until the rowsources were set.
Since the find tab is the default one, and quicker to load, I just load that on load. Then, if someone clicks on the other tab, I will load the add listboxes. I also set an integer variable to 0 on load of the form. When I click on the tab to go to the add page (add page is active), I check that variable, and if it is 0, I set the row source, and then +1 to the variable. Next time I click on it, I don't re-order it.
This way, I'm not using resources to load and unload the listboxes, and I only load 2 of them, if the user even goes to that tab. Many times, they might just be looking for one in the system, and going to view it.
Here is the full code, in case this method helps someone else. You could also make the variable boolean, and just set it to true, and then false.
Option Compare Database
Option Explicit
Dim AddLoaded As Integer
Property Get ActivePage() As Access.Page
'PROPERTY TO IDENTIFY WHICH TAB WE ARE ON, FOR FILTERING AND IDENTIFYING WHICH ACTIVE LISTBOX TO LOOK AT, FOR VALUES AND ACTIONS
With Me.tbAddFind
Set ActivePage = .Pages(.Value)
End With
End Property
Private Sub Form_Load()
Dim Listctrl As Control
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Dim cSQL As String
AddLoaded = 0
For Each Listctrl In Form.Controls
If (Listctrl.ControlType = acListBox) Then
With Listctrl
.RowSource = ""
End With
End If
Next Listctrl
Me.tbAddFind.Value = 0
cSQL = "SELECT vw_CMP_Projects.CM_CID, [vw_CMP_Projects]![ProjectName] &" & Chr$(34) & " (" & Chr$(34) & "& [vw_CMP_Projects]![ProjectNo] &" & Chr$(34) & ") " & Chr$(34) & " AS Projects FROM vw_CMP_Projects ORDER BY [vw_CMP_Projects]![ProjectName] &" & Chr$(34) & " (" & Chr$(34) & "& [vw_CMP_Projects]![ProjectNo] &" & Chr$(34) & ")" & Chr$(34)
Me.lstProjects.RowSource = cSQL
Me.lstProjects.Requery
End Sub
Private Sub tbAddFind_Change()
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Select Case Me.ActivePage.Name
Case "pgAddProjects"
If AddLoaded = 0 Then
cmd.ActiveConnection = GetCatalog()
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "sp_RefreshProjectsAdd"
cmd.Execute
Me.lstAllProjects.RowSource = "Select * From qryAddProjectsYes"
Me.lstAllProjects.Requery
Me.lstAddProjects.RowSource = "Select * From qryAddProjectsNo"
Me.lstAddProjects.Requery
AddLoaded = AddLoaded + 1
End If
End Select
End Sub
Thanks for the discussion. It was helpful, as it gave me things to research.

Tab control in VB

I'm working on a legacy VB6 application. I'm sure this probably relates to VB.NET so i will tag it, but please let me know if it's completely different(which I dont think it is) then I'll remove the tag to avoid confusion.
Here is my issue....
I have a Tab control with multiple tabs: 0 - 3. On TabStuff.Tab = 0, I have a few textboxes and comboboxes. The user uses keyboard TAB to move from Indexed controls. What happens is once they get to the last control which is a textbox called txtCity - and click keyboard TAB once more, it brings them to TabStuff.Tab=1.
My issue is I do VALIDATE on txtCity - I call a function that verifies that a couple of the fields aren't NULL and if one of the fields is in fact NULL then I show a MSgBox and try to setFocus on that control. But instead, when OK is clicked on msgbox, it goes to the next tab which is TabStuff.tab=1 which is not correct.
Here's some of my code...
Dim FirstName, City as String
flag=false
firstName = txtName.text
city = txtcity.text
if FirstName="" or isnull(FirstName) then
msgbox "Please enter Name"
tabstuff.tab=0
txtname.setfocus
exit sub
elseif city = "" or isnull(city) then
msgbox "Please enter city"
tabstuff.tab=0
txtcity.setfocus
exit sub
end if
flag=true
This code is in txtCITY_VALIDATE
So in case city was empty, it shows MsgBox, stays on Tab=0 and setfocus on that control, but instead it goes to the next tab=1 and sets focus on the first control of that tab.
EDIT:
in txtCITY_LostFocus
If Flag = False Then
TabStuff.Tab = 0
Exit Sub
End If
I added this but it still goes to tabstuff.tab=1 setting the focus on first control of the tab
EDIT 2:
In a new project i created txt1 and txt2 - i set TabIndex 0 and 1 respectively.
Private Sub Txt1_Validate(Cancel As Boolean)
If Txt1.Text = "" Then
MsgBox "no text in txt1"
Txt1.SetFocus
End If
End Sub
This is the code I use. I click TAB on txt1 without entering any text, so this gets executed, but after msgbox, the focus gets set on txt2
For some extremely weird reason - i seem to have been getting this discrepancy because I was doign it in the VALIDATE property. When i entered the same code in LostFOCUS it seems to work fine. Thanks everyone for your help with this!

VBA Detail Shortcut Menu

I am updating some old VBA code to work with Access 2010. One problem we encountered is that no Shortcut Menu appears when you right click so we create a shortcut menu and bound it to the Application object like so...
Application.ShortcutMenuBar = "GeneralClipboardMenu"
In general this works however if you right click on a column in a Detail pane, "Which we are using as an excel grid", no menu appears. This aspect is critical to the use of our application so we can not ignore it.
Nowhere in the code are Shortcut Menus being disable. Also I realize shortcut menus are being replaced by the ribbon in the 2010 Office suit however right click is a basic feature that we would ideally like to keep.
Any help would be greatly appreciated. Here is the code for creating the shortcut menu in-case it is relevant.
Sub CreateSimpleShortcutMenu()
On Error Resume Next 'If menu with same name exists delete
CommandBars("GeneralClipboardMenu").Delete
Dim cmb As CommandBar
Set cmb = CommandBars.Add("GeneralClipboardMenu", msoBarPopup, False, False)
With cmb
.Controls.Add msoControlButton, 21, , , True ' Cut
.Controls.Add msoControlButton, 19, , , True ' Copy
.Controls.Add msoControlButton, 22, , , True ' Paste
.Controls.Add msoControlButton, 4016, , , True 'Sort Ascending
.Controls.Add msoControlButton, 4017, , , True 'Sort Decending
End With
Set cmb = Nothing
End Sub
I believe the Application-wide Shortcut Menu bar is a DAO database property. You can change it in the GUI under Access Options > Current Database > Ribbon and Toolbar Options.
You can also change it using the following code:
UpdateCustomProperty("StartupShortcutMenuBar", "NameOfMyCustomShortcutMenuBar")
Private Function CreateCustomProperty(ByVal sPropertyName As String, _
ByVal sPropertyValue As String)
On Error Resume Next
If sPropertyName <> "" And sPropertyValue <> "" Then
Dim p1 As DAO.Property
Set p1 = CurrentDb.CreateProperty(sPropertyName, DB_TEXT, sPropertyValue)
CurrentDb.Properties.Append p1
Set p1 = Nothing
End If
End Function
Public Function UpdateCustomProperty(ByVal sPropertyName As String, _
ByVal sPropertyValue As String)
On Error Resume Next
If sPropertyName <> "" And sPropertyValue <> "" Then
CurrentDb.Properties(sPropertyName) = sPropertyValue
If Err.Number = 3270 Then
Err.Clear
Call CreateCustomProperty(sPropertyName, sPropertyValue)
End If
End If
Err.Clear
End Function
Actually I discovered a workaround that is satisfactory. The only reason we needed to be able to right click a column was for sorting. Using the code I initially had when you right clicked a cell the sort options where grayed out. However it appears there are several id's for sort commands and they all have different functionality.
http://support.microsoft.com/kb/159466
The above link has a list of available id's for shortcut menus.
I am fairly sure there is no way to add right click functionality to entire columns in 2010 detail panes. Nowhere was I disabling menus I did a through search for any commands capable of doing that as well as triple checking my properties.
One possibility is that Shortcut Menu is set to "No" in the form properties. You can access these by viewing the form in design view, then viewing Form Properties, and checking the "Shortcut Menu" setting. It should be set to "Yes."

How can I change the view of an MS Access subform at runtime in VBA code?

This seems like it would be a simple affair, and I am sure I have done this before, but it has been a while since I have done any UI programming in Access. What I need to do is put a button on a form to toggle between datasheet and form view for a subform.
I have found a defaultview property, but nothing that looks like it would toggle the view of the form after it is already open.
Essentially I need the property I can fill in the following code..
sfEmployeeBatchEntry.Form.??? = acFormDS
I found it on my own. I was missing it because it used the silly and clunky RunCommand syntax instead of a simple property or method on the control or form classes.
It ain't pretty, but for posterity, here is the answer.
'You have to set focus to the subform control or the change view call will'
'fail (UGH!)'
MyForm.mySubFormControl.SetFocus
'Change to datasheet view...'
DoCmd.RunCommand acCmdSubformDatasheet
'Change to Form View...'
DoCmd.RunCommand acCmdSubformFormView
I tried a number of different solutions I found on different sites. Some seemed unnecessarily complicated. I cleaned out some of the clutter and found this fits my needs the best.
Dim intView As Integer
intView = Me.Form.CurrentView
If intView = 1 Then
DoCmd.RunCommand (acCmdSubformDatasheetView)
Else
DoCmd.RunCommand (acCmdSubformFormView)
End If
Exit Sub
To Toggle the View of a subForm between Continuous and Datasheet, use this code:
Private Sub cmdToggleView_Click()
If Me.frmViewDetailedTransactionsSub.Form.CurrentView = 1 Then
Me.frmViewDetailedTransactionsSub.SetFocus
DoCmd.RunCommand acCmdSubformDatasheetView
Exit Sub
End If
If Me.frmViewDetailedTransactionsSub.Form.CurrentView = 2 Then
Me.frmViewDetailedTransactionsSub.SetFocus
DoCmd.RunCommand acCmdSubformFormView
Exit Sub
End If
End Sub