Most usable select all/deselect all checkbox format - usability

What is the best pattern for having a select all or deselect all checkboxes. Can someone come up with a better way to have it in this form:

I'll be honest, I've never liked the idea of using a checkbox for the "select all" option, even though you see it a lot. It's not a single item to be picked, it's an action. And if you select all and then start unselecting individual items in the list, the "checked" state of the select all checkbox becomes inherently confusing. I prefer to use a simple but obvious link/button that toggles between "select all" and "unselect all" as it is clicked. There is no state to confuse you with when individual items have been deselected, and the outcome of pushing the button is never in doubt. The exclusive nature of the operation makes it perfectly reasonable to toggle back and forth (rather than using two always visible buttons; one for select all, one for unselect all), since you are at most two clicks away from your desired behavior. And it visually separates out this "action" from the individual items, preventing misclicks and distinguishing behavior.

If you can format your dialog with lists, I like the "checkbox in the list header" method (and most users intutively know how to use it).
If you do not want to use a list, I think a button or a hyperlink (that toggles from "Select All" to "Select None" would work better than yet another checkbox which is hard to make out among all the other checkboxes. Also, unchecking a "check all" checkbox would not necessarily immply a "check none" functionality for a user.

Just bring the Select All check box closer to the left border. Perhaps change the text something like "All previous games" etc. to make it clear what "all" is being selected.

Here's the logic for a User Control in WinForms to implement #nezroy's answer. This lets you specify an InitialAction [one of SelectAll or DeselectAll] as well.
Imports System.ComponentModel
''' <summary>
''' A control which allows the user to toggle back-and-forth
''' between selecting all of something, or de-selecting all of something.
''' </summary>
Public Class uscSelectDeselectAll
#Region "Events"
Public Event CurrentAction_Changed()
#End Region
#Region "Enums"
Public Enum SelectAction
SelectAll
DeselectAll
End Enum
#End Region
#Region "Module-level variables"
Private _initialAction As SelectAction
Private _currentAction As SelectAction
#End Region
#Region "Properties"
Public Property CurrentAction As SelectAction
Get
Return _currentAction
End Get
Private Set(value As SelectAction)
_currentAction = value
SetActionLinkText()
End Set
End Property
<Browsable(True)>
<EditorBrowsable(EditorBrowsableState.Always)>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)>
Public Property InitialAction As SelectAction
Get
Return _initialAction
End Get
Set(value As SelectAction)
_initialAction = value
SetActionLinkText()
End Set
End Property
#End Region
#Region "Procedures"
Private Sub SetActionLinkText()
If _currentAction = SelectAction.SelectAll Then
llActionText.Text = "Select All"
ElseIf _currentAction = SelectAction.DeselectAll Then
llActionText.Text = "Deselect All"
Else
Throw New InvalidEnumArgumentException("Invalid SelectActionProvided.")
End If
End Sub
Private Sub ToggleAction()
If CurrentAction = SelectAction.SelectAll Then
CurrentAction = SelectAction.DeselectAll
ElseIf CurrentAction = SelectAction.DeselectAll Then
CurrentAction = SelectAction.SelectAll
Else
Throw New Exception("CurrentAction has the invalid value: " & CurrentAction.ToString())
End If
End Sub
#End Region
#Region "Event Handlers"
Private Sub llActionText_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles llActionText.LinkClicked
RaiseEvent CurrentAction_Changed()
ToggleAction()
End Sub
Private Sub uscSelectDeselectAll_Load(sender As Object, e As EventArgs) Handles Me.Load
CurrentAction = InitialAction
End Sub
#End Region
End Class

I would say that It's the most intuitive way to make the select/deselect all. But I've also seen some use a link, but i would prefer that.

Related

Access VBA Set Focus in Column

good afternoon,
I have an access with a subform (sub_frm_robo2) that has a specific column (CD_SENHA).
In the Form Load event I put the code: (Me.sub_frm_robo2.Form! SENHA.InputMask = "Password")
and I am trying to create a condition that at the moment this Column
(CD_SENHA) receives focus (Me.sub_frm_robo2.Form!SENHA.SetFocus),
the data mask be removed (Me.sub_frm_robo2.Form!SENHA.InputMask = "")
and when the focus changes to the next column return the data mask to the initial format (Me.sub_frm_robo2.Form! PASSWORD = "Password")
Below some images to better exemplify
Before Focus
With Focus
After Focus
I think the code would look something like this
Do While Me.sub_frm_robo2.SetFocus = True
If Me.sub_frm_robo2.Form!SENHA.SetFocus Then
Me.sub_frm_robo2.Form!SENHA.InputMask = ""
End If
Next
Can you help me?
Well, I did not have any help here but I managed to resolve after a few attempts and errors, just to code a code in the event of each column of the subformaluario to make it work. Good luck to everyone
Private Sub CNPJ_AF_GotFocus()
Me.Form!SENHA.InputMask = "Password"
End Sub
Private Sub SENHA_GotFocus()
Me.Form!SENHA.InputMask = ""
End Sub

Why won't the ForeColor of this label visibly change when altered in a loop?

I am making a form that has groups of controls that I want to visibly enable/disable with a related toggle button (let's call them Group Toggles). Each group has a different variety of control types, so I made a common procedure to handle the toggling:
'constants for control ForeColors
Public Enum LabelForeColor
Default = 8355711
Off = 14277081
End Enum
Public Enum ListForeColor
Default = 4210752
Off = 12566463
End Enum
Public Sub EnableControl(Ctrl As Control, Enabled As Boolean)
With Ctrl
Select Case Ctrl.ControlType
Case acLabel
If Enabled Then .ForeColor = LabelForeColor.Default Else .ForeColor = LabelForeColor.Off
Debug.Print "LABEL", .ForeColor
Case acListBox
If Enabled Then .ForeColor = ListForeColor.Default Else .ForeColor = ListForeColor.Off
.Enabled = Enabled
Debug.Print "LIST", .ForeColor
Case acCommandButton
.Enabled = Enabled
Debug.Print "BUTTON", "NA"
Case acCheckBox
.Enabled = Enabled
Debug.Print "CHECK", "NA"
Case Else
Debug.Print "Control [" & .Name & "] is not of a type that EnableControl can handle."
End Select
End With
End Sub
Each group of controls is represented by a collection. When the form is loaded, every control with a particular tag property is added to the corresponding collection. The Group Toggles are not added to any collection and instead have event procedures that look like this:
Private Sub ToggleGroup1_AfterUpdate()
Dim State As Boolean
'a public function that converts the toggle button's value to a boolean
State = FormCommon.ToggleButtonState(ToggleGroup1.Value)
Dim iCtrl As Control
For Each iCtrl In Controls_ByPlant
FormCommon.EnableControl iCtrl, State
Next iCtrl
End Sub
When I click on a GroupToggle, all of the controls in the corresponding group visibly change appropriately, except for the labels. After an hour of troubleshooting, here's what I know:
The ForeColor property of the label does change, but not visibly.
When I call EnableControl on a label outside of a loop, the label visibly changes.
It doesn't matter if I pass the label object specifically to the subroutine or if I pass it from its group collection; the change is visible in both cases
If I toggle-disabled a label as part of the Group Toggle event and then call EnableControl specifically on that label to try to disable it again, there is no visible change (probably because the ForeColor property is already set to the "off" color)
Turning screen updating off with Application.Echo while the Group Toggle event runs and then turning it back on at the end of the event does not make a difference.
Making the Group Toggle event run with a For i = 1 to .Count instead of a For Each does not make a difference.
This problem also occurs when changing a different visual property instead, such as ForeTint.
(Per comments) Repaint does not make a difference
(Per comments) DoEvents does not make a difference
Why is this happening?
(First ever question, so apologies if I messed something up in the post)
This was interesting, but somewhat anticlimactic.
Your code does work for the labels, but what happens is this:
All labels are associated with input controls (as it is usual)
When you deactivate a group, you disable the input controls (.Enabled = Enabled)
This automatically sets the associated labels to a (system defined) light gray text color which cannot be changed.
This "disabled label" color is very similar to your LabelForeColor.Default color, so it is hard to see the change when toggling. But it does change.
Change your color constants to make the effect more visible:
Public Enum LabelForeColor
Default = vbRed ' 8355711
' the "Off" color is never visible, unless you add an un-associated label to a group
Off = vbBlue ' 14277081
End Enum
Edit: your test code FormCommon.EnableControl iCtrl, False works, because it only affects the label, but doesn't disable its associated list box.

VBA code that changes background color of form conditionally by answer

I want to use VBA (or some other solution) to conditionally change the background color of a form based off what number users enter in a numeric field. Basically, after they enter their answer to the Starter question, if they entered 1 then I want the form background to change to a specific shade of blue, and if they entered 2 then I want the form background to change to a specific shade of green. I saw a code that looks like it would be very similar to my need in another question on here, but I couldn't figure out how to make the code work, and was having trouble figuring out exactly how/where to put each module.
Some information:
The field I want it to be based off of is numeric, called Starter, and through data validation users are limited to entering 1, 2, 9, or leaving it blank. I only want the color to change if it's entered as 1 or 2.
I'm using Access 2010
the form has neither header nor footer
the code I was attempting to use and made some alterations to is the following:
Private Sub Form_AfterUpdate()
blue_yes = "15325906"
green_no = "13888226"
Dim colorThis As String
booWhatever = Me.Starter ''Use of the variable can prevent problems
If booWhatever = 1 Then
colorThis = "blue_yes"
End If
If booWhatever = 2 Then
colorThis = "green_no"
End If
subFrm.Form.Section(acDetail).BackColor = colorThis
subFrm.Form.Repaint
End Sub
I've also managed, off a very different piece of code, to sort of do what I want, but the way it's working it seems to change the status of all forms, not just the one I'm currently working with, which is the goal. So for example if I enter 2 to starter, it changes the background color of every single record's form.
Private Sub Starter_AfterUpdate()
If Me.Starter = "1" Then Me.Detail.BackColor = vbBlue
If Me.Starter = "2" Then Me.Detail.BackColor = vbGreen
End Sub
EDIT:
Welp, embarrassingly I found the solution. It's not a very neat one, but it works.
Private Sub Form_Current()
Dim Presence As String
Presence = Nz(Me.Starter.Value, 9)
Select Case Presence
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
Private Sub Starter_AfterUpdate()
Dim Presence As String
Presence = Nz(Me.Starter.Value, 9)
Select Case Presence
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
I know it is a really old question (probably you have already solved it in a better way) but I will give it a try anyways.
Try the following:
Private Sub Text0_Change()
Select Case Me.Text0.Text
Case ""
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
EDIT:
I tried that and it works I think now as it supposed to do.
When you change the text on the text box triggers this event every time, runs the Sub, checks it's own text and changes the color of the form as described.
The change is that I changed the property of the field it checks. From Value to Text. We want when the event triggers to check the current text because the Value property updates when you "finish" with the textbox (after you press enter or the focus on the control is lost) and we want the change to happen the same moment we press the key changing the value and not later.
The second change and the reason we got strange patterns before is that I have added one more Case when the text is "" to do nothing on that change (empty case). Without that case when we used delete or backspace to remove the text and left the textbox empty ("") then the case else was True and it changed the background color.
I hope this is the correct answer now. Please let me know!

Assiging a 'User Stamp' when saving a record

So the first thing is that every table has 4 fields. Created_By, Created_Date, Last_Updated_By and Last_Updated_Date. This will allow me to keep a track of who saved what records and when. I want a public sub (or function?) to update these fields when any record is saved.
Ideally I don't want to have to copy/call my code from every form, but I will if that's what is necessary. I imagine there is a way of doing this globally.
I currently have the following:
Public gLoggedIn As Integer
Public Function get_global(Global_name As String) As Variant
Select Case Global_name
Case "Employee_ID"
get_global = gLoggedIn
End Select
End Function
My next thing is to add vba code to fill the 2 of the 4 fields. The following is something I have in one of my forms, but like I say, I want to able to achieve this globally on every save.
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.NewRecord = True Then
Me.[Created_By] = gLoggedIn
Me.[Created_Date] = Now()
Else
Me.[Last_Updated_By] = gLoggedIn
Me.[Last_Updated_Date] = Now()
End If
End Sub
How can I do this globally?
I'm not sure if 'me' is the correct reference to us if this is global?
Exactly for your demand, you could use a VBA modul with following sub
Public Sub setTimestamp(objForm As Form)
If objForm.NewRecord = True Then
objForm![Created_By] = gLoggedIn
objForm![Created_Date] = DateTime.Now
Else
objForm![Last_Updated_By] = gLoggedIn
objForm![Last_Updated_Date] = DateTime.Now
End If
End sub
You need to call this method in every form when the Timestamp Update should be fired (BTW: I would recommend an event when a save button is clicked or field update, because an edit in the dataset of the form at form update event will probably cause another form update event and could lead to an endless loop).
call setTimestamp(Me)
But you should alternatively consider using a macro like #E Mett said in comment.
Another hint: If you set the variable gLoggedIn to public, you can refer directly without using a function. (You did this even in your example) A function makes sense when you want to hide the variable inside a modul as private. This is called encapsulation, if you want to learn more about it.
EDIT
Changed code by andre451 ' s suggestion.

moving focus from subform to main form

i have main form MAINF and two subforms SUBONE and SUBTWO
I want to be able to move focus (cursor) between them.
From MAINF to SUBONE or SUBTWO, I can call Me![SUBONE].SetFocus or Me![SUBTWO].SetFocus. This seems to work.
BUT:
1) From SUBONE to SUBTWO, I have no idea. what is the correct way of programatically moving focus?
2) From SUBONE to one of MAINF's control say "Customer ID", how do i do it?
Edit: Here's the code that rtochip provided.
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyF5
Me.Parent![Item - Order Subform].SetFocus
DoCmd.GoToControl "Supplier ID NUM"
Case vbKeyF6
Me.Parent.[Item ID].SetFocus
End Select
End Sub
If SUBTWO is a child of SUBONE, then it's the same way. However, if they are siblings thenyou have to reference it as an object on the parent first.
There are two ways to reference objects on your parent:
You can reference the parent
Me.Parent.[Customer ID].SetFocus
(btw, change than control's name to Customer_ID - it makes it easier to use, and you won't require the []'s)
You can reference it directly
Forms!MAINF.[Customer ID].SetFocus
Update: The KeyDown event is probably being caught later on the main form. You could always clear it out before you finish with moving focus.
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyF5
Me.Parent![Item - Order Subform].SetFocus
DoCmd.GoToControl "Supplier ID NUM"
KeyCode = 0 'Trap F5
Case vbKeyF6
Me.Parent.[Item ID].SetFocus
keyCode = 0 'Trap F6
End Select
'keyCode = 0 'Note: you can't do it here because it will trap ALL your
'KeyCodes. Not just F5 and F6.
End Sub