Как добавить рукоятку захвата в 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);
Это приведет к базовой разделительной линии между панелями.