Author Topic: double click  (Read 5370 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: double click
« Reply #15 on: February 17, 2020, 07:01:04 pm »
I have deployed Terry's code in my simple menu app and...
Code: QB64: [Select]
  1. _TITLE "press menu number key or Double Click Menu Item" 'b+ 2020-02-17 with TerryRitchie mouse code
  2. TYPE MOUSE
  3.     x AS INTEGER '           actual Y location of mouse cursor
  4.     y AS INTEGER '           actual X location of mouse cursor
  5.     Click AS INTEGER '       TRUE if single click occurred
  6.     DoubleClick AS INTEGER ' TRUE if double click occurred
  7.     DCTimer AS INTEGER '     double click timer
  8.     LeftDown AS INTEGER '    TRUE if left button is down
  9.     ClickX AS INTEGER
  10.     ClickY AS INTEGER
  11.  
  12. CONST FALSE = 0, TRUE = NOT FALSE
  13. CONST FPS = 60
  14. DIM Mouse AS MOUSE, m, ms$, ink$, oldink$, keyhit AS LONG, oldkeyhit AS LONG
  15. 'SCREEN _NEWIMAGE(640, 480, 32) '<<<<<<<<<<<<<< i'm thinking mouse sub should work in any screen including default
  16.     _LIMIT FPS
  17.     CLS
  18.     PRINT "Press menu # key or double click menu item:"
  19.     FOR m = 1 TO 8
  20.         ms$ = _TRIM$(STR$(m))
  21.         PRINT ms$; ") Menu item "; ms$
  22.     NEXT
  23.     PRINT "9) Quit this demo"
  24.  
  25.     UpdateMouse
  26.     'IF Mouse.DoubleClick THEN SOUND 880, 1
  27.     'IF Mouse.Click THEN SOUND 440, 1
  28.     'PRINT "Mouse X     : "; Mouse.x
  29.     'PRINT "Mouse Y     : "; Mouse.y
  30.     'PRINT "Last click X: "; Mouse.ClickX
  31.     'PRINT "Last click Y: "; Mouse.ClickY
  32.     'PRINT "Left button is ";
  33.     'IF Mouse.LeftDown THEN PRINT "DOWN" ELSE PRINT "UP"
  34.     keyhit = _KEYHIT
  35.     IF keyhit > 0 THEN oldkeyhit = keyhit
  36.     ink$ = INKEY$
  37.     IF ink$ <> "" THEN oldink$ = ink$
  38.     'PRINT "Last KeyHit = "; oldkeyhit
  39.     'PRINT "Last Inkey$ = "; oldink$
  40.     'IF Mouse.LeftDown THEN
  41.     'LINE (Mouse.ClickX, Mouse.ClickY)-(Mouse.x, Mouse.y), _RGB32(0, 0, 255), BF
  42.     'END IF
  43.     LOCATE 15, 1: PRINT "Mouse x, y:"; Mouse.x; ","; Mouse.y
  44.     FOR m = 1 TO 9
  45.         IF NOT Mouse.Click THEN
  46.             IF Mouse.DoubleClick AND Mouse.ClickY = m + 1 OR ink$ = _TRIM$(STR$(m)) THEN 'for screen 0 or default my = line number
  47.                 PRINT "You selected menu"; m: _DELAY 2
  48.                 IF m = 9 THEN SYSTEM
  49.             END IF
  50.         END IF
  51.     NEXT
  52.  
  53.     ' Demo use single click info when doesn't interfere with dbl click evaluation, ie doesn't delay 2nd click detection
  54.     IF Mouse.Click AND (Mouse.ClickY > 10) THEN PRINT " You clicked outside then menu area: col"; Mouse.ClickX; ", row"; Mouse.ClickY
  55.     PRINT "You pressed "; ink$
  56.  
  57.  
  58.     '_DISPLAY
  59.  
  60.  
  61. SUB UpdateMouse ()
  62.  
  63.     SHARED Mouse AS MOUSE
  64.  
  65.     Mouse.x = _MOUSEX '                     actual X coordinate
  66.     Mouse.y = _MOUSEY '                     actual Y coordinate
  67.     Mouse.DoubleClick = FALSE
  68.     Mouse.Click = FALSE
  69.     SELECT CASE _MOUSEBUTTON(1) '                   current state of left button?
  70.         CASE TRUE '                                 button is down
  71.             IF NOT Mouse.LeftDown THEN '            already held down?
  72.                 Mouse.LeftDown = TRUE '             no, remember that it is now
  73.                 IF Mouse.DCTimer THEN '             was last click less than double click timer value?
  74.                     IF ABS(Mouse.ClickX - Mouse.x) < 3 AND ABS(Mouse.ClickY - Mouse.y) < 3 THEN
  75.                         Mouse.DoubleClick = TRUE '  yes, report a double click happened
  76.                     END IF
  77.                     Mouse.DCTimer = 0 '             reset the double click timer
  78.                 ELSE '                              no, double click timer has run out
  79.                     Mouse.DCTimer = FPS \ 3 '       reset double click timer to 1/3 second
  80.                     Mouse.ClickX = Mouse.x '        remember X location of click
  81.                     Mouse.ClickY = Mouse.y '        remember Y location of click
  82.                     Mouse.Click = TRUE '            report that a single click occurred
  83.                 END IF
  84.             END IF
  85.         CASE FALSE '                                button is up
  86.             IF Mouse.LeftDown THEN '                was the left button previously down?
  87.                 Mouse.LeftDown = FALSE '            yes, report that it's now up
  88.             END IF
  89.             IF Mouse.DCTimer THEN '                 time left in double click timer?
  90.                 Mouse.DCTimer = Mouse.DCTimer - 1 ' yes, decrement value
  91.             END IF
  92.     END SELECT
  93.  

OK works nice, it can distinguish a click from a double. :) and it's not using TIMER().

Don't know why I was having trouble with INKEY$ and mouse, a day or 2 ago.
« Last Edit: February 17, 2020, 07:52:46 pm by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: double click
« Reply #16 on: February 19, 2020, 08:02:27 pm »
What plenty of wonderful codes about double click!

Thanks guys!

@krovit
my 2 cents

reading this
Quote
So it works but then, inserting it into the real program, no. Maybe it's some variable that disturbs...

In any case is this the cleanest code to monitor the double click or do you think and be another more efficient?
and this one
Quote
I can't insert double click! when I'm on the field (because I pressed a click or because I got there by scrolling through the fields with the keyboard) I can't manage the double click: it doesn't notice and during the attempts I get to the maximum that the first click is already mistaken for the second and activate - or try to activate even where it doesn't exist - the drop-down menu.
Well, no dragging action in your application!

So if less variables = less change to get a glitch

my first step is
Code: QB64: [Select]
  1.   WHILE 1
  2.     DO
  3.         j$ = INKEY$
  4.         xxw& = _KEYHIT
  5.  
  6.         num_click = 0
  7.         the_end = 0
  8.         IF _MOUSEINPUT THEN ' <-- user presses left button
  9.             mb% = _MOUSEBUTTON(1) ' <-- it stores the status of left button of mouse
  10.             DO WHILE mb% 'check for button release
  11.                 i = _MOUSEINPUT
  12.                 mb% = _MOUSEBUTTON(1)
  13.                 num_click = 1
  14.             LOOP
  15.             IF num_click = 1 THEN 'if button was pressed and released
  16.                 t = TIMER + .3
  17.                 DO WHILE TIMER < t 'check for a second press within .3 seconds
  18.                     i = _MOUSEINPUT
  19.                     IF _MOUSEBUTTON(1) THEN num_click = 2
  20.                 LOOP
  21.             END IF
  22.         END IF
  23.     LOOP UNTIL j$ <> "" OR the_end > 0 OR num_click > 0
  24.  
  25.     PRINT num_click
  26.  

and this is my second step to shrink your working code to fit well in the original application

Code: QB64: [Select]
  1.  WHILE 1
  2.     DO
  3.         j$ = INKEY$
  4.         xxw& = _KEYHIT
  5.  
  6.         num_click = 0
  7.         the_end = 0
  8.         IF _MOUSEINPUT AND _MOUSEBUTTON(1) THEN ' <-- user presses left button
  9.  
  10.             num_click = 1
  11.             WHILE _MOUSEBUTTON(1)
  12.                 dummy = _MOUSEINPUT
  13.             WEND
  14.  
  15.             t = TIMER + .3
  16.             DO WHILE TIMER < t 'check for a second press within .3 seconds
  17.                 i = _MOUSEINPUT
  18.                 IF _MOUSEBUTTON(1) THEN num_click = 2
  19.             LOOP
  20.         END IF
  21.  
  22.     LOOP UNTIL j$ <> "" OR the_end > 0 OR num_click > 0
  23.  
  24.     PRINT num_click
  25.  
  26.  

here your code in scheme
  [ You are not allowed to view this attachment ]  
Programming isn't difficult, only it's  consuming time and coffee

Offline krovit

  • Forum Regular
  • Posts: 179
    • View Profile
Re: double click
« Reply #17 on: February 21, 2020, 04:43:27 pm »
Grazie Tempodibasic per l'ulteriore contributo (non mi ero accorto che il 3d era andato avanti!).

Scrivo in italiano per intendersi (mi pare che tu sia un connazionale) e poi in inglese (traduttore permettendo) per tutti gli altri.
Il tuo codice è stringato e funziona benissimo: è la sintesi di molti altri che fanno un po' di tutto e anche loro lo fanno molto bene.
Purtroppo quando vado ad inserirlo nelle mie routine continuo ad ottenere comportamenti incomprensibili.

Una delle chiavi sta anche nel DOVE si inserisce il codice di controllo del mouse. Alle volte vedo che va inserito dove... non diresti di doverlo mettere. D'altra parte la programmazione non è totalmente "ad oggetti", un certo flusso sequenziale il codice, di per se, lo ha, e quindi il "dove" assume la sua importanza.

Ho individuato il dove. E ci ho messo un codice primitivo (nel senso che davvero è ben poco elegante) ma funziona. Però... però, a mio parere la funzione TIMER ha qualche problema e il programma ne risente. Le pause diventano troppo lunghe aggiungendo solo 0.3 secondi a TIMER. Se se ne aggiungono meno il doppio click non viene intercettato in nessun caso.

La funzione TIMER funziona e non rallenta l'applicazione se la tolgo dal DO-LOOP e mi limito ad intercettare il primo click e poi a verificare se il secondo avviene entro .3 secondi. Purtroppo il monitoraggio inizia, ovviamente, dopo il primo click per cui viene perso e davvero il programma agisce solo dopo aver verificato il secondo. In altre parole, se mi aspettassi un certo comportamento con il primo click (ad esempio saltare su un campo) in effetti dovrei aspettare il secondo per stabilire se davvero si trattava di un doppio click o piuttosto di due click singoli.

Ho scritto grandi quantità di codice e fatto molta fatica a concepire un sistema completo... ma la gestione del secondo click sembra diventare una chimera. Che peccato!

Per esperienza so, ed immagino sappiamo bene tutti, che se dai all'utente la possibilità di sbagliare ad inserisce un dato... quello sbaglierà di sicuro. Il doppio click mi serve all'interno di un sistema che gestisce fino allo sfinimento l'immissione dei dati. Ad esempio se voglio un numero a 5 cifre con due decimali mi deve impedire qualsiasi cosa tranne che scrivere fino a 5 cifre con 2 decimali (prevedendo l'uso del mouse, delle correzioni, del salto ad altro campo, e chi più ne ha più ne metta).

E' facile capire che il sistema non è semplicissimo e prevede molti casi nei quali la routine del doppio click s'inserisce male e con i risultati di ho parlato.

Continuerò a provare... ci vorrà ancora molto tempo (accidenti!) e comunque faccio tesoro dei contributi che trovo in questi forum. Sono dietro a queste cose dai tempi del C64 e devo dire che questa comunità è la migliore di sempre. Anche dal punto di vista umano: sempre disponibili, mai supponenti e naturalmente molto competenti. Se puoi, dillo in giro...

Oro provo a postare il pezzetto di codice che ho elaborato sulla base dei vostri contributi e a scrivere qualcosa in inglese...

Code: QB64: [Select]
  1. FUNCTION Click%
  2.     DO
  3.         WHILE _MOUSEINPUT: WEND
  4.         mb = _MOUSEBUTTON(1) OR _MOUSEBUTTON(2) OR _MOUSEBUTTON(3) ' >>>>>>>>>>>>> report mouse status
  5.                 IF mb AND oldMouse = 0 THEN
  6.                         if plusClick% = 2 then Click%=2 else Click%=1
  7.                 end if
  8.                 oldMouse = mb
  9.     LOOP UNTIL Click%
  10.  
  11. FUNCTION plusClick%
  12. static oldMouse2       
  13.         ct=0
  14.         t3#=timer(.1)+.3
  15.     DO while timer(.1)<t3#
  16.         WHILE _MOUSEINPUT: WEND
  17.         mb2 = _MOUSEBUTTON(1) OR _MOUSEBUTTON(2) OR _MOUSEBUTTON(3)
  18.         IF mb2 AND oldMouse2 = 0 THEN
  19.                 ct=ct+1
  20.         end if
  21.         oldMouse2 = mb2
  22.     LOOP
  23.    plusClick%=ct
  24.    oldMouse2=0
  25.  

First of all it seems important - or at least very useful - that the code is put in the form of a function (you are more sure not to make mistakes and the use is simple and lean).

I understand... it's not a nice code... it's primitive, inelegant maybe redundant but as I said the examples posted - lastly also that of TempodiBasic - in my application are not effective (and I do not understand because! alone work perfectly...).

The example I put works everywhere but has annoying delays that make it in fact not advisable.
In my humble opinion the TIMER function has some problems that in some cases that I can not say manifests itself. ...

An important thing is also the WHERE you insert the mouse control. The flowchart can be very complex and perhaps double-click control should not be put where you would think but elsewhere. On the other hand, QB is not a real object programming and its sequential execution and events can only partially be managed outside of this lienarity.

What a pity! I've written thousands of lines of code to create a development environment that can serve to produce applications of various kinds on the same platform... and (maybe) I'll have to do without the double click!

For a few more months (!!!) I will keep trying... a system there has to be...








« Last Edit: February 21, 2020, 04:49:58 pm by krovit »
Nothing is easy, especially when it appears simple (and nothing could be as dangerous as trying to do good to others)

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: double click
« Reply #18 on: February 21, 2020, 05:20:58 pm »
Ciao Krovit se per te va bene continuo a risponderti in inglese in modo da non renderlo una comunicazione personale, d'altronde il tuo quesito è generalizzabile per gli interessi di tutti.

So I'm saying that IMHO the issue is the logic structure of the events that you are managing.

A click of a button of the mouse is a complex event made by detecting in sequence these 3 simple events
1 mouse button is up (not pressed/activated) --> 2 mouse button is down (pressed/activated) --> 3 mouse button is up (not pressed/activated)

A double click of a button of the mouse is a bigger complex event made by 2 mouse single click in a set range of time
  1 click of mouse button  --> 2 click of mouse button
  ^                                        ^
3 |     set interval of time         |
   ---------------------------------

Thinking about these informations it is clear that you can detect a double click only after have spent the set interval of time both if  you use a loop with TIMER both if you use a loop with flags.

About my attempt to shrink your initial code, I'm working on a detection in a single loop to make easier the use of a function that is the goal of your code posted.
In the while you confirm that you needn't a dragging function?
The Dragging event is another complex event (I say always complex because we have no native function that detect it and we must build something to manage it) in  which is detected the following events in sequence
1. mouse button up --> 2 mouse button down (activate/pressed) --> 3 mouse position changes --> 4 mouse button up (released/ not pressed)

Good luck


Programming isn't difficult, only it's  consuming time and coffee

Offline krovit

  • Forum Regular
  • Posts: 179
    • View Profile
Re: double click
« Reply #19 on: February 21, 2020, 07:23:08 pm »
Yes, of course, detecting mouse drag is an opportunity to consider to reduce the cases in which to monitor mouse behavior.

In the event of this event it would certainly be a single click. The conditions for defining double clicks are in fact the simultaneous occurrence of two conditions: 1) the reduced time between clicks; 2) have not moved.

However, to reduce the number of cases observed, additional commands must be inserted. Perhaps we have to say how much is to be agreed.

However it really seems that TIMER within a series of nested DO-LOOPs creates a kind of redundancy, of echo... which leads to delays in execution.

Thank you for the interest and also for the interesting flowchart.


____
Being human - that is, belonging to mankind - is really a mysterious, fascinating and wonderful condition, even truly supernatural. And also unmanageable (there is no "code" that can predict all behaviors and all reactions...): we are here to talk about mouse and right around and near us the covid19 reaps real victims...

« Last Edit: February 21, 2020, 07:28:19 pm by krovit »
Nothing is easy, especially when it appears simple (and nothing could be as dangerous as trying to do good to others)

Offline krovit

  • Forum Regular
  • Posts: 179
    • View Profile
Re: double click
« Reply #20 on: February 25, 2020, 08:09:57 am »
It took me days but maybe, I say maybe, I solved my problem (with the double click mouse...  to the rest of my life I'm still working on it)

I think the solution is useful for everyone.

This function provides the following result:
1) intercepts a single click isolated;
2) intercepts a click and deems it single if the next is pressed beyond the allowed time;
3) intercept one click, and check if you perform another one within the allotted time;
4) If the second click is within the allotted time then it's a double click!

The function does not cause delays in the execution of the application that remains fluid and you don't appreciate any slowing or jumping or momentary interruption.
 
The function intercepts the first click and places the cursor on the chosen field (of course you have to have a field to jump on).
On the field where you jumped intercept the possible second click.

Ultimately the routine handles clicks as naturally as on any other windows application.

Can it be improved?

Yes, Of course. For example, a first improvement would be to check whether the variables it carries with it and continuously monitors are really all indispensable.

I'm not going to try any change, at the moment ... ;) it took me too many days to get to this point and it only takes a nothing to destroy everything!


Code: QB64: [Select]
  1.   print Click%
  2.  
  3.  
  4.  
  5.  
  6. FUNCTION Click%
  7.         DO
  8.                 WHILE _MOUSEINPUT: WEND
  9.         mb = _MOUSEBUTTON(1) OR _MOUSEBUTTON(2) OR _MOUSEBUTTON(3)
  10.                         IF mb AND oldMouse = 0 THEN
  11.                                 passato=0
  12.                                 IF plusClick%(timer) = 2 THEN
  13.                                         Click%=2
  14.                                 else
  15.                                         Click%=1
  16.                                 end if
  17.                         END IF
  18.                         oldMouse = mb
  19.     LOOP UNTIL Click%
  20. FUNCTION plusClick%(t1#)
  21. static passato,t2#
  22.         DO
  23.         WHILE _MOUSEINPUT: WEND
  24.         mb2 = _MOUSEBUTTON(1) OR _MOUSEBUTTON(2) OR _MOUSEBUTTON(3)
  25.         IF mb2=0 THEN  'mouse up
  26.                         if timer-t2# <.3 then
  27.                                 t2#=timer
  28.                                 t1#=timer
  29.                                 passato=0
  30.                                 plusClick%=2
  31.                                 exit FUNCTION
  32.                         end     if
  33.                         if timer-t1#<.3 then
  34.                                 if passato=0 then  'first mouse in time
  35.                                         passato=38
  36.                                         t1#=timer
  37.                                         t2#=timer
  38.                                         plusClick%=1
  39.                                 elseif passato=38 then  'mouse up ignored
  40.                                         passato=0
  41.                                         t1#=timer
  42.                                         t2#=timer
  43.                                         plusClick%=1
  44.                                 end if
  45.                         else  'useless to monitor yet because time has passed
  46.                                 t1#=timer
  47.                                 t2#=timer
  48.                                 passato=0
  49.                                 plusClick%=1
  50.                         end if
  51.                 END IF
  52.     LOOP until plusClick%
  53.  
  54.  
  55.  



« Last Edit: February 25, 2020, 11:00:48 am by krovit »
Nothing is easy, especially when it appears simple (and nothing could be as dangerous as trying to do good to others)

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: double click
« Reply #21 on: February 25, 2020, 07:42:33 pm »
Good Krovit, it seems that you have found your way to solve the issue.
Well done.
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: double click
« Reply #22 on: February 25, 2020, 09:41:51 pm »
Yes congratulations krovit.

I am glad to find Terry's system thank's to this thread.
« Last Edit: February 25, 2020, 10:44:21 pm by bplus »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: double click
« Reply #23 on: February 25, 2020, 10:28:22 pm »
Hmm, this reminded me of the code I posted in Bill's program thread.

https://www.qb64.org/forum/index.php?topic=2226.msg114708#msg114708
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline krovit

  • Forum Regular
  • Posts: 179
    • View Profile
Re: double click
« Reply #24 on: February 26, 2020, 03:43:59 am »
Thank you all!

There is no perfect algorithm, there are only those that work better than others in certain contexts.
The real trick is to predict the predictable and try to manage it better writing a code that is as adaptable to any situation without too upheavals... but it's not always possible.
The greater the needs and the greater the difficulty in solving them.

Everyone's contribution is important: where one does not arrive another and vice versa.
And it applies to anything in life...

« Last Edit: February 26, 2020, 04:21:57 am by krovit »
Nothing is easy, especially when it appears simple (and nothing could be as dangerous as trying to do good to others)