ms access on long click or on short click - ms-access

i want to display a character in an inputbox: dot . on click and dash - on long click. For instance, holding left click for 2 seconds will display dash instead of dot.
i have tried this on double click, here is my code:
Private Sub input_Click()
Me.input.Value = "." + Me.input.Value
End Sub
Private Sub input_DblClick(Cancel As Integer)
Me.input.Value = "-" + Me.input.Value
End Sub
the problem here is that when i double click it will pass thru click and display dot and dash when it is suppose to display dash only.
i'd like to add that i need to use only left click on this. no keyboard, no right click.
that's why my idea is to use either click for dot and double click for dash, or click and long click.
I have an idea of having if statement on VBA and check if its a single click or double without using the double click event.

Define in the header of form's module the following variables:
Private isMouseKeyPreessed As Boolean
Private timeMouseKeyPreessed As Date
then define MouseUp and MouseDown events for textbox named input (by the way it is bad name, because input is reserved word):
Private Sub input_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = acLeftButton Then
isMouseKeyPreessed = True
timeMouseKeyPreessed = Now
End If
End Sub
Private Sub input_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim Delta As Double
Dim symbol As String
If Button = acLeftButton Then
isMouseKeyPreessed = False
Delta = Now - timeMouseKeyPreessed
If Delta > 0.00002 Then
' 0.00002 - is a value to tune up to get exactly 2 seconds
' it should be about
' cdbl(timeserial(0,0,2)-timeserial(0,0,0))
symbol = "-"
Else
symbol = "."
End If
Me.input.Value = symbol & Me.input.Value
End If
End Sub

Related

TextBox.SelStart gives different value for mouse and keyboard

I have a TextBox on a Form. I take the cursor position using .SelStart property in that TextBox. It works as required when I click within TextBox. I then use that position to insert certain symbols on cursor position by pressing buttons on the same form which print their captions.
However, if I type some characters with the keyboard in TextBox, the Selstart returns 0. Even though I type several characters and cursor visibly is at the end of text, SelStart remains 0. Now, if I print buttons on other form the new characters get printed always at the start of TextBox which is not what I want. I want the captions to be printed always at cursor location even when I type with keyboard.
This behavior is very puzzling. Can someone help out on this?
Private LastPosition as Long 'declared in form module
Private sub t_LostFocus() 'to obtain last position in `TextBox`
LastPosition = Me!t.SelStart
End Sub
Private Sub Insert()
Dim Text As String
If LastPosition = 0 AND IsNull(Me!t.value) Then
Me!t.Value = " " + Me.ActiveControl.Caption
LastPosition = LastPosition + Len(Me.ActiveControl.Caption) + 1
ElseIf LastPosition >=0 AND Not IsNull(Me!t.Value) Then
Text = Me!t.Value
Me!t.Value = Left(Text, LastPosition) & " " & Me.ActiveControl.Caption & Mid (Text, LastPosition + 1)
LastPosition = LastPosition + Len(Me.ActiveControl.Caption)+1
Else
Me!t.Value = Me!t.Value + " " + Me.ActiveControl.Caption
End If
End Sub
Private Sub button1_Click()
Call Insert
End Sub
First a few facts about data entry on an Access Form. These need to be understood separately to properly explain the behavior described in the question, and especially if one is trying to alter the default behavior of the control.
The TextBox.SelStart, SelLength, and SelText are only available and valid when the control has focus. When a TextBox control receives focus again, the default is for all text to be selected, so that SelStart = 0 and SelLength = length of Text property. When using the mouse and clicking on the TextBox at a particular character position, the default behavior is bypassed and the cursor is placed at the mouse cursor, as expected.
TextBox controls have both a Text property and a Value property. The Text property represents the text string as it is displayed in the control. The displayed text can be different than the underlying value that the control represents, especially if Value is a non-text data type (e.g. an integer is stored as a number, but represented as individual text digits). The Value property returns a VBA variant which itself holds the underlying value of a particular data type.
For a bound control (i.e. the ControlSource property is populated), the Value data type will be the same as the bound source column.
For an unbound control (i.e. ControlSource is blank), the Value data type is dictated by the TextBox.Format property. If Format is blank, then the data type is text and will effectively match the Text property.
Text and Value are not always synced and this is especially true when the control has focus and is being edited. When the text is edited by the form user (i.e. not from code), Value is not updated until the control loses focus or Shift+Enter saves the form (except in cases when the Enter key behavior has been altered). Most events that will update the control will also involve clicking or otherwise moving focus outside the control, like saving the record, changing focus to another control, etc.
When the control’s Value is updated, the displayed text--accessible via the Text property--is interpreted and/or convert into the appropriate data type which is then saved to the Value property. (Sometimes the synchronization continues by reformatting the ‘Value’ back into a representation specified in the Format property. For instance, if Format = Long Date then: Text entered as “4-12-19” --> updated Value: #4/12/19 00:00# → updated Text: “Friday, April 12, 2019”.
One important last fact before I get to the point:
When TextBox.Value property is updated--even if it is also a String data type--the Text property is also refreshed and the cursor position and text selection is reset so that the entire text is selected. In other words, SelStart is set to 0 and SelLength is set to the length of Text, just like the behavior observed when the TextBox newly receives focus (as mentioned in the first point above).
Finally to the crux of all this detail:
When the keyboard is used to alter the text, this will eventually trigger an update, but usually not until the control loses focus. But when such an update occurs, it happens before the LostFocus event and the text selection is reset as described above, so that within the LostFocus event handler, SelStart == 0.
The issue is really not between keyboard and mouse, rather between the control text being altered or unaltered. If one only uses the arrow keys while in the textbox, then the cursor position and text selection are retained in the LostFocus event because a control update has not occurred. Contrariwise, if the mouse is used to alter the text (e.g. right-click Paste), this also triggers an update which will reset the selection. In fact, if one changes the text in any way and then uses the arrow keys or the mouse clicks, an update will still occur and reset the cursor position and text selection.
If the focus is moved outside the textbox and then back in using the mouse, an update may have occurred but the mouse will subsequently set the cursor position. I only mention this to be aware of stray clicks that might unknowing cause an update and still give the illusion that there is unique behavior to the mouse.
For kicks, press Shift+Enter to force an update but retain focus on the control, and observe that all of the text is automatically selected.
It is worth tracing the code by placing some "logging" statements in the various events, so that you can observe when they happen and the order.
Option Explicit
Option Compare Database
Dim LastSelStart As Integer
Dim LastSelLength As Integer
Dim UpdateSelStart As Integer
Dim UpdateSelLength As Integer
Private Sub button1_Click()
Insert
End Sub
Private Sub button2_Click()
Insert
End Sub
Private Sub Form_Load()
LastSelStart = -1
LastSelLength = 0
ResetUpdateSelValues
End Sub
Private Sub ResetUpdateSelValues()
UpdateSelStart = -1
UpdateSelLength = 0
End Sub
Private Sub t_AfterUpdate()
On Error Resume Next
UpdateSelStart = Me.t.SelStart
UpdateSelLength = Me.t.SelLength
If Err.Number <> 0 Then
UpdateSelStart = -1
End If
End Sub
Private Sub t_GotFocus()
On Error Resume Next
If LastSelStart >= 0 Then
Me.t.SelStart = LastSelStart
Me.t.SelLength = LastSelLength
End If
End Sub
Private Sub t_LostFocus()
LastSelStart = Me.t.SelStart
LastSelLength = Me.t.SelLength
If LastSelStart = 0 And UpdateSelStart > 0 Then
LastSelStart = UpdateSelStart
LastSelLength = UpdateSelLength
End If
ResetUpdateSelValues
End Sub
Private Sub Insert()
Dim caption As String
caption = Me.ActiveControl.caption
If IsNull(Me.t.Value) Then
Me.t.Value = caption
LastSelStart = Len(caption)
LastSelLength = 0
Else
Dim Text As String
Text = Me.t.Value
If LastSelStart = 0 Then
'* Don't add extra space at beginning
Text = caption & Mid(Text, LastSelLength + 1)
'Text = caption & Text
LastSelStart = Len(caption)
LastSelLength = 0
ElseIf LastSelStart > 0 Then
Text = Left(Text, LastSelStart) & " " & caption & Mid(Text, LastSelStart + LastSelLength + 1)
'Text = Left(Text, LastSelStart) & " " & caption & Mid(Text, LastSelStart + 0 + 1)
LastSelStart = LastSelStart + 1 + Len(caption)
LastSelLength = 0
Else
'If last cursor position is invalid, append characters
Text = Text & " " & caption
LastSelStart = Len(Text)
LastSelLength = 0
End If
t.Value = Text
End If
Me.t.SetFocus
End Sub

How after pressing "Enter" at the end of the text that is in the form field add ", " and the cursor did not move to the next line?

How after pressing "Enter" at the end of the text that is in the form field add ", " and the cursor did not move to the next line?
Logics:
- The user enters "Text_1";
- The user presses "Enter";
- The code adds ", ";
- Result in the form field - "Text_1, ";
- The user enters "Text_2";
- The user presses "Enter";
- The code adds ", ";
- Result in the form field - "Text_1, Text_2, ";
Private Sub Field1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = 13 Then
Me.Field1.Text = Me.Field1.Text & ", "
Me.Field1.SelStart = Len(Me.Field1.Text)
End If ' KeyCode
End Sub
I try to do, but I can't.
Now the cursor after pressing "Enter" moves to the next line.
How to make the cursor remain on the same line with the text?
Update_1
How to make a space after the comma?
My solution does not leave a space after the comma after pressing "Enter".
Update_2
Database file - link
You want to "swallow" the keypress. You can do that by setting the KeyCode to 0 - notice it's implicitly being passed ByRef (parameters are passed by reference in VBA, unless specified otherwise), so by changing the value in the handler (which is invoked before the keypress lands into the textbox), the event source will see that value as 0.
Private Sub Field1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = 13 Then
Me.Field1.Text = Me.Field1.Text & ", "
Me.Field1.SelStart = Len(Me.Field1.Text)
KeyCode = 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

MouseMove High CPU Usage - Looking for better and elegant solution

I'm working on an Access 2007 application and have some concerns about performance with MouseMove over labels and form.
So far with my solution I'm getting high cpu usage on a dual core I5 3.0ghz.
When I move the mouse cpu usage jumps to about 30-32% of one core.(With hyperthreading on)
For such a trivial task as a MouseMove, I'd like to have something a bit more efficient :)
The code below as been shortened; I have 8 labels with MouseMove event handler.
Here's how it's implemented:
Private moveOverOn As Boolean
Private Property Get isMoveOverOn() As Boolean
isMoveOverOn = moveOverOn
End Property
Private Property Let setMoveOverOn(value As Boolean)
moveOverOn = value
End Property
'label MouseMove detection
Private Sub lbl_projects_completed_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Shift = 0 And isMoveOverOn = False Then
Me.lbl_projects_completed.FontBold = True
setMoveOverOn = True
End If
End Sub
'main form MouseMove detection
Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If isMoveOverOn Then
resetBold 'call a sub that reset all labels .FontBold
setMoveOverOn = False
End If
End Sub
I don't know if it's possible, but I think that reducing the speed at which the MouseMove
is refreshed would help for this task, unfortunately I wasn't able to find information about it.
I'm opened to suggestions, thanks for your time! :)
The accdb format has hover and press color properties for buttons, so if you don't mind converting to that format and the labels could be buttons that should work much better than what you have going on.
Okay so this will do what you want with less of an expense but just know mouse move does not update X,Y when over a control so it has intermittent issues with the event.
This is custom implementation of a mouseHover event using mouse move on the detail section so it is only called 1 time. It then loops through the controls (you can change this loop to only look at controls you want) and sees if the cursor is within 5 twips of the control on any side
It also accepts a fuzziness parameter because of the lack of updating when over a control. The default it 50 twips. Also know that the controls should be shrunk to the minimum size possible to fit the data as this function uses the controls height and width to determine if you are inside of the control.
Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
mouseHover X, Y
End Sub
Private Sub mouseHover(X As Single, Y As Single)
Dim ctrl As Control
'You may want to make an array of controls here to shorten the loop
'i.e.
' Dim ctrl_array() As Variant
' ctrl_array(0) = Me.lbl_projects_completed
' ctrl_array(1) = Me.some_other_label
' For Each ctrl in ctrl_array
For Each ctrl In Me.Controls
If ctrl.ControlType = acLabel Then
If FuzzyInsideControl(ctrl.top, ctrl.left, ctrl.width, ctrl.height, X, Y) Then
ctrl.FontBold = True
ctrl.ForeColor = RGB(255, 0, 0)
Exit For
Else
ctrl.ForeColor = RGB(0, 0, 0)
ctrl.FontBold = False
End If
End If
Next ctrl
End Sub
Private Function FuzzyInsideControl(top As Long, left As Long, width As Long, height As Long, X As Single, Y As Single, Optional fuzz As Integer = 50) As Boolean
Dim coord_left As Long
Dim coord_right As Long
Dim coord_top As Long
Dim coord_bottom As Long
Dim inside_x As Boolean
Dim inside_y As Boolean
coord_top = top - fuzz
coord_bottom = top + height + fuzz
coord_left = left - fuzz
coord_right = left + width + fuzz
inside_y = Y > coord_top And Y < coord_bottom
inside_x = X > coord_left And X < coord_right
FuzzyInsideControl = inside_x And inside_y
End Function
While I still think that this is unnecessary it was an interesting question and fun to work with but there are some of limitations due to how mouseMove works
Edit
Changed the FuzzyInsideControl function for a cleaner more concise version should be more accurate although I will have to test tomorrow when I get back to a computer with access.
Finally I found what I was looking for to reduce the MouseMove strain on the CPU:
'put this in head of the form code
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
'form MouseMove with sleep timer
Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
'placeholder call sub to change the label FontBold Suggested by engineersmnky
Sleep (25)
End Sub

selstart returns position 0 if text is entered in memo field (not clicked)

I have memo field and list. What I want to accomplish is if I am typing something in memo field and then just click on text record in list that the text shows up in memo positioned with the beginning where cursor was.
After research, and googling I succeed to make it. I did it with .selstart property.
But for me it seems that selstart has bug. It works only if I click somewhere in memo (Then everything works great.) But if was typing something, and then click on text in list (without previously clicking in memo field) selstart returns position 0.
This makes me huge problem.
Can anyone help? Thank you.
As you found out, the problem is that the cursor position is lost when you move away from the memo.
This is probably due to the fact that Access form controls are not "real" controls: they are real windows controls only when they have the focus. the rest of the time, they are sort of images of the control pasted onto the form.
So, what you need to do is track the cursor position (and currently selected length of text) during various interractions:
when the user moves the cursor using the keyboard (KeyUp event)
when the user clicks inside the memo (Click event, to position the cursor or select text using the mouse)
when the memo initially gets the focus (GetFocus, the first time, the whole text is selected and the cursor is at position 0)
To test this, I made a small form:
The added the following code to the form:
'----------------------------------------------------------
' Track the position of the cursor in the memo
'----------------------------------------------------------
Private currentPosition As Long
Private currentSelLen As Long
Private Sub txtMemo_Click()
RecordCursorPosition
End Sub
Private Sub txtMemo_GotFocus()
RecordCursorPosition
End Sub
Private Sub txtMemo_KeyUp(KeyCode As Integer, Shift As Integer)
RecordCursorPosition
End Sub
Private Sub RecordCursorPosition()
currentPosition = txtMemo.SelStart
currentSelLen = txtMemo.SelLength
End Sub
'----------------------------------------------------------
' Insert when the user double-click the listbox or press the button
'----------------------------------------------------------
Private Sub listSnippets_DblClick(Cancel As Integer)
InsertText
End Sub
Private Sub btInsert_Click()
InsertText
End Sub
'----------------------------------------------------------
' Do the actual insertion of text
'----------------------------------------------------------
Private Sub InsertText()
If Len(Nz(listSnippets.Value, vbNullString)) = 0 Then Exit Sub
Echo False 'Avoid flickering during update
' Update the Memo content
Dim oldstr As String
oldstr = Nz(txtMemo.Value, vbNullString)
If Len(oldstr) = 0 Then
txtMemo.Value = listSnippets.Value
Else
txtMemo.Value = Left$(oldstr, currentPosition) & _
listSnippets.Value & _
Mid$(oldstr, currentPosition + currentSelLen + 1)
End If
'We will place the cursor after the inserted text
Dim newposition As Long
newposition = currentPosition + Len(listSnippets.Value)
txtMemo.SetFocus
txtMemo.SelStart = newposition
txtMemo.SelLength = 0
currentPosition = newposition
currentSelLen = 0
Echo True
End Sub
I have made a test accdb database that you can download so you can see the details and play around with this.