Помогите перекрасить линию - PullRequest
0 голосов
/ 04 марта 2010

Я делаю пользовательский элемент управления (унаследованный от VisualBasic.PowerPacks.LineShape), который должен быть нарисован как стандартный, но рядом с ним отображается значок.

Итак, я просто переопределил OnPaint вот так:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
    base.OnPaint(e);
}

Теперь все в порядке, но когда мой контроль перемещается, значок все еще остается нарисованным в древнем месте.

Есть ли способ нарисовать его правильно?

альтернативный текст http://lh4.ggpht.com/_1TPOP7DzY1E/S5gXmp7xYiI/AAAAAAAADHI/pa1OhpKYSoM/Untitled-2.png Реальная проектная ситуация

CODE: пример кода для тестов

альтернативный текст http://lh6.ggpht.com/_1TPOP7DzY1E/S5jSluxvtDI/AAAAAAAADHw/EUz0Tfet-rw/s800/Capture2.png

using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;

namespace LineShapeTest
{
    /// 
    /// Test Form
    /// 
    public class Form1 : Form
    {        
        IconLineShape myLine = new IconLineShape();
        ShapeContainer shapeContainer1 = new ShapeContainer();
        Panel panel1 = new Panel();

        public Form1()
        {
            this.panel1.Dock = DockStyle.Fill;
            // load your back image here
            this.panel1.BackgroundImage = 
                global::WindowsApplication22.Properties.Resources._13820t;
            this.panel1.Controls.Add(shapeContainer1);

            this.myLine.StartPoint = new Point(20, 30);
            this.myLine.EndPoint = new Point(80, 120);
            this.myLine.Parent = this.shapeContainer1;

            MouseEventHandler panelMouseMove = 
                new MouseEventHandler(this.panel1_MouseMove);
            this.panel1.MouseMove += panelMouseMove;
            this.shapeContainer1.MouseMove += panelMouseMove;

            this.Controls.Add(panel1);
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                myLine.StartPoint = e.Location;
            }
        }
    }

    /// 
    /// Test LineShape
    /// 
    public class IconLineShape : LineShape
    {
        Icon myIcon = SystemIcons.Exclamation;

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
            base.OnPaint(e);
        }
    }
}

Nota Bene , для линии Форма:

Parent = ShapeContainer
Parent.Parent = Panel

Обновление 1 TRACES

В этом варианте OnPaint у нас есть следы:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    Graphics g = Parent.Parent.CreateGraphics();
    g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);            
    base.OnPaint(e);
}        

альтернативный текст http://lh4.ggpht.com/_1TPOP7DzY1E/S5j29lutQ0I/AAAAAAAADH4/4yEnZd_hPjA/s800/Capture3.png

Обновление 2 BLINKS

В этом варианте OnPaint у нас есть мигающее изображение :

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    Parent.Parent.Invalidate(this.Region, true);
    Graphics g = Parent.Parent.CreateGraphics();
    g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);            
    base.OnPaint(e);
}  

альтернативный текст http://lh5.ggpht.com/_1TPOP7DzY1E/S5j4Bam7hiI/AAAAAAAADIA/1hQWKyV8Fr0/s800/Capture4.png

Обновление 3: внешняя проверка

Этот вариант работает хорошо, но ... по внешнему виду класса IconLineShape:

private void panel1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Region r = myLine.Region;
        myLine.StartPoint = e.Location;
        panel1.Invalidate(r);
    }
}


/// 
/// Test LineShape
/// 
public class IconLineShape : LineShape
{
    Icon myIcon = SystemIcons.Exclamation;
    Graphics parentGraphics;

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        parentGraphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
        base.OnPaint(e);
    }

    protected override void OnParentChanged(System.EventArgs e)
    {
        // Parent is a ShapeContainer
        // Parent.Parent is a Panel
        parentGraphics = Parent.Parent.CreateGraphics();
        base.OnParentChanged(e);
    }
}

Даже это решает проблему тестового примера, мне нужно, чтобы этот элемент управления был выполнен внутри элемента управления, потому что я не могу заставить внешние «клиенты» этого элемента управления не забыть сохранить старый регион и сделать родительский объект недействительным. каждый раз меняя местоположение ...

Ответы [ 6 ]

1 голос
/ 12 марта 2010

просто добавление другого, совершенно другого (надеюсь, снова рабочего :-) решения. Поскольку я не знал о требовании «код должен быть внутри класса», это продолжение.

Аксиома: НИКОГДА не вызывайте Invalidate() или Refresh() в OnPaint или OnPaintBackground, потому что вы (всегда) окажетесь в бесконечном цикле .

Так что нам нужно найти другое место для них. Я пытался скомпилировать ваши классы в Visual Studio, но я не смог найти класс LineShape (Microsoft.VisualBasic.PowerPacks.Vs.dll не сработал), поэтому снова непроверенный код.

что я сделал?

  1. Удалил обработчик MouseMove из формы и поместил его в класс IconLineShape. Все будет хорошо, потому что, если клиент хочет перетащить, просто отлично. Попробуйте одно из описанных решений.
  2. Добавлено свойство для отключения перетаскивания в IconLineShape (если клиент не согласен с этим :-). без перетаскивания у нас не было бы проблемы в первую очередь.

-

    public class Form1 : Form
    {
       IconLineShape myLine = new IconLineShape();
       ShapeContainer shapeContainer1 = new ShapeContainer();
       Panel panel1 = new Panel();

       public Form1()
       {
           this.panel1.Dock = DockStyle.Fill;
           // load your back image here
           this.panel1.BackgroundImage =
               global::WindowsApplication22.Properties.Resources._13820t;
           this.panel1.Controls.Add(shapeContainer1);

           this.myLine.StartPoint = new Point(20, 30);
           this.myLine.EndPoint = new Point(80, 120);
           this.myLine.Parent = this.shapeContainer1;

           this.Controls.Add(panel1);
       }
   }

   public class IconLineShape : LineShape
   {
       Icon myIcon = SystemIcons.Exclamation;

       protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
       {
           e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
           base.OnPaint(e);
       }

       protected override void OnMouseMove(MouseEventArgs e)
       {
           if (draggable && 
               e.Button == MouseButtons.Left &&
               !this.StartPoint.Equals(e.Location))
           {
               Region r = this.Region.Clone();

               this.StartPoint = e.Location;

               // try solution 1
               this.Invalidate(r);

               // solution 2; walk up to the upmost parent and refresh
               // as said before, this.Invalidate() is to be preferred
               Control currentParent = this.Parent;
               while (currentParent.Parent != null)
               {
                   currentParent = currentParent.Parent;
               }
               currentParent.Refresh();
           } 
       }

       private bool draggable = true;

       public bool Draggable
       {
           get { return this.draggable; }
           set { this.draggable = value; }
       }
   }

Пожалуйста, оставьте отзыв.

1 голос
/ 11 марта 2010

попробуйте изменить следующую функцию вашей формы, чтобы сделать недействительным буфер, в котором ранее находился значок, и тем самым удалить все остальное (непроверенный код):

    private void panel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Point oldPos = myLine.StartPoint;
            myLine.StartPoint = e.Location;
            this.Invalidate(new Recangle(oldPos.X, oldPos.Y, myLine.Width, myLine.Height));
        }
    }

если это не работает, попробуйте:

    private void panel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            myLine.StartPoint = e.Location;
            this.Refresh();
        }
    }

Этот метод не рекомендуется из-за проблем с производительностью (очищается весь буфер), но больше ничего не работает ...

1 голос
/ 08 марта 2010

Вы пытались очистить буфер (нарисовать прямоугольник заливки с цветом фона)?Также убедитесь, что вы обнулили области отсечения до размера вашего элемента управления, затем нарисуйте свой значок, а затем вызовите рисование родителей.

0 голосов
/ 12 марта 2010

Это помогает? Кажется, вы слишком увлечены LineShape. Для меня производное от RectangleShape имело больше смысла. Я завернул все в помощника, который заботится о деталях. Этот помощник является стандартной техникой, которую я использую для связи элементов управления вместе без создания «составного элемента управления», что обычно проще.

using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;

namespace LineShapeTest {

    public partial class Form1 : Form {

        /*  Designer support through
         *  Create Panel
         *  Set panel's background image
         *  Add LineShape
         *  Add IconShape
         *  Create IconicLineShapeHelper
         */
        public Form1() {
            InitializeComponent();
            IconicLineShapeHelper arbitrary1 = new IconicLineShapeHelper(lineShape1, iconShape1);
            IconicLineShapeHelper arbitrary2 = new IconicLineShapeHelper(lineShape2, iconShape2);
        }

        private Panel panel1;
        private ShapeContainer shapeContainer1;
        private LineShape lineShape1;
        private IconShape iconShape1;
        private ShapeContainer shapeContainer2;
        private LineShape lineShape2;
        private IconShape iconShape2;

    #region [ Form1.Designer.cs ]
        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing) {
            if (disposing && (components != null)) {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        private void InitializeComponent() {
            this.lineShape1 = new Microsoft.VisualBasic.PowerPacks.LineShape();
            this.panel1 = new System.Windows.Forms.Panel();
            this.shapeContainer1 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer();
            this.iconShape1 = new LineShapeTest.IconShape();
            this.shapeContainer2 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer();
            this.lineShape2 = new Microsoft.VisualBasic.PowerPacks.LineShape();
            this.iconShape2 = new LineShapeTest.IconShape();
            this.panel1.SuspendLayout();
            this.SuspendLayout();
            // 
            // lineShape1
            // 
            this.lineShape1.Name = "lineShape1";
            this.lineShape1.X1 = 13;
            this.lineShape1.X2 = 88;
            this.lineShape1.Y1 = 11;
            this.lineShape1.Y2 = 34;
            // 
            // panel1
            // 
            this.panel1.BackgroundImage = global::LineShapeTest.Properties.Resources._13820t;
            this.panel1.Controls.Add(this.shapeContainer1);
            this.panel1.Location = new System.Drawing.Point(27, 24);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(162, 122);
            this.panel1.TabIndex = 1;
            // 
            // shapeContainer1
            // 
            this.shapeContainer1.Location = new System.Drawing.Point(0, 0);
            this.shapeContainer1.Margin = new System.Windows.Forms.Padding(0);
            this.shapeContainer1.Name = "shapeContainer1";
            this.shapeContainer1.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] {
            this.iconShape1,
            this.lineShape1});
            this.shapeContainer1.Size = new System.Drawing.Size(162, 122);
            this.shapeContainer1.TabIndex = 0;
            this.shapeContainer1.TabStop = false;
            // 
            // iconShape1
            // 
            this.iconShape1.BorderStyle = System.Drawing.Drawing2D.DashStyle.Custom;
            this.iconShape1.Location = new System.Drawing.Point(88, 64);
            this.iconShape1.Name = "iconShape1";
            this.iconShape1.Size = new System.Drawing.Size(32, 32);
            // 
            // shapeContainer2
            // 
            this.shapeContainer2.Location = new System.Drawing.Point(0, 0);
            this.shapeContainer2.Margin = new System.Windows.Forms.Padding(0);
            this.shapeContainer2.Name = "shapeContainer2";
            this.shapeContainer2.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] {
            this.iconShape2,
            this.lineShape2});
            this.shapeContainer2.Size = new System.Drawing.Size(292, 266);
            this.shapeContainer2.TabIndex = 2;
            this.shapeContainer2.TabStop = false;
            // 
            // lineShape2
            // 
            this.lineShape2.Name = "lineShape2";
            this.lineShape2.X1 = 48;
            this.lineShape2.X2 = 123;
            this.lineShape2.Y1 = 187;
            this.lineShape2.Y2 = 210;
            // 
            // iconShape2
            // 
            this.iconShape2.Location = new System.Drawing.Point(136, 220);
            this.iconShape2.Name = "iconShape2";
            this.iconShape2.Size = new System.Drawing.Size(75, 23);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.panel1);
            this.Controls.Add(this.shapeContainer2);
            this.Name = "Form1";
            this.Text = "Form1";
            this.panel1.ResumeLayout(false);
            this.ResumeLayout(false);

        }
        #endregion
    }
    #endregion

    public class IconicLineShapeHelper {
        ShapeContainer _container;
        LineShape _line;
        IconShape _icon;
        public IconicLineShapeHelper(LineShape line, IconShape icon) {
            _container = line.Parent;
            _line = line;
            _icon = icon;
            _container.MouseMove += new MouseEventHandler(_container_MouseMove);
        }
        void _container_MouseMove(object sender, MouseEventArgs e) {
            if (e.Button == MouseButtons.Left) {
                _line.StartPoint = e.Location;
                _icon.Location = e.Location;
            }
        }
    }
    public class IconShape : RectangleShape {
        Icon _icon = SystemIcons.Exclamation;
        public IconShape() {
            this.Size = new System.Drawing.Size(32, 32);
            this.BorderStyle = System.Drawing.Drawing2D.DashStyle.Custom;
        }
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
            e.Graphics.DrawIcon(_icon, this.Location.X, this.Location.Y);
            base.OnPaint(e);
        }
    }
}
0 голосов
/ 10 марта 2010

Вы делали это на пользовательском элементе управления?

для удаления эффекта "стробоскопа"

Public Sub New()
    Me.SetStyle(ControlStyles.ResizeRedraw Or _
                ControlStyles.DoubleBuffer Or _
                ControlStyles.UserPaint Or _
                ControlStyles.AllPaintingInWmPaint, _
                True)
    Me.UpdateStyles()

End Sub
0 голосов
/ 04 марта 2010

Наконец, в итоге я добавил PictureBox вместо того, чтобы рисовать иконку сам.

using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;

namespace LineShapeTest
{
    /// 
    /// Test Form
    /// 
    public class Form1 : Form
    {
        IconLineShape myLine = new IconLineShape();
        ShapeContainer shapeContainer1 = new ShapeContainer();
        Panel panel1 = new Panel();

        public Form1()
        {
            this.panel1.Dock = DockStyle.Fill;
            // load your back image here
            //this.panel1.BackgroundImage =
            //global::WindowsApplication22.Properties.Resources._13820t;
            this.panel1.BackColor = Color.White;
            this.panel1.Controls.Add(shapeContainer1);

            this.myLine.StartPoint = new Point(20, 30);
            this.myLine.EndPoint = new Point(80, 120);
            this.myLine.Parent = this.shapeContainer1;

            MouseEventHandler panelMouseMove =
                new MouseEventHandler(this.panel1_MouseMove);
            this.panel1.MouseMove += panelMouseMove;
            this.shapeContainer1.MouseMove += panelMouseMove;

            this.Controls.Add(panel1);
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                myLine.StartPoint = e.Location;
            }
        }
    }

    /// 
    /// Test LineShape
    /// 
    public class IconLineShape : LineShape
    {
        Icon myIcon = SystemIcons.Exclamation;
        PictureBox pictureBox = new PictureBox();

        public IconLineShape()
        {
            pictureBox.Image = Bitmap.FromHicon(myIcon.Handle);
            pictureBox.Size = myIcon.Size;
            pictureBox.Visible = true;
        }

        protected override void OnMove(System.EventArgs e)
        {
            base.OnMove(e);
            pictureBox.Location = this.StartPoint;
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            base.OnPaint(e);
            pictureBox.Invalidate();
        }

        public override bool HitTest(int x, int y)
        {            
            return base.HitTest(x, y) |
                pictureBox.RectangleToScreen(
                    pictureBox.DisplayRectangle).Contains(new Point(x, y));
        }

        protected override void OnParentChanged(System.EventArgs e)
        {
            // Parent is a ShapeContainer
            // Parent.Parent is a Panel
            pictureBox.Parent = Parent.Parent;
            base.OnParentChanged(e);
        }
    }
}

Спасибо всем за участие!

...