Custom paint Splitter control in C# WinForms
Asked Answered
Z

2

3

I am trying to paint the split line that appears when you drag a splitter control:

Splitter

As you can see from this image, the default splitter is a checkerboard.

...this doesn't work:

public partial class MockForm : Form
{
    public MockForm()
    {
        InitializeComponent();
        this.splitter1.Paint += splitter1_Paint;
    }

    private void splitter1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.Clear(Color.Red);
    }
}

this just paints the background of the control but not the splitter when it's dragged.

Any ideas?

Zillah answered 5/3, 2015 at 12:51 Comment(4)
Unfortunatelly the system does not generate any paint messages while dragging the splitter. The drawing is done internally. It is like the scroll bar control. You can not do something about it. I may be wrong though and there is hack that I do not know about.Aneurysm
Check this.Chocolate
I know this is somehow old question and the answer posted by LarsTech is really good, But the handler flickers are somehow annoying. Instead of showing the control in Form, if you show a Form as splitter handler and show it above the Container of splitter, the flickers will be gone.Lenes
Also to see a custom splitter which supports transparent handler take a look at this related post. In the other post I created a new splitter control using source codes of original splitter, but changed rendering the highlight: Change Splitter Highlighting/Resize LineLenes
L
3

The answer posted by LarsTech is really good, But the handler flickers are somehow annoying. Instead of showing the control in Form, if you show a Form as splitter handler and show it above the Container of splitter, the flickers will be gone.

HighLight f = new HighLight() { BackColor = Color.Red };
private void splitter1_SplitterMoving(object sender, SplitterEventArgs e)
{
    this.splitter1.Parent.Refresh();
    f.Location = this.splitter1.Parent.PointToScreen(new Point(e.SplitX, e.SplitY));
    f.Size = this.splitter1.Size;
    if (!f.Visible)
        f.ShowInactiveTopmost();
}
private void splitter1_SplitterMoved(object sender, SplitterEventArgs e)
{
    f.Hide();
}

Here is the form which I used as highlight:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class HighLight : Form
{
    public HighLight()
    {
        Opacity = 0;
        FormBorderStyle = FormBorderStyle.None;
        ShowInTaskbar = false;
        StartPosition = FormStartPosition.Manual;
    }
    protected override void OnDeactivate(EventArgs e)
    {
        base.OnDeactivate(e);
        this.Hide();
    }
    private const int SW_SHOWNOACTIVATE = 4;
    private const int HWND_TOPMOST = -1;
    private const uint SWP_NOACTIVATE = 0x0010; 
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    static extern bool SetWindowPos(int hWnd, int hWndInsertAfter,
         int X, int Y, int cx, int cy, uint uFlags);
    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    public void ShowInactiveTopmost()
    {
        ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
        SetWindowPos(this.Handle.ToInt32(), HWND_TOPMOST,
        this.Left, this.Top, this.Width, this.Height,
        SWP_NOACTIVATE);
        this.Opacity = 1;
    }
}

To see a custom splitter which supports transparent handler take a look at this related post. In the other post I created a new splitter control using source codes of original splitter, but changed rendering the highlight:

Lenes answered 21/8, 2016 at 20:54 Comment(0)
M
2

The old Splitter control uses a private painting method to produce that checkerboard effect, so there isn't any thing you can override to replace that.

You can fake it by dragging your own control in the space of the checkerboard control you see on the screen. This may produce some flicker:

Control draggingControl = new Control { BackColor = Color.Green, Visible = false };

public MockForm() {
  InitializeComponent();
  this.Controls.Add(draggingControl);
  splitter1.SplitterMoving += splitter1_SplitterMoving;
  splitter1.SplitterMoved += splitter1_SplitterMoved;
}

void splitter1_SplitterMoving(object sender, SplitterEventArgs e) {
  draggingControl.Bounds = new Rectangle(new Point(e.X - (e.X - e.SplitX), 0),
                                         splitter1.Size);
  if (!draggingControl.Visible) {
    draggingControl.Visible = true;
    draggingControl.BringToFront();
  }
  this.Refresh();
}

void splitter1_SplitterMoved(object sender, SplitterEventArgs e) {
  draggingControl.Visible = false;
  this.Refresh();
}

The Splitter control was deprecated in favor of the SplitContainer control.

Mourning answered 5/3, 2015 at 17:13 Comment(1)
Really good idea, but the flickers are somehow annoying. I used a Form above the current form instead of user control then since the original highlight is drawn on the container of splitter which is under the highlight form which I used, the flickers removed.Lenes

© 2022 - 2024 — McMap. All rights reserved.