Détecter un clic en dehors du formulaire (bureau ou autre appli)

Signaler
Messages postés
57
Date d'inscription
dimanche 24 février 2008
Statut
Membre
Dernière intervention
4 septembre 2011
-
Messages postés
57
Date d'inscription
dimanche 24 février 2008
Statut
Membre
Dernière intervention
4 septembre 2011
-
Bonjour ! Et bonne année à tous

J'en viens à vous afin d'avoir un petit coup de pouce. J'ai beau chercher, mais je n'arrive pas à me dépétrer de ce soucis.

J'essaye de déclencher un évènement lorsque je clique hors d'un des formulaires de mon application.
J'ai bien sûr trouvé l'évènement "Desactivate" qui fait ceci, mais le problème est que cet évènement est aussi déclencher à la fermeture du formulaire avec la croix et ça me pose problème.

Y'at-il une solution prévue par le Net Framework ? Ou faut-il bidouiller quelque chose avec les API windows ?

Merci d'avance pour votre aide

5 réponses

Messages postés
78
Date d'inscription
jeudi 21 avril 2005
Statut
Membre
Dernière intervention
15 novembre 2018

bonjour,

je ne vois pas très bien ce que tu veux faire.
mais pour moi la seul solution pour détecter un clique hors d'une form de ton application est de faire un hook sur la souris via les API (SetWindowsHookEx, UnhookWindowsHookEx, CallNextHookEx).
Messages postés
57
Date d'inscription
dimanche 24 février 2008
Statut
Membre
Dernière intervention
4 septembre 2011

Bonjour Breton51 et merci pour la piste.
En effet, au fil des lectures, j'ai fini par tomber sur quelques articles qui parlaient de Hook souris.
Mais bon, n'étant pas bien doué avec les APIs, j'ai continué de chercher avec les méthodes du framework.

En fait, si je cherche à faire ça, c'est que, comme beaucoup, j'essaye de faire un petit color picker de base avec une fenêtre de zoom et tout.

Du coup, j'ai trouvé un système qui m'a l'air assez simple avec un System.Timers.Timer qui est déclenché par un clic sur un bouton du formulaire ou autre. Ce timer déclenche un Delegate qui lance une fonction d'affichage.
Je ne connaissais pas les Delegate, mais ça m'a l'air super ce truc . Voilà à quoi ressemble mon code :

Public Class Form1
    Private WithEvents myTimer As Timers.Timer
    Private Delegate Sub delegPositionChange(ByVal mousePoint As Point)

    Private ActualMousePos As Point

    Private Sub Form1_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Click
        myTimer = New Timers.Timer(50)
        myTimer.Start()
    End Sub
    
    Private Sub myTimerElapsed(ByVal sender As System.Object, _
              ByVal e As System.EventArgs) Handles myTimer.Elapsed
        ActualMousePos = Control.MousePosition

        If Me.InvokeRequired Then
            Me.Invoke(New delegPositionChange(AddressOf _
                 AfficheMousePosition), ActualMousePos)
        End If

        'on arrête le timer si le bouton gauche est cliqué même 
        'en dehors de la fenêtre
        If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then
            myTimer.Stop()
            myTimer.Dispose() : myTimer = Nothing
        End If
    End Sub

    Private Sub AfficheMousePosition(ByVal theMousePos As Point)
        Label1.Text = "X=" & theMousePos.X
        Label2.Text = "Y=" & theMousePos.Y
    End Sub
End Class


Ca marche du tonerre et je peux aussi bien récupérer la position que la couleur ...
Maintenant, je ne sais pas si je me sers correctement des Delegate et si c'est bien optimisé d'utiliser un Timer .
A ce que j'ai pu voir, les timers fonctionnent sur des Threads séparés, donc même si je dois faire un lourd traitement en même temps, ça ne gênera pas si j'ai bien compris ?
Messages postés
1402
Date d'inscription
mardi 1 mai 2007
Statut
Membre
Dernière intervention
7 octobre 2012
5
Bonjour,
Si ton seul problème est avec la fermeture du formulaire, utilises une variable booleenne.
Que tu metteras à True dans l' événement Unload du Formulaire.


Dim Is_Unload As Boolean

Sub Desactivate()
If Is_Unload Then Exit Sub
'Suite du traitement
End Sub


[] Ce qui va sans dire. va mieux en le disant.
Messages postés
1835
Date d'inscription
vendredi 13 mai 2005
Statut
Membre
Dernière intervention
20 novembre 2013
9
Salut,

peut être une piste/solution sans pretention aucune :

l'idée est de comparer à intervale régulié(via un timer), le handle la fenetre qui est au premier plan avec la form. Si ce n'est plus la form on arrete

ATTENTION c'est du VB6 donc faudra transcrire

Dans un module:
Option Explicit

Public Declare Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function GetForegroundWindow Lib "user32" () As Long

Public Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long

Public MeHwnd As Long
Sub CheckForegroundWindow(ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long)
    'quelle fenetre est au premier plan ?
    If Not GetForegroundWindow = MeHwnd Then 'si ce n'est pas la form
        'ici l'action à executer
        demo
        DoEvents
    End If
End Sub

Sub demo()
    'fermeture de la form et arret du timer
    Unload UserForm1
    KillTimer MeHwnd, 0
End Sub
Sub DebutDemo()
   UserForm1.Show
End Sub


dans le code la form :

Option Explicit


Private Sub CmdBtnOK_Click()
    demo
End Sub

Private Sub UserForm_Initialize()
    'on récupère le handle de notre form
    MeHwnd = FindWindowA(vbNullString, Me.Caption)
    'on lance le timer
    SetTimer MeHwnd, 0, 100, AddressOf CheckForegroundWindow
End Sub


L'inconveniant, peut être, le timer... mais bon cela fonctionne donc à toi de voir

A+
Messages postés
57
Date d'inscription
dimanche 24 février 2008
Statut
Membre
Dernière intervention
4 septembre 2011

Bonjour Bigfish et Libre_Max et merci pour votre passage et vos propositions

En effet, ce sont deux autres solutions auxquelles je n'avais pas pensé. Ta solution a l'air pas mal Bigfish et ressemble un peu à la mienne pour l'utilisation d'un Timer. Seulement, si j'ai bien capté, Ton timer à toi est démarré dès le lancement de l'appli, alors que le miens est lancé uniquement quand je passe en mode "capture couleurs".

Je pense que je vais rester avec mon système, car c'est celui que je comprends le mieux et on reste en .Net.

En tous cas, merci pour vos idées qui sont tout de même intéressantes et qui pourraient bien me resservir ailleurs