Рисование сверх средств управления в панели (C# WinForms)

Другое событие NullPointerException возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals для гарантированного непустого объекта.

Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null.

Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

41
задан Community 8 February 2017 в 14:09
поделиться

9 ответов

Оказывается, что это намного легче, чем я думал. Спасибо за не принятие любого из моих других ответов. Вот двухступенчатый процесс для создания Fline ( строка f loating - извините, поздно):

alt text

Шаг 1 : Добавьте UserControl к своему проекту и назовите его "Fline". Добавьте следующее к операторам использования:

using System.Drawing.Drawing2D;

Шаг 2 : Добавьте следующее к событию Fline's Resize:

int wfactor = 4; // half the line width, kinda
// create 6 points for path
Point[] pts = {
    new Point(0, 0), 
    new Point(wfactor, 0), 
    new Point(Width, Height - wfactor),
    new Point(Width, Height) ,
    new Point(Width - wfactor, Height),
    new Point(0, wfactor) };
// magic numbers! 
byte[] types = {
    0, // start point
    1, // line
    1, // line
    1, // line
    1, // line
    1 }; // line 
GraphicsPath path = new GraphicsPath(pts, types);
this.Region = new Region(path);

Компиляция, и затем перетаскивают Fline на Вашу форму или панель. Важный: BackColor по умолчанию совпадает с формой, таким образом изменяют BackColor Fline на Красный или что-то очевидное (в разработчике). Одна странная причуда об этом - то, что при перетаскивании его вокруг в разработчике это показывает твердым блоком, пока Вы не выпускаете его - не огромное соглашение.

Это управление может появиться перед или позади любого другого управления. Если Вы устанавливаете, Включил ко лжи, это все еще будет видимо, но не вмешается в события от нажатия мыши на средствах управления внизу.

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

Обновление : это делает хорошую плотную остроту, также. Просто поместите это в событие Resize своего UserControl:

this.Region=new Region(new System.Drawing.Drawing2D.GraphicsPath(new Point[]{new Point(0,0),new Point(4,0),new Point(Width,Height-4),new Point(Width,Height),new Point(Width-4,Height),new Point(0,4)},new byte[]{0,1,1,1,1,1}));
20
ответ дан Glorfindel 27 November 2019 в 00:51
поделиться

Если Вы хотите, чтобы строка была просто простой горизонтальной или вертикальной строкой, поместила другую панель (отключенный, таким образом, это не берет событий от нажатия мыши) на основной панели, установите ее высоту (или ширина) к 3 или 4 пикселям (или независимо от того, что Вы хотите), и перенесите его на передний план. Если необходимо измениться, где строка во время времени выполнения, можно просто переместить панель и сделать ее видимой и невидимой. Вот то, как это смотрит:

alt text

можно даже нажать где угодно, Вам нравится, и строки не вмешиваются вообще. Линия проведена по любому виду управления вообще (хотя выпадающую часть ComboBox или DatePicker все еще показывают выше строки, которая хороша так или иначе). Синяя строка является просто тем же самым, но отправленный в спину.

9
ответ дан Glorfindel 27 November 2019 в 00:51
поделиться

Да, это может быть сделано. Проблема состоит в том, что панель и средства управления на ней являются всеми отдельными окнами (в смысле API), и таким образом все отдельные поверхности рисунка. Нет никакой поверхности рисунка для продвиганий для получения этого эффекта (кроме экранной поверхности верхнего уровня, и это считало невежливым для рисования на всем протяжении этого).

(кашель - взлом - кашель) прием должен разграничить на панели под средствами управления, и также потянуть его на каждых из самих средств управления, приведя к этому (который сохранится, даже когда Вы нажимаете кнопки и перемещаете мышь):

alt text

Создают проект winforms (который должен идти с Form1 по умолчанию). Добавьте панель (названный "panel1") и две кнопки ("button1" и "button2") на панели как показано. Добавьте этот код в конструкторе формы:

panel1.Paint += PaintPanelOrButton;
button1.Paint += PaintPanelOrButton;
button2.Paint += PaintPanelOrButton;

и затем добавляют этот метод к коду формы:

private void PaintPanelOrButton(object sender, PaintEventArgs e)
{
    // center the line endpoints on each button
    Point pt1 = new Point(button1.Left + (button1.Width / 2),
            button1.Top + (button1.Height / 2));
    Point pt2 = new Point(button2.Left + (button2.Width / 2),
            button2.Top + (button2.Height / 2));

    if (sender is Button)
    {
        // offset line so it's drawn over the button where
        // the line on the panel is drawn
        Button btn = (Button)sender;
        pt1.X -= btn.Left;
        pt1.Y -= btn.Top;
        pt2.X -= btn.Left;
        pt2.Y -= btn.Top;
    }

    e.Graphics.DrawLine(new Pen(Color.Red, 4.0F), pt1, pt2);
}

Что-то вроде этого должно быть оттянуто в событии Paint каждого управления для строки для сохранения. Легко потянуть непосредственно на средствах управления в.NET, но независимо от того, что Вы тянете, вытерт, когда кто-то нажимает кнопку или перемещает мышь через него (если это постоянно не перерисовывается в событиях Paint, как здесь).

Примечание, что для этого для работы любое дистиллируемое управление должно иметь событие Paint. Я уверен, что необходимо будет изменить этот образец для достижения того, в чем Вы нуждаетесь. При предложении хорошей обобщенной функции для этого отправьте ее.

Обновление: этот метод не будет работать на полосы прокрутки, текстовые поля, поля комбинированного списка, listviews, или в основном что-либо с вещью типа текстового поля как часть его (и не потому что это только смещает для кнопок в примере выше - Вы просто не можете потянуть сверху текстового поля вообще, по крайней мере, не от его события Paint, по крайней мере, не, если Вы - я). Надо надеяться, это не будет проблемой.

6
ответ дан Glorfindel 27 November 2019 в 00:51
поделиться

Единственное простое решение, о котором я могу думать, должно создать обработчики событий Краски для каждого управления, сверху которого Вы хотите нарисовать. Тогда скоординируйте рисунок строки между этими обработчиками. Это не наиболее удобное решение, однако это даст Вам способность подрисовать вершина из средств управления.

кнопка Assuming является дочерним элементом управления панели:

panel.Paint += new PaintEventHandler(panel_Paint);
button.Paint += new PaintEventHandler(button_Paint);

protected void panel_Paint(object sender, PaintEventArgs e)
{
    //draw the full line which will then be partially obscured by child controls
}

protected void button_Paint(object sender, PaintEventArgs e)
{
    //draw the obscured line portions on the button
}
3
ответ дан asponge 27 November 2019 в 00:51
поделиться

Панель форм окон является контейнером для средств управления. Если Вы хотите потянуть что-то сверх других средств управления в панели, то то, в чем Вы нуждаетесь, является другим управлением (во главе порядка z).

К счастью, можно создать элементы управления Windows Forms, которые имеют непрямоугольные границы. Посмотрите на эту технику: http://msdn.microsoft.com/en-us/library/aa289517 (По сравнению с 71) .aspx

, Чтобы просто потянуть что-то на экране используйте элемент управления "метка" и выключите AutoSize. Тогда присоедините к событию Paint и установите Размер и регион Свойства.

Вот пример кода:

private void label1_Paint(object sender, PaintEventArgs e)
{
    System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new  System.Drawing.Drawing2D.GraphicsPath();
    myGraphicsPath.AddEllipse(new Rectangle(0, 0, 125, 125));
    myGraphicsPath.AddEllipse(new Rectangle(75, 75, 20, 20));
    myGraphicsPath.AddEllipse(new Rectangle(120, 0, 125, 125));
    myGraphicsPath.AddEllipse(new Rectangle(145, 75, 20, 20));
    //Change the button's background color so that it is easy
    //to see.
    label1.BackColor = Color.ForestGreen;
    label1.Size = new System.Drawing.Size(256, 256);
    label1.Region = new Region(myGraphicsPath);
}
5
ответ дан Matt Brunell 27 November 2019 в 00:51
поделиться

Я думаю, что лучший способ состоит в том, чтобы наследовать управление, которого Вы хотите чертить линию на. Переопределите метод OnPaint, назовите основу. Краска () из, после этого разграничьте использование того же графического экземпляра. В то же время у Вас может также быть параметр, который конкретный, в которой точке строка должна быть ничьей, так, чтобы можно было управлять строкой непосредственно от основной формы.

1
ответ дан faulty 27 November 2019 в 00:51
поделиться

Сделайте новый LineControl: Управление как это:

тогда вызов BringToFront () после Редактирования InitializeComponent

public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this.simpleLine1.BringToFront();
        }
    }



using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;

public class SimpleLine : Control
{
    private Control parentHooked;   
    private List<Control> controlsHooked;

    public enum LineType
    {
        Horizontal,
        Vertical,
        ForwardsDiagonal,
        BackwardsDiagonal
    }

    public event EventHandler AppearanceChanged;
    private LineType appearance;
    public virtual LineType Appearance
    {
        get
        {
            return appearance;
        }
        set
        {
            if (appearance != value)
            {
                this.SuspendLayout();
                switch (appearance)
                {
                    case LineType.Horizontal:
                        if (value == LineType.Vertical)
                        {
                            this.Height = this.Width;
                        }

                        break;
                    case LineType.Vertical:
                        if (value == LineType.Horizontal)
                        {
                            this.Width = this.Height;
                        }
                        break;
                }
                this.ResumeLayout(false);

                appearance = value;
                this.PerformLayout();
                this.Invalidate();
            }
        }
    }
    protected virtual void OnAppearanceChanged(EventArgs e)
    {
        if (AppearanceChanged != null) AppearanceChanged(this, e);
    }

    public event EventHandler LineColorChanged;
    private Color lineColor;
    public virtual Color LineColor
    {
        get
        {
            return lineColor;
        }
        set
        {
            if (lineColor != value)
            {
                lineColor = value;
                this.Invalidate();
            }
        }
    }
    protected virtual void OnLineColorChanged(EventArgs e)
    {
        if (LineColorChanged != null) LineColorChanged(this, e);
    }

    public event EventHandler LineWidthChanged;
    private float lineWidth;
    public virtual float LineWidth
    {
        get
        {
            return lineWidth;
        }
        set
        {
            if (lineWidth != value)
            {
                if (0 >= value)
                {
                    lineWidth = 1;
                }
                lineWidth = value;
                this.PerformLayout();
            }
        }
    }
    protected virtual void OnLineWidthChanged(EventArgs e)
    {
        if (LineWidthChanged != null) LineWidthChanged(this, e);
    }

    public SimpleLine()
    {
        base.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable, false);
        base.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        base.BackColor = Color.Transparent;

        InitializeComponent();

        appearance = LineType.Vertical;
        LineColor = Color.Black;
        LineWidth = 1;
        controlsHooked = new List<Control>();

        this.ParentChanged += new EventHandler(OnSimpleLineParentChanged);
    }

    private void RemoveControl(Control control)
    {
        if (controlsHooked.Contains(control))
        {
            control.Paint -= new PaintEventHandler(OnControlPaint);
            if (control is TextboxX)
            {
                TextboxX text = (TextboxX)control;
                text.DoingAPaint -= new EventHandler(text_DoingAPaint);
            }
            controlsHooked.Remove(control);
        }
    }

    void text_DoingAPaint(object sender, EventArgs e)
    {
        this.Invalidate();
    }

    private void AddControl(Control control)
    {
        if (!controlsHooked.Contains(control))
        {
            control.Paint += new PaintEventHandler(OnControlPaint);
            if (control is TextboxX)
            {
                TextboxX text = (TextboxX)control;
                text.DoingAPaint += new EventHandler(text_DoingAPaint);
            }
            controlsHooked.Add(control);
        }
    }

    private void OnSimpleLineParentChanged(object sender, EventArgs e)
    {
        UnhookParent();

        if (Parent != null)
        {

            foreach (Control c in Parent.Controls)
            {
                AddControl(c);
            }
            Parent.ControlAdded += new ControlEventHandler(OnParentControlAdded);
            Parent.ControlRemoved += new ControlEventHandler(OnParentControlRemoved);
            parentHooked = this.Parent;
        }
    }

    private void UnhookParent()
    {
            if (parentHooked != null)
            {
                foreach (Control c in parentHooked.Controls)
                {
                    RemoveControl(c);
                }
                parentHooked.ControlAdded -= new ControlEventHandler(OnParentControlAdded);
                parentHooked.ControlRemoved -= new ControlEventHandler(OnParentControlRemoved);
                parentHooked = null;
            }
    }

    private void OnParentControlRemoved(object sender, ControlEventArgs e)
    {
        RemoveControl(e.Control);
    }   

    private void OnControlPaint(object sender, PaintEventArgs e)
    {
        int indexa =Parent.Controls.IndexOf(this) , indexb = Parent.Controls.IndexOf((Control)sender);
        //if above invalidate on paint
        if(indexa < indexb)
        {
            Invalidate();
        }
    }

    private void OnParentControlAdded(object sender, ControlEventArgs e)
    {
        AddControl(e.Control);
    }

    private System.ComponentModel.IContainer components = null;
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
            return cp;
        }
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
        switch (this.Appearance)
        {
            case LineType.Horizontal:
                this.Height = (int)LineWidth;
                this.Invalidate();
                break;
            case LineType.Vertical:
                this.Width = (int)LineWidth;
                this.Invalidate();
                break;
        }

        base.OnLayout(levent);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        //disable background paint
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        switch (Appearance)
        {
            case LineType.Horizontal:
                DrawHorizontalLine(pe);
                break;
            case LineType.Vertical:
                DrawVerticalLine(pe);
                break;
            case LineType.ForwardsDiagonal:
                DrawFDiagonalLine(pe);
                break;
            case LineType.BackwardsDiagonal:
                DrawBDiagonalLine(pe);
                break;
        }
    }

    private void DrawFDiagonalLine(PaintEventArgs pe)
    {
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, this.ClientRectangle.Bottom,
                                    this.ClientRectangle.Right, this.ClientRectangle.Y);
        }
    }

    private void DrawBDiagonalLine(PaintEventArgs pe)
    {
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, this.ClientRectangle.Y,
                                    this.ClientRectangle.Right, this.ClientRectangle.Bottom);
        }
    }

    private void DrawHorizontalLine(PaintEventArgs pe)
    {
        int  y = this.ClientRectangle.Height / 2;
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p, this.ClientRectangle.X, y,
                                    this.ClientRectangle.Width, y);
        }
    }

    private void DrawVerticalLine(PaintEventArgs pe)
    {
        int x = this.ClientRectangle.Width / 2;
        using (Pen p = new Pen(this.LineColor, this.LineWidth))
        {
            pe.Graphics.DrawLine(p,x, this.ClientRectangle.Y,
                                   x, this.ClientRectangle.Height);
        }
    }
}

: Добавленная диагональная поддержка

я добавил некоторую поддержку средств управления, которые перекрашивают, когда они получают фокус.

текстовые поля и comboboxs привычка работают, как Вы, должен будет сделать Ваше собственное и сцепить там paintish команды как так:

public class TextboxX : TextBox
{
    public event EventHandler DoingAPaint;
    protected override void WndProc(ref Message m)
    {
        switch ((int)m.Msg)
        {
            case (int)NativeMethods.WindowMessages.WM_PAINT:
            case (int)NativeMethods.WindowMessages.WM_ERASEBKGND:
            case (int)NativeMethods.WindowMessages.WM_NCPAINT:
            case 8465: //not sure what this is WM_COMMAND?
                if(DoingAPaint!=null)DoingAPaint(this,EventArgs.Empty);
                break;
        }           
        base.WndProc(ref m);
    }
}

не протестированный и я уверен, что можно изменить к лучшему его

4
ответ дан Hath 27 November 2019 в 00:51
поделиться

Исходный код должен быть:

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp;
            cp = base.CreateParams;
            cp.Style &= 0x7DFFFFFF; //WS_CLIPCHILDREN
            return cp;
        }
    }

Это работает!!

1
ответ дан 27 November 2019 в 00:51
поделиться

Как насчет этого возьмем решение #1 (Get the desktop DC and Draw on the screen):

  1. Get the desktop DC and the graphics object for that DC [Graphics.fromHDC(...)]
  2. Установим свойство Clip результирующего графического объекта в качестве видимой в данный момент области вашей формы. (Я еще не исследовал, как найти видимую область формы)
  3. Делайте рендеринг своей графики.
1
ответ дан 27 November 2019 в 00:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: