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

Windows Presentation Foundation Discussion :

C# \ WPF : Problème de ratio dans un canvas.


Sujet :

Windows Presentation Foundation

  1. #1
    Nouveau candidat au Club
    Inscrit en
    Septembre 2010
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2
    Par défaut C# \ WPF : Problème de ratio dans un canvas.
    Bonjour à tous.

    Je suis entrain de développer une application qui permet d'afficher le fuselage d'un avion. Le problème est que le dessin contenue dans le canvas conserve pas du tout les bonnes proportions.

    Pourriez-vous m'éclairer sur mon erreur.

    Je vous en remercie par avance.


    Le code vu du xaml :
    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <Grid Name="rootGrid" Margin="0">
            <Grid x:Name ="chartGrid" Grid.Column="0" Grid.Row="0"
    			   ClipToBounds="True" Background="Transparent" SizeChanged="chartGrid_SizeChanged" />
     
            <Canvas x:Name="chartCanvas" MouseLeftButtonDown="OnMouseLeftButtonDown" ClipToBounds="True">
                <Canvas.RenderTransform>
                    <ScaleTransform x:Name="myScaler" ScaleX="1" ScaleY="1" CenterX="0" CenterY="0"/>
                </Canvas.RenderTransform>
            </Canvas>
        </Grid>

    Le code de l'évènement SizeChanged :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            private void chartGrid_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                this.chartCanvas.Width = this.chartGrid.Width;
                this.chartCanvas.Height =  this.chartGrid.Height;
            }

    Le code qui calcule la position du point par rapport à la taille du canvas :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public Point NormalizePoint(Point pt)
            {
                Point result = new Point();
                result.X = (pt.X - Xmin) * ChartCanvas.Width / (Xmax - Xmin);
                result.Y = ChartCanvas.Height - (pt.Y - Ymin) * ChartCanvas.Height / (Ymax - Ymin);
                return result;
            }

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Je ne sais pas trop quel est le problème, mais voilà déjà 2 remarques pour te simplifier la vie :

    - inutile de gérer l'évènement SizeChanged de la grille pour changer la taille du Canvas : si tu ne changes pas l'alignement par défaut (Stretch), le canvas prendra tout seul la taille de la Grid

    - Pour obtenir la taille réelle d'un contrôle, utilise les propriétés ActualWidth et ActualHeight plutôt que Width et Height. Ces dernières n'ont pas forcément une valeur significatives si la hauteur et la largeur sont automatiques (d'ailleurs je suppose que c'est pour ça que tu les avais définies explicitement dans le SizeChanged)

  3. #3
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut "scaler" les objets dans un canvas
    bonjour,Julien board ,comme le grand julius ceasar,
    "le plus terrible est le plus petit d'entre eux" (proverbe arabe).

    Il me semble que c'est l'approche inverse qu'il faut faire .C'est plutot zoomer dans le canvas auquel il faut penser,comme ca tu y mettras les fuselages de 2A380 ,parce que l'approche en matiere de dessin 2d ou 3d c'est toujours mettre les dimensions des objets en unites de bases (point ou pixel ) non lies aux dimensions du controle utilise ( convertir en millimetres pour le papier eventuellement).
    Mais il n'est pas question de s'imposer des contraintes en unites de dessin,a cause des dimensions d'un canvas(ou d'un ecran autrement).
    Il faut savoir aussi une chose comme l'a dit notre ami ,que le canvas a part defaut une largeur et hauteur indefinie.
    Dans tous les cas de figure je t'envoie ci-apres le code d'un "zoomable canvas" qui je l'espere t'aideras:
    - derivee simplement du canvas
    - avec 1 methode override ,cet override mets les dimensions du canvas assez juste pour contenir tous les objets inclus dans celui (quelque soit le total des dimensions).Ca devient un "viewport":
    -a l'utilisation on le droppe dans un scrollviewer et on ajoute un slider
    -ScaleX et ScaleY du canvas sont bindes a valeur du slider(trackbar)
    caramba !
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    /// code du custom canvas
    using System;
    using System.Windows;
    using System.Windows.Controls;
    namespace ZoomCanvas 
    {
    public class ZoomableCanvasControl : Canvas
    {
    static ZoomableCanvasControl()
    {
    DefaultStyleKeyProperty.OverrideMetadata(
    typeof(ZoomableCanvasControl),
    new FrameworkPropertyMetadata(
    typeof(ZoomableCanvasControl)));
    }
    protected override Size MeasureOverride(
    Size constraint)
    {
    double bottomMost = 0d;
    double rightMost = 0d;
    // Loop through the child FrameworkElements,
    // and track the highest Top and Left value
    // amongst them.
    foreach(object obj in Children)
    {
    FrameworkElement child = obj as FrameworkElement;
    if(child != null)
    {
    child.Measure(constraint);
    bottomMost = Math.Max(
    bottomMost,
    GetTop(child) +
    child.DesiredSize.Height);
    CHAPTER 4 ■ CREATING USER AND CUSTOM CONTROLS 223
    rightMost = Math.Max(
    rightMost,
    GetLeft(child) +
    child.DesiredSize.Width);
    }
    }
    if(double.IsNaN(bottomMost)
    || double.IsInfinity(bottomMost))
    {
    bottomMost = 0d;
    }
    if(double.IsNaN(rightMost)
    || double.IsInfinity(rightMost))
    {
    rightMost = 0d;
    }
    // Return the new size
    return new Size(rightMost, bottomMost);
    }
    }
    }
    code du winform utilisant le canvas:
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    <Window x:Class="ZoomCanvas.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:test="clr-namespace:ZoomCanvas;assembly="
    Title="WPF canvas " Height="300" Width="300" >
    <Window.Resources>
    <Style TargetType="Button">
    <Setter Property="Width" Value="Auto" />
    <Setter Property="Height" Value="24" />
    </Style>
    </Window.Resources>
    <DockPanel>
    <Slider
    DockPanel.Dock="Bottom"
    x:Name="zoomSlider"
    Minimum="0.1"
    Maximum="5"
    Value="1"
    />
    <ScrollViewer
    VerticalScrollBarVisibility="Auto"
    HorizontalScrollBarVisibility="Auto">
    <test:ZoomableCanvasControl x:Name="zoomControl">
    <Canvas.LayoutTransform>
    <ScaleTransform
    ScaleX="{Binding Path=Value, ElementName=zoomSlider}"
    ScaleY="{Binding Path=Value, ElementName=zoomSlider}"
    />
    </Canvas.LayoutTransform>
    <Rectangle
    Canvas.Top="0"
    Canvas.Left="0"
    StrokeThickness="2"
    Stroke="Red"
    Width="50"
    Height="50"
    />
    <Rectangle
    Canvas.Top="50"
    Canvas.Left="50"
    StrokeThickness="2"
    Stroke="Blue"
    Width="150"
    Height="150"
    />
    <Rectangle
    Canvas.Top="200"
    Canvas.Left="200"
    StrokeThickness="2"
    Stroke="Green"
    Width="200"
    Height="200"
    />
    </test:ZoomableCanvasControl>
    </ScrollViewer>
    </DockPanel>
    </Window>
    Lux fat...Alea Jacta est aurais dit un romain il y a 1600 ans ...
    Les lumieres de l'esprit n'ont pas d'epoque ni de contrees....
    J'aime lire l'histoire ,j'ai la conquete des gaules dans ma biblio et la republique de Ciceron.

    Bon soiree et bonne fete de noel....

  4. #4
    Nouveau candidat au Club
    Inscrit en
    Septembre 2010
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2
    Par défaut
    Bonjour,

    Tout d'abord merci pour vos responses.

    Il me semble que j'ai mal engagé le developpement et la liste des problemes s'allonge.

    Je n'ai malhereusement pas compris comment recupere les dpix et dpiy pour les setter a chaque points du dessin.

    Du coup lorsque je change de resolotion d'écran la difference entre Height et Width s'aggrave.

    Pourriez-vous m'aiguiller.

    Merci

  5. #5
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    rebonjour,Julien board ,grand julius ceasar
    bon pour la distorsion height et width il faut mettre le canvas dans un Viewbox avec la propriete du ViewBox à Stretch="Uniform".

    Pour ce qui est du DPI d'ecran d'abord :
    1/ Toutes les coordonnees et tailles dans le system WPF defaut sont exprimees en unite de 1/96 dot per Inch(DPI),designee dans XAML par
    * px: unite DPI par defaut WPF soit 1 dot =1/96 eme Inch
    c.a.d quand tu ecris par exemple sans specifier d'unite canvas.width=100
    tu veux dire 100 *(1/96 inch)

    Voici la table de conversion des unites -je souligne- drectement utilisables dans l'interface WPF:
    • in: unites inches; 1 in = 96px
    • cm: unites centimeters; 1 cm = (96/2.54) px
    • pt: unites points; 1pt = (96/72) px

    Si on a des millemetres dans le ViewPort il faut evidemment convertir en cm d'abord puisque WPF ne gere pas cette unite.

    Maintenant je reviens à ce que j'ai dit hier le ViewPort Utilsateur avec ses Unites Universelles(world) .
    Je te joins ci-apres un code exemple pour un Wpf Chart qui montre comment utiliser un ViewPort.
    En gros on utilise les unites qu'on veut et on convertit ensuite les points et les tailles des objets en coord. WPF avant affichage.
    La subtilite de tout ca vient de ce que quand tu multiple par canvas.width ou canvas.height tu as fait une conversion DPI (1/96 inch) implicite.
    C'est un peu la prose de Monsieur Jourdain.
    Voici le bout de code XAML:

    Code xml : 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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
     
    <Window x:Class="WpfAppChart.plotChart2D"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Chart2D Coordinate System"
    Height="420" Width="360">
        <Viewbox Stretch="Uniform">
            <StackPanel Height="420" Width="360">
                <Canvas x:Name="plotCanvas" ClipToBounds="True"
    Width="300" Height="250"
    Margin="30,30,30,30">
                    <Rectangle x:Name="plotArea"
    Width="300" Height="250"
    Stroke="Black"
    StrokeThickness="1"/>
                </Canvas>
                <Grid Width="340" Height="100"
    HorizontalAlignment="Left"
    VerticalAlignment="Top">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="60" />
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition Width="60"/>
                        <ColumnDefinition Width="110" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Column="0" Grid.Row="0"
    Margin="25,5,10,5">XMin</TextBlock>
                    <TextBox Name="tbXMin" Grid.Column="1"
    Grid.Row="0"
    TextAlignment="Center">0</TextBox>
                    <TextBlock Grid.Column="2" Grid.Row="0"
    Margin="25,5,10,5">XMax</TextBlock>
                    <TextBox Name="tbXMax" Grid.Column="3"
    Grid.Row="0"
    TextAlignment="Center">10</TextBox>
                    <TextBlock Grid.Column="0" Grid.Row="1"
    Margin="25,5,10,5">YMin</TextBlock>
                    <TextBox Name="tbYMin" Grid.Column="1"
    Grid.Row="1"
    TextAlignment="Center" >0</TextBox>
                    <TextBlock Grid.Column="2" Grid.Row="1"
    Margin="25,5,10,5">YMax</TextBlock>
                    <TextBox Name="tbYMax" Grid.Column="3"
    Grid.Row="1"
    TextAlignment="Center">10</TextBox>
                    <Button Click="btnApply_Click"
    Margin="40,20,20,0"
    Height="25" Grid.ColumnSpan="2"
    Grid.Column="0" Grid.Row="2">Apply
                    </Button>
                    <Button Click="btnClose_Click"
    Margin="40,20,20,0"
    Height="25" Grid.ColumnSpan="2"
    Grid.Column="2" Grid.Row="2">Close
                    </Button>
                </Grid>
            </StackPanel>
        </Viewbox>
    </Window>
    Voici le bout de code behind-code:
    Code c# : 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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfAppChart
    {
        /// Logique d'interaction pour Chart2D.xaml
     
        public partial class plotChart2D : Window
        {
     
            /// Dimension du ViewPort Personnel en Unites Universelles
            /// de l'Utilisateur(mm ou autres  cm,metres....)
     
            private double xMin = 0.0;
            private double xMax = 10.0;
            private double yMin = 0.0;
            private double yMax = 10.0;
            private Line line1;
            private Polyline polyline1;
            public plotChart2D()
            {
                InitializeComponent();
                AddGraphics();
            }
            private void AddGraphics()
            {
                line1 = new Line();
                line1.X1 = XNormalize(2.0);
                line1.Y1 = YNormalize(4.0);
                line1.X2 = XNormalize(8.0);
                line1.Y2 = YNormalize(10.0);
                line1.Stroke = Brushes.Blue;
                line1.StrokeThickness = 2;
                plotCanvas.Children.Add(line1);
                polyline1 = new Polyline();
                polyline1.Points.Add(new Point(XNormalize(8),
                YNormalize(8)));
                polyline1.Points.Add(new Point(XNormalize(6),
                YNormalize(6)));
                polyline1.Points.Add(new Point(XNormalize(6),
                YNormalize(4)));
                polyline1.Points.Add(new Point(XNormalize(4),
                YNormalize(4)));
                polyline1.Points.Add(new Point(XNormalize(4),
                YNormalize(6)));
                polyline1.Points.Add(new Point(XNormalize(6),
                YNormalize(6)));
                polyline1.Stroke = Brushes.Red;
                polyline1.StrokeThickness = 5;
                plotCanvas.Children.Add(polyline1);
            }
            /// Conversion des Coordonnees Utilisateurs en Coordonnees DPI(ppx)
            /// on a: x(ppx) = x(mm) *Largeur Canvas(ppx)/ Largeur ViewPortUser(mm)  
            private double XNormalize(double x)
            {
                double result = (x - xMin) *
                plotCanvas.Width / (xMax - xMin);
                return result;
            }
            /// On a: y(ppx) = y(mm) *Hauteur Canvas(ppx)/ Hauteur ViewPortUser(mm)  
            /// le resultat doit etre complemente par rapport à Canvas Height pour avoir des coordonnees y
            /// comptees vers le haut:
            /// y(ppx) =Hauteur Canvas(ppx)- y(mm) *Hauteur Canvas(ppx)/ Hauteur ViewPortUser(mm)  
            private double YNormalize(double y)
            {
                double result = plotCanvas.Height - (y - yMin) *
                plotCanvas.Height / (yMax - yMin);
                return result;
            }
            private void btnClose_Click(object sender,
            EventArgs e)
            {
                this.Close();
            }
            private void btnApply_Click(object sender,
            EventArgs e)
            {
                xMin = Convert.ToDouble(tbXMin.Text);
                xMax = Convert.ToDouble(tbXMax.Text);
                yMin = Convert.ToDouble(tbXMin.Text);
                yMax = Convert.ToDouble(tbYMax.Text);
                plotCanvas.Children.Remove(line1);
                plotCanvas.Children.Remove(polyline1);
                AddGraphics();
            }
        }
    }
    bon code...

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/06/2009, 21h41
  2. [WPF] Problème de WrapPanel dans un ItemsControl
    Par Asarnil dans le forum Windows Presentation Foundation
    Réponses: 4
    Dernier message: 03/03/2009, 09h03
  3. [WPF] Probléme de binding dans un UserControl :(
    Par UNi[FR] dans le forum Windows Presentation Foundation
    Réponses: 6
    Dernier message: 17/07/2008, 15h51
  4. Réponses: 2
    Dernier message: 11/02/2008, 22h02
  5. [WPF] Problème de menu dans fenetre transparente
    Par Zucher dans le forum Framework .NET
    Réponses: 3
    Dernier message: 30/01/2008, 22h28

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