IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Application qui perd le focus après appel .ShowDialog


Sujet :

VB.NET

  1. #1
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut Application qui perd le focus après appel .ShowDialog
    Un truc bien casse pied avec VB :

    Vous avez une application ; dans une fenêtre vous affichez une autre fenêtre avec .ShowDialog

    Dans certains cas après que l'utilisateur (ou votre code) ait fermé la fenêtre ouverte avec .ShowDialog, votre fenêtre de départ ne retrouve pas le focus. Pire elle peut être masquée par d'autres applications ouvertes !

    Solution : ajouter Me.BringToFront() après l'appel de .ShowDialog :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                CentrerFenetre(Me, FrmDiag)
                FrmDiag.ShowDialog()
                Me.BringToFront()
    Code de la sub de centrage :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        Public Sub CentrerFenetre(FenetreActuelle As Form, FenetreAOuvrir As Form)
            'ATTENTION
            'Pour que ça fonctionne il faut que dans les propriétées de la fenête, StartPosition soit réglé sur Manual
            If FenetreAOuvrir.Width <= FenetreActuelle.Width Then
                FenetreAOuvrir.Left = CInt(FenetreActuelle.Left + (FenetreActuelle.Width - FenetreAOuvrir.Width) * 0.5)
            Else
                FenetreAOuvrir.Left = FenetreActuelle.Left
            End If
            If FenetreAOuvrir.Height <= FenetreActuelle.Height Then
                FenetreAOuvrir.Top = CInt(FenetreActuelle.Top + (FenetreActuelle.Height - FenetreAOuvrir.Height) * 0.5)
            Else
                FenetreAOuvrir.Top = FenetreActuelle.Top
            End If
        End Sub
    Parfois, cette manipulation ne fonctionne pas, notamment dans le cas suivant :
    - depuis une fenêtre A vous affichez une fenêtre B avec .ShowDialog()
    - B correspond à un traitement, avec une barre de progression
    - à la fin du traitement :
    - en cas d'échec du traitement on ferme B et on revient à A
    - en cas de succès du traitement on ferme B, on ferme A et on ouvre la fenêtre C

    Ce cas de figure se présente lorsqu'on passe d'une étape à l'autre d'un traitement de données, l'étape 'i' étant la fenêtre A, l'étape 'i+1' étant la fenêtre C, et B étant la barre de progression

    La solution consiste à utiliser le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    'Dans le code de A :
        CentrerFenetre(Me, B)
        B.ShowDialog
        Me.BringToFront()
     
    'Dans le code de B, en cas de succès (on "passe" de A à C) :
        Me.Hide()
        Call TransmettrePositionFenetre(A, C) 'Pour afficher C au même endroit que A
        C.Show()
        A.Hide()
     
    'Dans le code de C, utiliser l’événement Shown :
        Private Sub C_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
            Me.BringToFront()
            Me.Focus()
        End Sub
     
    'Dans un module :
        Public Sub TransmettrePositionFenetre(FenetreActuelle As Form, FenetreAOuvrir As Form)
            'ATTENTION
            'Pour que ça fonctionne il faut que dans les propriétées de la fenêtre StartPosition soit réglé sur Manual
            FenetreAOuvrir.Top = FenetreActuelle.Top
            FenetreAOuvrir.Left = FenetreActuelle.Left
        End Sub
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  2. #2
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir,

    NON ça c'est du bricolage, il faut utiliser le Owner disponible en 1er argument de la signature de la méthode ShowDialog. Pour se faire on créer une classe qui implémente l'interface IWin32Window :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    Public Class Win32Window
        Implements IWin32Window
        Private handle As IntPtr
     
        Public Sub New(window As IWin32Window)
            Me.handle = window.Handle
        End Sub
     
        Private ReadOnly Property IWin32Window_Handle() As IntPtr Implements IWin32Window.Handle
            Get
                Return handle
            End Get
        End Property
    End Class
    Dans la classe FrmMain de type Form qui devra avoir le focus après la fermeture de la FrmTest depuis l'appel de la méthode ShowDialog on déclare une variable privée de type Win32Window, on l'instancie dans le constructeur de FrmMain avec pour argument la référence à son parent (ici FrmMain) et on utilise cette variable plus tard lors de l'appel de la méthode ShowDialog de la classe FrmTest :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    Public Class FrmMain
     
    #Region " Field "
        Private m_Owner As Win32Window
    #End Region
     
    #Region " Constructor "
     
        Sub New()
            InitializeComponent()
            m_Owner = New Win32Window(Me)
        Ens Sub
    #End Region
     
    #Region " Method "
        Private Sub AShittyMethod()
            Dim frmTest As New FrmTest()
            frm.ShowDialog(m_Owner)
        End Sub
     
    #End Region
     
    End Class
    A mettre en place selon les spécificités de ton projet.
    On définie ainsi le parent et ce dernier conserve le focus.

    A+

  3. #3
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Intéressant

    J'avais essayé en passant simplement le nom de la fenêtre comme paramètre parent de .ShowDialog() mais ça ne fonctionnait pas

    Ta méthode permet donc de passer en paramètre le parent que l'on veut, y compris si il n'est pas la fenêtre appelante de .ShowDialog() ?

    Mais comment faire dans mon cas de figure avec les fenêtres A, B et C ? En effet, au moment de l'appel de B.ShowDialog() on ne sait pas encore si c'est A ou C qui devra être affichée et avoir le focus (c'est le succès ou l'échec du calcul dans le code de B.ShowDialog() qui détermine si on affiche A ou C) ?

    Citation Envoyé par wallace1 Voir le message
    Bonsoir,

    NON ça c'est du bricolage, il faut utiliser le Owner disponible en 1er argument de la signature de la méthode ShowDialog. Pour se faire on créer une classe qui implémente l'interface IWin32Window :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    Public Class Win32Window
        Implements IWin32Window
        Private handle As IntPtr
     
        Public Sub New(window As IWin32Window)
            Me.handle = window.Handle
        End Sub
     
        Private ReadOnly Property IWin32Window_Handle() As IntPtr Implements IWin32Window.Handle
            Get
                Return handle
            End Get
        End Property
    End Class
    Dans la classe FrmMain de type Form qui devra avoir le focus après la fermeture de la FrmTest depuis l'appel de la méthode ShowDialog on déclare une variable privée de type Win32Window, on l'instancie dans le constructeur de FrmMain avec pour argument la référence à son parent (ici FrmMain) et on utilise cette variable plus tard lors de l'appel de la méthode ShowDialog de la classe FrmTest :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    Public Class FrmMain
     
    #Region " Field "
        Private m_Owner As Win32Window
    #End Region
     
    #Region " Constructor "
     
        Sub New()
            InitializeComponent()
            m_Owner = New Win32Window(Me)
        Ens Sub
    #End Region
     
    #Region " Method "
        Private Sub AShittyMethod()
            Dim frmTest As New FrmTest()
            frm.ShowDialog(m_Owner)
        End Sub
     
    #End Region
     
    End Class
    A mettre en place selon les spécificités de ton projet.
    On définie ainsi le parent et ce dernier conserve le focus.

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  4. #4
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Le seul problème que tu rencontres concerne la perte du focus en passant de B vers A (son parent) à l'issu du long traitement.
    Lorsque tu affiches "C" c'est une nouvelle fenêtre qui prends obligatoirement le focus donc ça tu n'as pas à t'en soucier finalement.........
    Donc tu instancies Win32Window dans le constructeur de A et tu ajoutes Me lorsque tu appelles ShowDialog de B.....that's all.

    Si tu veux davantage d'explications tu postes un projet de circonstance et je te détaillerais comment faire car en l'état je ne connais pas le périmètre de ton projet !

    ++

  5. #5
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Citation Envoyé par wallace1 Voir le message
    Lorsque tu affiches "C" c'est une nouvelle fenêtre qui prends obligatoirement le focus donc ça tu n'as pas à t'en soucier finalement.........
    Justement ça ne fonctionne pas, c'est la fenêtre "C" qui m'a donné le plus de fil à retordre

    Sur un forum en anglais (mais que des vieux posts de 2001 et 2005) une des explications que j'avais trouvé était que pendant un court laps de temps aucune fenêtre n'était affichée ou complètement affichée et du coup face à cette situation windows passait le focus au logiciel suivant dans l'ordre du "Alt Tab", et ensuite la fenêtre C une fois affichée l'était en arrière plan, un autre logiciel ayant déjà pris le focus.

    Chose curieuse dont j'ai oublié de parler : dans la barre des tâches le nom de la fenêtre "C" de mon appli restait "enfoncé" comme si elle avait toujours le focus, alors qu'elle n'avait plus le focus et qu'elle était en arrière plan.

    C'était chiant : il fallait aller dans la barre des tâches, cliquer sur une autre appli, puis recliquer sur mon appli pour la remettre au premier plan.

    Mon appli est très grosse, il faudrait que je refasse un exemple plus simple
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Application qui plante au .close() après passage de .accdb à .mdb
    Par Kermichou dans le forum Bases de données
    Réponses: 0
    Dernier message: 17/07/2013, 15h16
  2. Réponses: 0
    Dernier message: 20/01/2012, 00h49
  3. TextBox qui perd le focus dès que l'on clique en dehors
    Par Takumi dans le forum Windows Presentation Foundation
    Réponses: 10
    Dernier message: 28/09/2010, 10h02
  4. [C#] [MSDE] Connexion qui se ferme après appel de fonction
    Par trotters213 dans le forum Windows Forms
    Réponses: 11
    Dernier message: 23/03/2005, 16h30
  5. Déterminer l'application qui a le Focus
    Par JakeGrafton dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 22/02/2004, 12h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo