Как добавить рукоятку захвата в Splitter of SplitContainer

В разделительной панели SplitContainer было 3 точки. Точно так же, как есть три строки, о которых идет речь, текстовое поле на StackOverflow, которое показывает, что его можно схватить. Как это сделать с помощью разделительной панели SplitContainer в .NET?

Ответы

Ответ 1

Не то, чтобы у меня было что-то против Алекс, но я думал, что поделюсь этим решением, поскольку он выглядит немного лучше для меня (на любом компьютере XP)?

private void SplitContainer_Paint(object sender, PaintEventArgs e)
{
    var control = sender as SplitContainer;
    //paint the three dots'
    Point[] points = new Point[3];
    var w = control.Width;
    var h = control.Height;
    var d = control.SplitterDistance;
    var sW = control.SplitterWidth;

    //calculate the position of the points'
    if (control.Orientation == Orientation.Horizontal)
    {
        points[0] = new Point((w / 2), d + (sW / 2));
        points[1] = new Point(points[0].X - 10, points[0].Y);
        points[2] = new Point(points[0].X + 10, points[0].Y);
    }
    else
    {
        points[0] = new Point(d + (sW / 2), (h / 2));
        points[1] = new Point(points[0].X, points[0].Y - 10);
        points[2] = new Point(points[0].X, points[0].Y + 10);
    }

    foreach (Point p in points)
    {
        p.Offset(-2, -2);
        e.Graphics.FillEllipse(SystemBrushes.ControlDark,
            new Rectangle(p, new Size(3, 3)));

        p.Offset(1, 1);
        e.Graphics.FillEllipse(SystemBrushes.ControlLight,
            new Rectangle(p, new Size(3, 3)));
    }
}

Надеюсь, это кому-то понравится? Хаа!

Ответ 2

Это не реализовано. Если вам нужна эта функция, лучше всего вывести SplitContainer и переопределить метод OnPaint.


Обновление 1

Вот код, который вы делаете. Это в VB.NET, и размещение точек может быть связано с некоторой настройкой. В целом, код работает как ожидалось.

Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing

Public Class SplitContainerEx
    Inherits SplitContainer

    ''' <summary>Determines the thickness of the splitter.</summary>
    <DefaultValue(GetType(Integer), "5"), Description("Determines the thickness of the splitter.")> _
           Public Overridable Shadows Property SplitterWidth() As Integer
        Get
            Return MyBase.SplitterWidth
        End Get
        Set(ByVal value As Integer)
            If value < 5 Then value = 5

            MyBase.SplitterWidth = value
        End Set
    End Property

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        'paint the three dots
        Dim points(2) As Point
        Dim pointRect = Rectangle.Empty

        'calculate the position of the points
        If Orientation = Windows.Forms.Orientation.Horizontal Then
            points(0) = New Point((MyBase.Width \ 2), SplitterDistance + (SplitterWidth \ 2))
            points(1) = New Point(points(0).X - 10, points(0).Y)
            points(2) = New Point(points(2).X + 10, points(0).Y)
            pointRect = New Rectangle(points(1).X - 2, points(1).Y - 2, 25, 5)
        Else
            points(0) = New Point(SplitterDistance + (SplitterWidth \ 2), (MyBase.Height \ 2))
            points(1) = New Point(points(0).X, points(0).Y - 10)
            points(2) = New Point(points(0).X, points(0).Y + 10)
            pointRect = New Rectangle(points(1).X - 2, points(1).Y - 2, 5, 25)
        End If

        e.Graphics.FillRectangle(Brushes.Gray, pointRect)

        For Each p In points
            p.Offset(-1, -1)
            e.Graphics.FillEllipse(Brushes.Black, New Rectangle(p, New Size(3, 3)))
        Next
    End Sub
End Class

Обновление 2

Я использую эквивалент С#, потому что вы отметили свой вопрос так. Если vb makes you sick, научитесь переходить к Преобразование VB.NET в С# - Разработчик Fusion и преобразование VB в С#.

using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

public class SplitContainerEx : SplitContainer
{

    /// <summary>Determines the thickness of the splitter.</summary>
    [DefaultValue(typeof(int), "5"), Description("Determines the thickness of the splitter.")]
    public virtual new int SplitterWidth {
        get { return base.SplitterWidth; }
        set {
            if (value < 5)
                value = 5;

            base.SplitterWidth = value;
        }
    }

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        base.OnPaint(e);
        //paint the three dots
        Point[] points = new Point[3];
        Rectangle pointRect = Rectangle.Empty;

        //calculate the position of the points
        if (Orientation == System.Windows.Forms.Orientation.Horizontal) {
            points[0] = new Point((int)(base.Width / 2), SplitterDistance + (int)(SplitterWidth / 2));
            points[1] = new Point(points[0].X - 10, points[0].Y);
            points[2] = new Point(points[2].X + 10, points[0].Y);
            pointRect = new Rectangle(points[1].X - 2, points[1].Y - 2, 25, 5);
        } else {
            points[0] = new Point(SplitterDistance + (int)(SplitterWidth / 2), (int)(base.Height / 2));
            points[1] = new Point(points[0].X, points[0].Y - 10);
            points[2] = new Point(points[0].X, points[0].Y + 10);
            pointRect = new Rectangle(points[1].X - 2, points[1].Y - 2, 5, 25);
        }

        e.Graphics.FillRectangle(Brushes.Gray, pointRect);

        foreach (Point p in points) {
            p.Offset(-1, -1);
            e.Graphics.FillEllipse(Brushes.Black, new Rectangle(p, new Size(3, 3)));
        }
    }
}

Ответ 3

Ближе всего вы можете прийти, не нарисовав его самостоятельно, чтобы изменить BorderStyle на Fixed3D. Это даст вам своего рода "бар" между двумя панелями.

Если вам не нравится затонувший вид на обеих панелях, вы можете "скрыть" внешние границы, поместив свою разделенную панель на другую панель и установив ее Location на отрицательное значение (например, -n,-n) и его размер до размера его родительской панели + 2*n. Затем я установил Anchor в Top | Left | Bottom | Right, чтобы он оставался таким, как вы изменяете размер родительской панели.

Это своего рода kludge, но кое-что, что я, безусловно, считал своим делом, поскольку ненавижу, что нет никаких указаний о том, где находится "точка захвата".

Ответ 4

Мне понравились shousper, и Алекс ответил, но они казались немного "сложными" для моего вкуса; казалось, было больше кода, который я бы счел нужным.

Ответ Shaun также работает (я также нашел это в MSDN), но в приложении, над которым я работаю, "ручки захвата" стали довольно отвлекающими, так как они почти заполняют разделитель, и у нас есть довольно много их.

Итак, я придумал это, которое находится между ними. Нет массивов, нет новых прямоугольников. Потребуется очень немного дополнительной работы для эффекта "3D" из "принятого" ответа, но для меня три простых точки:

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

    Point centerPoint = new Point(SplitterRectangle.Left - 1 + SplitterRectangle.Width / 2, SplitterRectangle.Top - 1 + SplitterRectangle.Height / 2);

    e.Graphics.FillEllipse(SystemBrushes.ControlText, centerPoint.X, centerPoint.Y, 3, 3);
    if (Orientation == System.Windows.Forms.Orientation.Horizontal) {
        e.Graphics.FillEllipse(SystemBrushes.ControlText, centerPoint.X - 10, centerPoint.Y, 3, 3);
        e.Graphics.FillEllipse(SystemBrushes.ControlText, centerPoint.X + 10, centerPoint.Y, 3, 3);
    } else {
        e.Graphics.FillEllipse(SystemBrushes.ControlText, centerPoint.X, centerPoint.Y - 10, 3, 3);
        e.Graphics.FillEllipse(SystemBrushes.ControlText, centerPoint.X, centerPoint.Y + 10, 3, 3);
    }
}

Ответ 5

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

...
mySplitContainer.Paint += CustomPaint.PaintSplitterWithHandle;
...

public static class CustomPaint {
  public static void PaintSplitterWithHandle(object sender, PaintEventArgs p) {
    SplitContainer splitter = sender as SplitContainer;
    if (splitter == null) return;
    if (splitter.Orientation == Orientation.Horizontal)
        p.Graphics.DrawLine(Pens.DarkGray, 
           0, splitter.SplitterDistance + (splitter.SplitterWidth / 2),
           splitter.Width, splitter.SplitterDistance + (splitter.SplitterWidth / 2));
    else
        p.Graphics.DrawLine(Pens.DarkGray, 
            splitter.SplitterDistance + (splitter.SplitterWidth / 2), 0,
            splitter.SplitterDistance + (splitter.SplitterWidth / 2), splitter.Height);
  }
}

Ответ 6

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

ControlPaint.DrawGrabHandle(e.Graphics, SplitterRectangle, true, Enabled);

Это приведет к базовой разделительной линии между панелями.