2017-09-04 5 views
1

Je crée un contrôle utilisateur similaire à TrackBar.C# Peindre un panneau pour entourer sa valeur d'emplacement

L'utilisateur peut cliquer sur un panneau et le faire glisser pour changer la valeur de int SelectedMin.

Je souhaite dessiner le panneau SelectedMin pour entourer la souris lorsque je la fais glisser au lieu de démarrer à la souris. En d'autres termes, je souhaite que le centre du panneau apparaisse sur ma valeur SelectedMin au lieu du côté gauche du panneau à SelectedMin.

Je crois que cela devrait fonctionner avec une ligne dans ma méthode ToolboxCustomTrackBar_Paint():

minPanel.Location = new Point((SelectedMin * Width/(Max - Min)) - PanelWidth/2, LabelHeight); 

Le programme démarre correctement, avec seulement la moitié du panneau affichant l'origine, ce qui indique que le ... - PanelWidth/2 fonctionne, mais quand je cliquez sur le panneau pour le faire glisser, il centre la gauche du panneau où se trouve le curseur de ma souris.


L'image du haut est ce qui se passe actuellement. L'image du bas est ce que j'essaye d'accomplir.

enter image description here


Code connexes:

private int min = 0; 
    private int max = 1000; 
    private int selectedMin = 200; 
    private int labelWidth = 0; 
    private int labelHeight = 200; 
    private int panelWidth = 10; 

    public int Min 
    { 
     get { return min; } 
     set { min = value; Invalidate(); } 
    } 
    public int Max 
    { 
     get { return max; } 
     set { max = value; Invalidate(); } 
    } 
    public int SelectedMin 
    { 
     get { return selectedMin; } 
     set 
     { 
      if (value >= Min && value <= Max) 
      { 
       selectedMin = value; 
       Invalidate(); 
      } 
     } 
    } 
    public int LabelWidth 
    { 
     get { return labelWidth; } 
     set { labelWidth = value; Invalidate(); } 
    } 
    public int LabelHeight 
    { 
     get { return labelHeight; } 
     set { labelHeight = value; Invalidate(); } 
    } 
    public int PanelWidth 
    { 
     get { return panelWidth; } 
     set { panelWidth = value; Invalidate(); } 
    } 

    public ToolboxCustomTrackBar() 
    { 
     InitializeComponent(); 
     SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
     SetStyle(ControlStyles.OptimizedDoubleBuffer, true); 

     selectionWidth = (Max - Min)/Width; 

     minLabel.Text = "0"; 
     LabelWidth = minLabel.Width; 
    } 

    private void ToolboxCustomTrackBar_Paint(object sender, PaintEventArgs e) 
    { 
     foreach (var panel in panels) 
     { 
      panel.Height = Height - LabelHeight; 

      if (panel != backdropPanel) 
      { 
       panel.Width = PanelWidth; 
      } 
     } 

     minPanel.Location = new Point((SelectedMin * Width/(Max - Min)) - PanelWidth/2, LabelHeight); 
    } 

    private void minPanel_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.Button == MouseButtons.Left) 
     { 
      SelectedMin += Min + e.X * (Max - Min)/Width; 
     } 
    } 

Répondre

0

créé un trackbar sur moi-même et il semble fonctionner:

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace TestProjectWinforms 
{ 
    public partial class TrackBar : UserControl 
    { 
     private int _CurrentValue; 
     private bool _IsDragging; 
     private int _MaximumValue; 
     private int _MinimumValue; 

     public TrackBar() 
     { 
      InitializeComponent(); 
      TrackColor = Color.Red; 
      TrackWidth = 10; 
      MinimumValue = 0; 
      MaximumValue = 10000; 
      CurrentValue = 3000; 
      HotTrackEnabled = true; 
     } 

     public event EventHandler CurrentValueChanged; 

     public int CurrentValue 
     { 
      get => _CurrentValue; 
      set 
      { 
       _CurrentValue = value; 
       ValidateCurrentValue(); 
       Invalidate(); 
       RaiseEvent(CurrentValueChanged); 
      } 
     } 

     public bool HotTrackEnabled { get; set; } 

     public int MaximumValue 
     { 
      get => _MaximumValue; 
      set 
      { 
       _MaximumValue = value; 

       if (_MaximumValue < _MinimumValue) 
        _MaximumValue = _MinimumValue; 

       ValidateCurrentValue(); 
       Invalidate(); 
      } 
     } 

     public int MinimumValue 
     { 
      get => _MinimumValue; 
      set 
      { 
       _MinimumValue = value; 

       if (_MinimumValue > _MaximumValue) 
        _MinimumValue = _MaximumValue; 

       ValidateCurrentValue(); 
       Invalidate(); 
      } 
     } 

     public Color TrackColor { get; set; } 

     public int TrackWidth { get; set; } 

     protected override void OnMouseDown(MouseEventArgs e) 
     { 
      base.OnMouseDown(e); 

      if (HotTrackEnabled) 
       _IsDragging = true; 
     } 

     protected override void OnMouseMove(MouseEventArgs e) 
     { 
      base.OnMouseMove(e); 

      if (_IsDragging) 
      { 
       UpdateCurrentValueFromPosition(e.X); 
       Invalidate(); 
      } 
     } 

     protected override void OnMouseUp(MouseEventArgs e) 
     { 
      base.OnMouseUp(e); 
      _IsDragging = false; 
     } 

     protected override void OnPaint(PaintEventArgs e) 
     { 
      base.OnPaint(e); 

      using (var brush = new SolidBrush(TrackColor)) 
      { 
       e.Graphics.FillRectangle(brush, CreateRectangle()); 
      } 
     } 

     protected override void OnResize(EventArgs e) 
     { 
      base.OnResize(e); 
      Invalidate(); 
     } 

     private RectangleF CreateRectangle() 
     { 
      var position = GetRectanglePosition(); 
      var rectangle = new RectangleF(position, 0, TrackWidth, Height); 
      return rectangle; 
     } 

     private float GetRectanglePosition() 
     { 
      var range = _MaximumValue - _MinimumValue; 
      var value = _CurrentValue - _MinimumValue; 
      var percentage = (float)value * 100/range; 
      var position = percentage * Width/100; 

      return position - (float)TrackWidth/2; 
     } 

     private void RaiseEvent(EventHandler handler) 
     { 
      handler?.Invoke(this, EventArgs.Empty); 
     } 

     private void UpdateCurrentValueFromPosition(float x) 
     { 
      var percentage = x * 100/Width; 
      var range = _MaximumValue - _MinimumValue; 
      var rawValue = percentage * range/100; 
      var value = rawValue + _MinimumValue; 

      CurrentValue = (int)Math.Round(value); 
     } 

     private void ValidateCurrentValue() 
     { 
      if (_CurrentValue < _MinimumValue) 
       _CurrentValue = _MinimumValue; 

      if (_CurrentValue > _MaximumValue) 
       _CurrentValue = _MaximumValue; 
     } 
    } 
} 
+0

Salut, merci pour la réponse. Il semble que nous faisons la même chose. Je commence à me demander si c'est peut-être quelque chose à voir avec le 'Panel', puisque vous (et beaucoup d'autres) préférez dessiner des rectangles. Comment se fait-il que vous ayez deux fonctions différentes pour calculer 'GetRectanglePosition()' et 'UpdateCurrentValueFromPosition()' quand ils semblent faire la même chose? De plus, je ne connais pas 'base.Method (e)', qu'est-ce que c'est? – Tawm

+0

Les deux méthodes sont complémentaires. 'GetRectanglePosition()' prend la valeur actuelle et calcule la position x en pixel pour le rectangle. Avec 'UpdateCurrentValueFromPosition()' je vais prendre la position actuelle de la souris (lorsque l'utilisateur fait glisser le rectangle) et calculer la valeur actuelle dans la plage. – Oliver

+0

Le 'base.Method (e)' est nécessaire, parce que je remplace les méthodes existantes dans la classe. Mais je n'aime pas remplacer ces méthodes. Au lieu de cela je voudrais faire seulement quelques trucs supplémentaires. Par conséquent, je dois appeler la méthode de base pour laisser le comportement par défaut s'exécuter et ensuite faire mes choses supplémentaires. Si vous aimez creuser plus profondément, vous devriez chercher 'override virtuel C#'. C'est une technique courante dans la programmation orientée objet. – Oliver