locked
Dessiner un contrôle qui soit indépendant de la résolution d'écran RRS feed

  • Question

  • Bonjour,

    Je développe une appli WinForm en VB.NET sous VS 2008, pour le Framework 2.0.

    J'ai réalisé un contrôle dont le contour est un cercle. J'utilise pour le dessiner un DrawEllipse(Pen, Rectangle). L'origine et les dimensions du rectangle sont en fait l'origine et les dimensions du contrôle, exprimés en pixels lors de sa création (Width=Height pour avoir un cercle).

    Mais la restitution n'est pas toujours correcte en fonction de la taille et de la résolution de l'écran cible : Le cercle apparait parfois comme une ellipse et n'est pas placé au bon endroit sur la Form alors que les contrôles standards sont bien conformes.

    Comment puis-je faire pour palier ces inconvénients ?

    Merci de vos suggestions.

     


    Alain
    mardi 20 avril 2010 16:03

Réponses

  • Bonsoir Alex,

    Oui, mon contrôle est un carré et le cercle est dessiné dedans, avec un léger retrait de 4 pixels sur chaque coté, comme le montre le code du Paint :

     e.Graphics.DrawEllipse(cr, New Rectangle(retrait, retrait, .Width - retrait * 2, .Height - retrait * 2))

    J'ai fait quelques observations qui me rendent perplexe...

    Sur le moniteur (19" à tube) où j'ai observé le problème, sous W7, j'ai essayé plusieurs résolutions d'écran : 1600x1200, 1360x1024, 1360x768, 1280x720, 1280x960, 1280x800 et 1024x768 ; j'observe toujours une ovalisation +/- importante de mon cercle et un décalage dans son positionnement X,Y. Ce qui est plus choquant et totalement inattendu c'est que j'observe également une ovalisation des boutons radios standards de l'IHM, lorsque Q=X/Y est > 1,333 !!

    Comment expliquer cela ? Sous W7 l'IHM est donc déformée en fonction de la résolution d'écran choisie ??

    Sur un ordinateur portable 1440x900 (Q=1,6) sous W7, tout va bien mais lorsque je change de résolution (1280x720 - Q=1,777 et 1152x864 - Q=1,333) alors une légère déformation des boutons radios apparait sous forme d'un étirement respectivement vertical et horizontal. Dans tous ces cas mon contrôle est bien positionné mais subit aussi la même faible déformation que les BR.

    Sur un autre portable en 1024X768 et 800x600, sous XP, tout est correct (les Q=X/Y sont ici identiques, = 1,333).

    J'en conclus, et j'aimerais avoir votre avis :

    1. la carte graphique qui pilote le moniteur 19" à tube ne fonctionne pas correctement sous W7 car aucune résolution ne donne de résultat correct
    2. le rendu d'une application WinForm dépend de la résolution d'écran choisie, c'est à dire que le GDI de W7 n'est pas indépendant de celle-ci.
    Merci de votre analyse.
    Bien cordialement

     


    Alain
    vendredi 23 avril 2010 21:57

Toutes les réponses

  • Bonjour,

    si ton Width=Height, alors je trouve cela bizarre de ne pas voir un cercle. Ma seule idée est que tu n'as pas une bonne résolution d'écran, celle-ci étire tout les éléments.

    Es-ce que tu aurais un bout de code?


    Microsoft MVP C# || gabrielmongeon.com
    mardi 20 avril 2010 19:47
  • Voici le code de ma classe UCB qui implémente ce contrôle.

    Public Class UCB
    
    #Region "Contexte de la classe"
    
      Private cr1 As Pen = New Pen(Color.Black, 1)
      Private pt1 As New Pen(Color.Red, 2)
      Private cr2 As Pen = New Pen(Color.DarkGray, 1)
      Private pt2 As New Pen(Color.DarkGray, 2)
    
      Private radians As Single          ' Angle en radians
      Private rayon As Double           ' Rayon du cercle
      Private pPoint As PointF          ' Matérialisation du point
      Private centre As PointF          ' Centre du cercle
      Private zéro As PointF           ' Origine des angles (axe des X)
      Private retrait As Double = 4        ' Rayon du cercle = Width/2 - retrait        
      Private coup As Integer = 1         ' Pour le MouseMove
    #End Region
    
    #Region "Propriétés"
      ''' <summary>
      ''' Angle exprimé en degrés
      ''' </summary>
      ''' <value></value>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Property Angle() As Single
        Get
          Return radians * (180 / Math.PI)
        End Get
        Set(ByVal value As Single)
          radians = Math.PI * value / 180.0
          With Me.ClientRectangle
            pPoint = New PointF(centre.X + rayon * Math.Cos(radians), _
                    centre.Y - rayon * Math.Sin(radians))
          End With
          Me.Invalidate()
        End Set
      End Property
      ''' <summary>
      ''' Activation / désactivation
      ''' </summary>
      ''' <value>Treu / False</value>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Property Enable() As Boolean
        Get
          Return Me.Enabled
        End Get
        Set(ByVal value As Boolean)
          If Me.Enabled <> value Then Me.Invalidate()
          Me.Enabled = value
        End Set
      End Property
    #End Region
    
    #Region "EventHandler"
      ' Evenement émis vers l'objet qui a créé l'instance
      Public Event AngleChange(ByVal obj As Control, ByVal angle As Single)
    #End Region
    
      ''' <summary>
      ''' Création d'une instance
      ''' </summary>
      ''' <param name="coté">coté du carré</param>
      ''' <remarks></remarks>
      Public Sub New(ByVal coté As Double)
    
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
    
        ' Add any initialization after the InitializeComponent() call.
        Size = New Size(coté, coté)
      End Sub
    
      Private Sub UCB_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Dim r As Rectangle = New Rectangle(pPoint.X - 1, pPoint.Y - 1, 4, 4)
          If r.Contains(e.Location) Then
            Cursor = Cursors.Hand
          End If
        End If
      End Sub
      Private Sub UCB_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left AndAlso Cursor = Cursors.Hand Then
          If coup > 0 Then
            coup -= 1
          Else
            coup = 1
            ' Calculer le nouvel angle
            Angle = GetArc(e.Location)
            RaiseEvent AngleChange(Me, Angle)
          End If
        End If
      End Sub
      Private Sub UCB_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Cursor = Cursors.Arrow
        End If
      End Sub
    
      Private Sub UCB_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    
        Dim cr, pt As Pen
    
        '-- Choisir les outils = f(Enabled)
        If Me.Enabled Then
          cr = cr1
          pt = pt1
        Else
          cr = cr2
          pt = pt2
        End If
    
        '-- Dessiner
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
        With Me.ClientRectangle
          ' Le cercle
          e.Graphics.DrawEllipse(cr, New Rectangle(retrait, retrait, .Width - retrait * 2, .Height - retrait * 2))
          ' L'axe
          e.Graphics.DrawLine(cr, centre, pPoint)
          ' Le point
          e.Graphics.DrawPie(pt, pPoint.X - 1, pPoint.Y - 1, 4.0F, 4.0F, 0.0F, 360.0F)
        End With
    
      End Sub
    
      Private Sub UCB_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
        With Me.ClientRectangle
          rayon = Width / 2 - retrait
          centre = New PointF(.Width / 2, .Height / 2)    ' Centre du cercle
          zéro = New PointF(.Width - retrait, .Height / 2)  ' Origine des angles
        End With
      End Sub
    
      ''' <summary>
      ''' Get arc
      ''' </summary>
      ''' <param name="p"></param>
      ''' <returns>L'angle en degrés</returns>
      ''' <remarks></remarks>
      Private Function GetArc(ByVal p As PointF) As Double
        Dim x, y, radians As Double
    
        x = p.X - centre.X
        y = centre.Y - p.Y
        radians = Math.Atan2(y, x)
        Return radians * (180 / Math.PI)
    
      End Function
    
    End Class
    

    Le New créé et dimensionne le contrôle. Le Paint dessine le cercle avec un rayon et un point.

    L'application créée le controle de la façon suivante :

        '-- Initialiser l'onglet Commentaires --
        Boule = New BouleAch.UCB(30)          ' Créer à 30 de côté
        Boule.Location = New Point(18, 93)       ' Placement en pixels
        Boule.Angle = My.Settings.Angle         ' En degrés
        GroupBox6.Controls.Add(Boule)         ' Add to

    En fonction de l'écran utilisé, le contrôle est parfois mal positionné dans le GroupBox6 et apparait comme une ellipse plus haute que large.

    Je ne sais pas joindre une image...

    Merci

     


    Alain
    mardi 20 avril 2010 21:14
  • Bonjour AchLog,

     

    J’ai testé votre contrôle pour toutes les résolutions que mon écran supporte. Pour quelques résolutions inferieures (ex. 1280x720) je vois une déformation du contrôle et il semble plus haut que large.

     

    En ce qui concerne la position par rapport aux autres contrôles, avez-vous essayé de vérifier en mode debug les coordonnées des contrôles ‘correctes’ et les comparer avec les coordonnées de votre contrôle ? Le déplacement est-il horizontale ou verticale ?

     

    Moi, à partir de mes observations, je crois qu’il s’agit d’une question de résolution, qui fait que pour certaines configurations les contrôles s’allongent en haut. Mais si vous observez des coordonnées différentes, il s’agit peut-être d’une autre cause.

     

    Cordialement,

    Alex


    Appel à contribution ! http://social.msdn.microsoft.com/Forums/fr-FR/vbasicfr/thread/bd974e0e-5519-4122-b8fc-3b998207c34f
    jeudi 22 avril 2010 09:03
  • Merci Alex pour ce travail d'investigation que vous avez fait.

    J'ai un lointain souvenir d'une question d'unité dans les dialogues, justement concernant les contrôles afin qu'ils soient indépendants de la résolution d'écran. Mais je ne sais plus où trouver cette information ni si elle est toujours à l'ordre du jour.

    Pour répondre à vos questions :

    Je n'ai pas fait d'examen comparatif de la question des coordonnées mais je vais regarder ça. Quant au déplacement, il est essentiellement vertical ainsi que l'allongement, ce qui donne une ellipse verticale mal placée.

    Mais il faut noter que certaines résolution d'écran fonctionnent bien.

    Avez-vous des précisions sur le système de coordonnées utilisés pour placer et dimensionner les contrôles ?

    Je réponds ici rapidement mais je ferai une réponse plus complète dès que je pourrai faire des essais plus poussés.

    Cordialement


    Alain
    jeudi 22 avril 2010 20:14
  • Bonjour,

     

    Avez-vous tenu compte de fait que votre contrôle est en fait un rectangle transparent avec un cercle dessiné, et sa propriété Location signifie les coordonnées du point ‘top-left’ de ce rectangle ? Par contre, je vois que dans votre contrôle vous utilisez le centre du cercle. Y a-t-il peut-être une confusion dans cet aspect ?

     

    Cordialement,

    Alex


    Appel à contribution ! http://social.msdn.microsoft.com/Forums/fr-FR/vbasicfr/thread/bd974e0e-5519-4122-b8fc-3b998207c34f
    vendredi 23 avril 2010 08:21
  • Bonsoir Alex,

    Oui, mon contrôle est un carré et le cercle est dessiné dedans, avec un léger retrait de 4 pixels sur chaque coté, comme le montre le code du Paint :

     e.Graphics.DrawEllipse(cr, New Rectangle(retrait, retrait, .Width - retrait * 2, .Height - retrait * 2))

    J'ai fait quelques observations qui me rendent perplexe...

    Sur le moniteur (19" à tube) où j'ai observé le problème, sous W7, j'ai essayé plusieurs résolutions d'écran : 1600x1200, 1360x1024, 1360x768, 1280x720, 1280x960, 1280x800 et 1024x768 ; j'observe toujours une ovalisation +/- importante de mon cercle et un décalage dans son positionnement X,Y. Ce qui est plus choquant et totalement inattendu c'est que j'observe également une ovalisation des boutons radios standards de l'IHM, lorsque Q=X/Y est > 1,333 !!

    Comment expliquer cela ? Sous W7 l'IHM est donc déformée en fonction de la résolution d'écran choisie ??

    Sur un ordinateur portable 1440x900 (Q=1,6) sous W7, tout va bien mais lorsque je change de résolution (1280x720 - Q=1,777 et 1152x864 - Q=1,333) alors une légère déformation des boutons radios apparait sous forme d'un étirement respectivement vertical et horizontal. Dans tous ces cas mon contrôle est bien positionné mais subit aussi la même faible déformation que les BR.

    Sur un autre portable en 1024X768 et 800x600, sous XP, tout est correct (les Q=X/Y sont ici identiques, = 1,333).

    J'en conclus, et j'aimerais avoir votre avis :

    1. la carte graphique qui pilote le moniteur 19" à tube ne fonctionne pas correctement sous W7 car aucune résolution ne donne de résultat correct
    2. le rendu d'une application WinForm dépend de la résolution d'écran choisie, c'est à dire que le GDI de W7 n'est pas indépendant de celle-ci.
    Merci de votre analyse.
    Bien cordialement

     


    Alain
    vendredi 23 avril 2010 21:57
  • Bonjour,

    1/Oui, pour vous en rendre compte, faites une capture d'écran, enregistrez là dans un fichier et regardez sur votre poste sous XP...

    2/Oui, c'est d'ailleurs pour cela que nouveau moteur graphique WPF résout ce problème.

    Cordialement


    Gilles TOURREAU - MVP C# - MCP - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    samedi 29 mai 2010 17:39
  • Bonsoir Gilles,

    Merci de votre message de confirmation.  Il me semble me souvenir que Windows utilise une unité spéciale, non les pixels, pour implanter les contrôles sur une Form, mais c'est un peu vague et lointain...

    Avez-vous connaissance de cela ?

    Cordialement.


    Alain
    samedi 29 mai 2010 19:49
  • Bonjour,

    Non... Pas à ma connaissance.

    Cordialement


    Gilles TOURREAU - MVP C# - MCP - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    dimanche 30 mai 2010 21:44
  • Bonsoir,

    Je reviens sur ce problème car j'en ai trouvé l'origine : C'est une question de police de caractères de Form associée à la propriété AutoScaleMode = Font.

    Je rappelle que mon appli est une Form qui incorpore un contrôle. Or ce contrôle est lui-même une Form et il dessine un cercle à sa surface (voir message initial et le code transmis le 20 avril). Les deux Form ont leur propriété AutoScaleMode = Font mais n'ont pas la même Font et c'est là la source du problème.

    Si on définit les deux Font identiques, alors le cercle tracé est bien toujours un cercle rond ! Ouf.

    Sur la plupart des écrans (et carte graphiques) la différence de Font ne pose pas de problème et l'appli fonctionne correctement, sur d'autres le cercle devient ovale.

    Reste encore à savoir pourquoi...

    Bien cordialement


    Alain
    lundi 14 juin 2010 22:42