Modal form SetFocus not selecting control - ms-access

Objective: Show a programmatic modal form with the appropriate control initially selected and ready for user input or interaction.
Code:
Dim frm As Form
Set frm = New Form_Popup_Sign
With frm
'Show window and SetFocus appropriately
.Visible = True
!CommandCancel.SetFocus
'.Modal = False: .Modal = True
'Loop until response (change in form.visible state) is received on popup
'User clicking Cancel or Sign sets .Visible = False
Do While .Visible
Sleep 1 'Sleeping makes CPU effect negligible
DoEvents
Loop
'Return popup_sign handle and leave form open to expose results
load_Popup_Sign = frm.hWnd
End With
' Form is destroyed later
Results:
The target control's GotFocus event DOES fire.
The form appears but appears to have nothing focused (selected).
In the forms pictured below, when the user clicks Cancel or Sign, Form_Popup.Visible is set to False, allowing the code execution to continue.
What appears (highlighted but not selected)
What I expect (button selected, user can hit enter or space to push button)
Things I've Tried
The following workarounds make the SetFocus'd control get focused:
Modality is programmatically turned on and off (see commented code line)
I would like to not need to do this
Interestingly, if form is saved as not modal and then modal is turned on at the line noted above, this no longer works. Weird.
Manual user actions:
Clicking the Header form section background
Alt-tabbing or clicking away to another app and back
Things that don't work:
Setting focus multiple times
Setting focus to form itself (which modality should do by default)
Setting focus to different control types (which is my actual intent), e.g. textboxes
Do not appear selected and cannot immediately type text in like when focused normally
Tabbing interestingly shifts "focus" but never selects the controls which have "focus".
Buttons "focused" in this manner have the peripheral highlight but no "selected" indication (thin dotted line around caption).
Textboxes and listboxes "focused" in this manner have no indication they have been tabbed to and cannot be typed into.
Setting TabIndex for the desired control to 0 and both selecting nothing or that control.
References:
MSDN VBA Form.Modal property
MSDN VBA SetFocus method

Related

Unexpected Tab key behavior in Datasheet form subdatasheet

When I tab through records in my (datasheet) form, the tab key behavior is as expected; Focus moves to the next field, and then at the end of the fields moves to the next record. In forms where I have master-child subdatasheets, when the subdatasheet isn't expanded and the user tabs past the end of a record, focus moves to the next record. This is good / what I want. When a subdatasheet is expanded and the user tabs past the end of the master record, focus moves to the first field in the child subdatasheet. Again this is good / what I want.
What happens on the next tab key press is my issue. Rather than moving focus to the next field in the subdatasheet, focus goes straight to the next record in the master datasheet. I expect and want focus to go to the next field in the subdatasheet.
I have been playing with the tabstops and cycle properties on both the main form, subform, and subform control within the main form, and cannot come to a configuration where I get the behavior I desire.
Solved this now and thought I should log it here. Was a pretty stupid problem caused by an oversight on my part.
Basically, all of the controls on my subdatasheet were being set to locked and tabstop = false, in a procedure I have to apply control settings by control name. So I'd actually made those settings a while ago, forgotten, and then assumed that the user should be able to tab through them.
Obviously Access was hitting the subdatasheet control, going "no controls available to tab through here", and so immediately exiting the subdatasheet control.
When I was trying in code to set focus to any of the controls, the reserved error 2950 must've been because the controls weren't tab-stoppable.

How to Handle a Popup, Modal, Resizable form

I need to have a popup form resizable for users whose screen is not as large as others - setting the form to Popup and Modal and BorderStyle Resizable has one major limitation - the code in the form that launches the popup now does not wait for the form to return.
So how does one wait for a form to be made invisible? I tried looping with sleep and doevents, but that makes the popup form not very responsive and chews up cpu cycles. I have tried setting the form.gotfocus event of the launching form but that does not trigger and which means I have to split the code that opened the popup form from the code that executes after the popup form is closed.
What is the best solution?
Thanks
I have never had any problems with DoEvents / Sleep 50 loops. CPU load stays minimal and the form responsive.
With a very old computer, perhaps use Sleep 100.
Sample code:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub TestOpenForm()
If FormOpenWait("frmPopup") Then
MsgBox "Form was hidden.", vbInformation
Else
MsgBox "Form was closed.", vbInformation
End If
End Sub
' Open fName, wait until it is
' - closed : return False
' - hidden : return True
Public Function FormOpenWait(fName As String, Optional sOpenArgs As String = "") As Boolean
If IsFormLoaded(fName) Then DoCmd.Close acForm, fName, acSaveNo
DoCmd.OpenForm FormName:=fName, OpenArgs:=sOpenArgs
' default: signal "closed"
FormOpenWait = False
' Wait until form is closed or made invisible
Do While IsFormLoaded(fName)
If Not Forms(fName).Visible Then
' Signal "hidden"
FormOpenWait = True
Exit Do
End If
' Wait 50ms without hogging the CPU
DoEvents
Sleep 50
Loop
End Function
Public Function IsFormLoaded(fName As String) As Boolean
IsFormLoaded = (SysCmd(acSysCmdGetObjectState, acForm, fName) And acObjStateOpen) > 0
End Function
You can open the form with acDialog option:
DoCmd.OpenForm "MyFormName", WindowMode:=acDialog
It will wait until the form closed or hidden.
The problem here is popup and modal forms don’t’ halt calling code.
But worse is your need to halt calling code. That requires a dialog form.
And more worse is a dialog form does NOT allow re-sizing.
You don’t want to confuse the 3 types of forms here.
Modal forms – they are different then popup forms, and very different from dialog forms.
And same goes for Popup forms. They are not dialog forms, and in fact they are also not model.
You also have to take into consideration if you Access application is set to use tabbed documents, or overlapping windows. (this will limit your choices again).
If you using tabbed interface, then you have to use a popup form if you want re-sizable ability – but this type of form will not halt calling code.
If you using overlapping windows, then I recommend a modal form. (But again it will not halt calling code, but will allow re-size).
While you “could” adopt some looping code in the calling form that “waits” for the second form to be dismissed, such loops are processor hogs and often cause a “poor” response in terms of mouse and typing.
So I would suggest that change your code approach. Have the calling form launch the form as popup (or modal if you not using the tabbed interface).
Then when you close the form, it calls some more code that you want to run in the calling form. This does mean you have to split out the code that you want to run after closing that 2nd form – and have the closing form call + run that code.
A “general” approach should avoid hard coding the forms names since then “many” routines and forms can call your second forms and that facilities re-use of such forms.
So try this:
In the second form, create a module level form variable like this:
Option Compare Database
Option Explicit
Dim frmPrevious As Form
In the forms on-open event of this form, GRAB the calling forms refeance like this:
Set frmPrevious = screen.ActiveForm
Now in the forms close event , do this:
frmPrevious.AfterClose
And in the calling form, create a public function called
AfterClose
So in the public function in the first form, you place the code that you want to run when you close the 2nd form. This is "less" ideal then nice procedural code that calls the 2nd form, waits and continues - but I think it still about the best choice.
And before you close, you can pass or “set” values to return to the calling form like:
frmPreviuos.SomePubicVar = me!LastNameSelected
frmPrevious!Company = me!CompanySelected
frmPrevious.AfterClose
In the above the first line sets a public variable in the calling form (if you want to do that and pass values back to module level vars in the first form). And the next line sets the value of a control in the calling form (if you want to pass values back to some controls on the calling form).
And the 3rd line executes the MyClose code in the calling form. And if you have some kind of “ok” or select button in that second form, then move the above code to behind that button – since you may not want such code running if the form has a cancel button (so the cancel button would simply close the form – but not call + run the above code in the first form). And hitting the X would also be assumed to be a cancel or exit. So your "save" or "ok" or "select" button would have the above code.

Avoid prompt to save form upon form close in MS Access

I have a form with save and cancel button.
When save is pressed and some required data was not provided, it prompts a message that data cannot be saved and I do some vba cosmetics to change the border of the controls that needed to be filled up. I change border colors in red and make it thicker.
My problem is when this changes was triggered and the user decided not to submit the form data, upon click on cancel button, message pops asking the user if he wants to save changes made on the form which obviously I do not want that.
I saw some suggestion in this post
MS Access - Prevent prompt to save form
but reading on the documentation of the suggested answer, to me is not ideal to tun off all errors.
I also found another possible solution using
DoCmd.Close acForm, "myform", acSaveNo
But it seems acSaveNo only applies to data changes not on the controls property changes.
Is there any better way to avoid prompting form save and automatically discard any changes and close the form?
Thanks
EDIT: My code on changing form control appearance
Public Function InvalidBox(ByRef theBox As Control)
theBox.BorderStyle = 1
theBox.BorderColor = RGB(255, 0, 0)
theBox.BorderWidth = 2
End Function
On my cancel button I have this code
DoCmd.Close acForm, "myform", acSaveNo
Solution was: normally Access doesn't ask "Do you want to save the changes" for changes made in Form view. Only in Design view.
So it is perfectly normal to change layout properties in a form at runtime, without any problems when closing the form.
Why the "save changes" prompt appeared here is unknown, but a reboot solved it.
There aren't really except for those methods you've already seen.
The best thing is to avoid "physical" design changes. Instead of changing the border thickness, only change the colour, or overlay the textbox with a red rectangle normally hidden. Then, for a warning, unhide the rectangle.

How to refresh conditional formats after closing a zoom in box

I have a form which has some fields which have conditionalformats which are linked to values which get entered via a zoom in box. In other words, to update each conditionally formatted field, the user clicks on the control and a zoom in box appears allowing the user to enter the data. In the following situation the conditional formatting takes effect only after i close the main form and re-enter. In other words, it does not update automatically once the user access the zoom in form. I tried to put a refresh command on the close zoom in form event, but it is giving me an error. Below is the code i put on the close event of the zoom in:
Private Sub Form_Close()
Forms("frmprojectphasemasterboard").Form("frmprojectphase")!Description = Me.txtZoom
Forms("frmprojectphasemasterboard").Form("frmprojectphase").Refresh
End Sub
Forms!frmProjectMasterBoard!frmProjectPhase.Form.Refresh

windows8 contest to take part

I'm trying to set focus on TextBox but Focus() method returns false
this.NameTextBox.Focus(FocusState.Programmatic);
However in msdn it is written:
Focus(FocusState value)
Return value: True if focus was set to the control, or focus was
already on the control. False if the control is not focusable.
and
You typically pass FocusState.Programmatic as the parameter to
indicate the control obtained focus through a deliberate call to the
Focus method. For example, if clicking an "Edit" button causes focus
to be set on a TextBox, use the Programmatic focus state.
So why does my command not work?