Show Splitter-like box when resize a form

G

Guest

I want to implement the following:

If the user clicks on the border of a form, then I want to show a box around
the form that represents the form's bounds. As the user moves the mouse only
the box's bounds would change. When the user releases the mouse the form's
bounds would be set to the bounds of the box. Note that this is very similar
to how the Splitter control works.

Does anybody know how to do this?

Thanks for any help!
Lance
 
L

Linda Liu [MSFT]

Hi Lance,

This is a quick note to let you know that I am performing research on this
issue and will get back to you ASAP.

I appreciate your patience!

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu [MSFT]

Hi Lance,

After doing some research, I work this issue out. My solution is to set the
FormBorderStyle property of the form to FixedSingle, and then draw the
sizing border using ControlPaint.DrawReversibleFrame method while the left
mouse button is held down.

Normally, when we point the mouse to the form borders, the cursor will be
altered to a proper shape, e.g.SizeNWSE, SizeNS and etc. At this time, if
we click the left mouse button down, the WM_SYSCOMMAND message is sent to
the form. Then the WM_ENTERSIZEMOVE message is sent one time to the form
after it enters the sizing modal loop. The size of the form will change
with the current position of the cursor.

I have tried to override the WndProc method of the form and capture the
WM_ENTERSIZEMOVE message and discard this message, but without effect. The
form still enters the sizing modal loop and its size changes when I drag
the form's border. I also have a try capturing the WM_SYSCOMMAND and if it
has a parmeter of SC_SIZE, discarding this message. However, at this time,
the form doesn't act to the drag operation.

So the only solution to draw splitter-like box when resizing a form is to
prevent the form from entering into the sizing modal loop(to do this, set
the FormBorderStyle of the form to FixedSingle) and draw the splitter-like
box by ourselves.

The following is a sample.

public partial class Form1 : Form
{
bool mouseIsDown = false;
Point lastPoint = new Point();
Cursor sizingCursor = Cursors.Arrow;

public Form2()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MouseDown += new MouseEventHandler(Form1_MouseDown);
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
this.MouseUp += new MouseEventHandler(Form1_MouseUp);
}

void Form1_MouseDown(object sender, MouseEventArgs e)
{
mouseIsDown = true;
lastPoint.X = -1;
lastPoint.Y = -1;
}

void Form1_MouseMove(object sender, MouseEventArgs e)
{
Point currentPoint = new Point(e.X,e.Y);

if (!mouseIsDown)
{
if (Math.Abs(e.X - this.ClientSize.Width) < 10 &&
Math.Abs(e.Y - this.ClientSize.Height) < 10)
{
this.Cursor = Cursors.SizeNWSE;
sizingCursor = this.Cursor;
}
else if (Math.Abs(e.X - this.ClientSize.Width) < 10)
{
this.Cursor = Cursors.SizeWE;
sizingCursor = this.Cursor;
}
else if (Math.Abs(e.Y - this.ClientSize.Height) < 10)
{
this.Cursor = Cursors.SizeNS;
sizingCursor = this.Cursor;
}
else
this.Cursor = Cursors.Arrow;
}
if (mouseIsDown)
{
this.Cursor = sizingCursor;
if (this.Cursor != Cursors.Arrow)
{

if (lastPoint.X != -1)
{
Point cal_lastPoint = new Point();
if (this.Cursor == Cursors.SizeWE)
{
cal_lastPoint.X = lastPoint.X;
cal_lastPoint.Y = this.ClientSize.Height;
}
else if (this.Cursor == Cursors.SizeNWSE)
{
cal_lastPoint = lastPoint;
}
else if (this.Cursor == Cursors.SizeNS)
{
cal_lastPoint.X = this.ClientSize.Width;
cal_lastPoint.Y = lastPoint.Y;
}
MyDrawReversibleFrame(new Point(0, 0),
cal_lastPoint);
}
lastPoint = currentPoint;

Point cal_currentPoint = new Point();
if (this.Cursor == Cursors.SizeWE)
{
cal_currentPoint.X = currentPoint.X;
cal_currentPoint.Y = this.ClientSize.Height;
}
else if (this.Cursor == Cursors.SizeNWSE)
{
cal_currentPoint = currentPoint;
}
else if (this.Cursor == Cursors.SizeNS)
{
cal_currentPoint.X = this.ClientSize.Width;
cal_currentPoint.Y = currentPoint.Y;
}
MyDrawReversibleFrame(new Point(0, 0),
cal_currentPoint);
}
}
}

void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseIsDown = false;
sizingCursor = Cursors.Arrow;
if (lastPoint.X != -1)
{
Point cal_lastPoint = new Point();
if (this.Cursor == Cursors.SizeWE)
{
cal_lastPoint.X = lastPoint.X;
cal_lastPoint.Y = this.ClientSize.Height;
}
else if (this.Cursor == Cursors.SizeNWSE)
{
cal_lastPoint = lastPoint;
}
else if (this.Cursor == Cursors.SizeNS)
{
cal_lastPoint.X = this.ClientSize.Width;
cal_lastPoint.Y = lastPoint.Y;
}
MyDrawReversibleFrame(new Point(0, 0), cal_lastPoint);
this.ClientSize = new Size(cal_lastPoint.X,cal_lastPoint.Y);
}
lastPoint.X = -1;
lastPoint.Y = -1;
}

private void MyDrawReversibleFrame(Point point1, Point point2)
{
point1 = PointToScreen(point1);
point2 = PointToScreen(point2);

ControlPaint.DrawReversibleFrame(
new Rectangle(point1.X - 3, point1.Y - 23,
point2.X-point1.X + 3, point2.Y-point1.Y+23),
Color.Black,
FrameStyle.Dashed);
}

}

It works well on my part. Please try it on your machine and let me know the
result.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Wow, that's great. It works just as you said. Thank you so much!

Just wondering though if you know how the splitter control draws its icon.
If possible I would like to mimic the appearance of the splitter control's
icon (i.e., a thick checkered line) but the ControlPaint.DrawReversibleFrame
method only allows for either FrameStyle.Dashed or FrameStyle.Thick.

Thanks again. You're always a big help!
Lance
 
L

Linda Liu [MSFT]

Hi Lance,

Thank you for your feedback.

After doing more research, I work out how to mimic the appearance of the
splitter control's icon. That is to create a bitmap in the project and
create a pattern brush on this bitmap. Select the patter brush into the
device context(DC) of the screen and then call the Gdi32 function PatBlt to
draw the sizing border of the form.

Firstly, double-click the Resources.resx in the Solution Explorer and add a
bitmap in the Resources.resx. The new bitmap is named Image1 and displayed
in an image editor automatically. Resize the bitmap to the size of 2*2.
Color the top-left and bottom-right panes to Black.

Modifiy the code I provided in my previous reply as follows:

using System.Runtime.InteropServices;
public partial class Form1 : Form
{
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError =
true, ExactSpelling = true)]
public static extern bool PatBlt(IntPtr hdc, int left, int top, int
width, int height, int rop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreatePatternBrush(IntPtr hbmp);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr
hgdiobj);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

int PATINVERT = 0x5A0049;

private void MyDrawReversibleFrame(Point point1, Point point2)
{
point1 = PointToScreen(point1);
point2 = PointToScreen(point2);

//ControlPaint.DrawReversibleFrame(
// new Rectangle(point1.X - 3, point1.Y - 23,
point2.X-point1.X + 3, point2.Y-point1.Y+23),
// Color.Black,
// FrameStyle.Thick);

using (Graphics g = this.CreateGraphics())
{
IntPtr hbitmap =
ControlPaint.CreateHBitmap16Bit(Properties.Resources.Image1,
Color.Transparent);
IntPtr hbrush = CreatePatternBrush(hbitmap);
IntPtr hScreenDC = GetDC(IntPtr.Zero);
SelectObject(hScreenDC,hbrush);
int x = point1.X - 3;
int y = point1.Y - 23;
int width = point2.X - point1.X + 3;
int height = point2.Y - point1.Y + 23;

PatBlt(hScreenDC,x-2 ,y-2, 2 ,height+4 , PATINVERT);
PatBlt(hScreenDC, x, y - 2, width, 2, PATINVERT);
PatBlt(hScreenDC, x, y + height, width, 2, PATINVERT);
PatBlt(hScreenDC, x + width , y -2, 2, height + 4,
PATINVERT);

ReleaseDC(IntPtr.Zero, hScreenDC);
}
}
}

Hope this helps.
If you need, I could send you a sample project.
If you have anything unclear, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top