I am developing an application to capture the user's desktop, this process works well, the desktop capture is sent to a picturebox with the full image, and within this picturebox, I have a custom control that is added, for the user to select the desired area. The problem in question is I can't draw in this control, I have a toolbox where the user can choose between free drawing and an arrow, but I can't make these drawings within the control. Drawings work well outside of control and also in another picturebox that is not linked.
I used the example provided in this post Detect mouse over User Control and all children - C# WinForms, but unfortunately it didn't work either
This is the code for my control, I even made some adaptations to the MouseDown, MouseUp and MouseMove events, but I still haven't been successful.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace ControlSizable
{
public partial class FrameControl: UserControl
{
public FrameControl()
{
InitializeComponent();
WireMouseEvents(this);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Transparent;
}
[DefaultValue(true)]
public bool CanMove { get; set; } = true;
void WireMouseEvents(Control container)
{
foreach (Control c in container.Controls)
{
c.MouseDown += (s, e) => OnMouseDown(e);
c.MouseMove += (s, e) => OnMouseMove(e);
c.MouseUp += (s, e) => OnMouseUp(e);
c.Click += (s, e) => OnClick(e);
c.DoubleClick += (s, e) => OnDoubleClick(e);
c.MouseHover += (s, e) => OnMouseHover(e);
c.MouseClick += (s, e) => {
var p = PointToThis((Control)s, e.Location);
OnMouseClick(new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta));
};
c.MouseDoubleClick += (s, e) => {
var p = PointToThis((Control)s, e.Location);
OnMouseDoubleClick(new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta));
};
WireMouseEvents(c);
};
}
Point PointToThis(Control c, Point p)
{
return PointToClient(c.PointToScreen(p));
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
WireMouseEvents(this);
}
private void FrameControl_MouseDown(object sender, MouseEventArgs e)
{
Console.Write("Box1 clicked.");
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var p = new Pen(Color.White , 3))
{
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash ;
e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
}
}
const int WM_NCHITTEST = 0x84;
const int WM_SETCURSOR = 0x20;
const int WM_NCLBUTTONDBLCLK = 0xA3;
protected override void WndProc(ref Message m)
{
int borderWidth = 10;
if (m.Msg == WM_SETCURSOR) /*Setting cursor to SizeAll*/
{
if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/)
{
//Cursor.Current = Cursors.SizeAll;
Cursor.Current = CanMove ? Cursors.SizeAll : Cursors.Arrow;
m.Result = (IntPtr)1;
return;
}
else if ((m.LParam.ToInt32() & 0xffff) == 0x3 /*Move*/)
{
Cursor.Current = Cursors.Arrow ;
m.Result = (IntPtr)1;
return;
}
}
if ((m.Msg == WM_NCLBUTTONDBLCLK)) /*Disable Mazimiz on Double click*/
{
m.Result = (IntPtr)1;
return;
}
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
{
var pos = PointToClient(new Point(m.LParam.ToInt32() & 0xffff,
m.LParam.ToInt32() >> 16));
if (pos.X <= ClientRectangle.Left + borderWidth &&
pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(13); //TOPLEFT
else if (pos.X >= ClientRectangle.Right - borderWidth &&
pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(14); //TOPRIGHT
else if (pos.X <= ClientRectangle.Left + borderWidth &&
pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(16); //BOTTOMLEFT
else if (pos.X >= ClientRectangle.Right - borderWidth &&
pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(17); //BOTTOMRIGHT
else if (pos.X <= ClientRectangle.Left + borderWidth)
m.Result = new IntPtr(10); //LEFT
else if (pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(12); //TOP
else if (pos.X >= ClientRectangle.Right - borderWidth)
m.Result = new IntPtr(11); //RIGHT
else if (pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(15); //Bottom
else
//m.Result = new IntPtr(2); //Move
m.Result = CanMove ? new IntPtr(2) : IntPtr.Zero;
}
}
}
}
This is the code I use to make the drawings and also the screenshot. My control is written in C# and created a Dll and all the rest of my code is in VB.net
Imports System.Drawing.Drawing2D
Public Class frm_transp_form
Private imgInput As Image
Private EndLocation As Point
Private StartLocation As Point
Private rect As Rectangle
Private IsMouseDown As Boolean = False
Private m_Drawing As Boolean
Private m_StartX, m_StartY, m_CurX, m_CurY As Single
Dim MyLineArrows As New List(Of LineList)
Private Sub frm_transp_form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Size = New Size(Screen.AllScreens.Sum(Function(s As Screen) s.Bounds.Width), Screen.AllScreens.Max(Function(s As Screen) s.Bounds.Height))
pb_screen.Dock = DockStyle.Fill
Dim bmp As Bitmap = New Bitmap(Screen.AllScreens.Sum(Function(s As Screen) s.Bounds.Width), Screen.AllScreens.Max(Function(s As Screen) s.Bounds.Height))
Using g As Graphics = Graphics.FromImage(bmp)
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
g.CopyFromScreen(SystemInformation.VirtualScreen.X, SystemInformation.VirtualScreen.Y, 0, 0, SystemInformation.VirtualScreen.Size, CopyPixelOperation.SourceCopy)
'Me.BackgroundImage = bmp
pb_screen.Image = bmp
End Using
Me.Location = New Point(0, 0)
Me.Cursor = Cursors.Arrow
ctrlResize.Size = New Size(0, 0)
ctrlResize.Location = New Point(0, 0)
pb_screen.Controls.Add(ctrlResize)
AddHandler ctrlResize.MouseDown, New MouseEventHandler(AddressOf controlResize_MouseDown)
AddHandler ctrlResize.MouseUp, New MouseEventHandler(AddressOf controlResize_MouseUP)
AddHandler ctrlResize.MouseMove, New MouseEventHandler(AddressOf controlResize_MouseMove)
AddHandler ctrlResize.MouseClick, New MouseEventHandler(AddressOf controlResize_MouseClick)
AddHandler ctrlResize.Paint, New PaintEventHandler(AddressOf controlResize_Paint)
End Sub
Private Sub pb_screen_MouseDown(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseDown
IsMouseDown = True
StartLocation = e.Location
ctrlResize.CanMove = True
pnl_menu.Visible = False
Console.WriteLine("Startlocation: " & StartLocation.ToString)
End Sub
Private Sub pb_screen_MouseMove(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseMove
If IsMouseDown = True Then
EndLocation = e.Location
GetRectangle()
Application.DoEvents()
lbl_position.Text = rect.Width & "x" & rect.Height
ctrlResize.Size = New Size(rect.Size)
ctrlResize.Location = New Point((StartLocation.X), (StartLocation.Y))
pnl_menu.Location = New Point(EndLocation.X + 5, EndLocation.Y - pnl_menu.Height)
Application.DoEvents()
pb_screen.Invalidate()
End If
End Sub
Private Sub pb_screen_Paint(sender As Object, e As PaintEventArgs) Handles pb_screen.Paint
e.Graphics.ExcludeClip(ctrlResize.Bounds)
Using b = New SolidBrush(Color.FromArgb(100, Color.Black))
e.Graphics.FillRectangle(b, pb_screen.ClientRectangle)
End Using
End Sub
Private Sub pb_screen_MouseUp(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseUp
If IsMouseDown = True Then
EndLocation = e.Location
IsMouseDown = False
Console.WriteLine("Retangulo: " & rect.Size.ToString)
pnl_menu.Visible = True
End If
End Sub
Private Sub UseDoubleBuffer()
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.UserPaint Or
ControlStyles.OptimizedDoubleBuffer, True)
End Sub
Private Sub controlResize_Paint(sender As Object, e As PaintEventArgs)
Dim i, x1, y1, x2, y2 As Integer
For i = 0 To MyLineArrows.Count - 1
Dim Arrow1 As New Pen(Color.FromArgb(255, 0, 0, 255), 10)
Arrow1.EndCap = LineCap.Custom
Arrow1.CustomEndCap = New AdjustableArrowCap(3, 3, False)
x1 = MyLineArrows(i).X1 : x2 = MyLineArrows(i).X2
y1 = MyLineArrows(i).Y1 : y2 = MyLineArrows(i).Y2
e.Graphics.DrawLine(Arrow1, x1, y1, x2, y2)
Next
If m_Drawing Then
Dim dashed_pen As New Pen(Color.Green, 1)
Dim Arrow As New Pen(Color.FromArgb(255, 0, 0, 255), 10)
Arrow.EndCap = LineCap.Custom
Arrow.CustomEndCap = New AdjustableArrowCap(3, 3, False)
e.Graphics.DrawLine(Arrow, m_StartX, m_StartY, m_CurX, m_CurY)
End If
End Sub
Private Sub controlResize_MouseClick(sender As Object, e As MouseEventArgs)
MessageBox.Show("Foi Clicado dentro do Controle")
Console.WriteLine("Foi Clicado dentro do Controle")
End Sub
Private Sub controlResize_MouseDown(sender As Object, e As MouseEventArgs)
m_Drawing = True
m_StartX = e.X
m_StartY = e.Y
m_CurX = e.X
m_CurY = e.Y
Console.WriteLine("Valores do MouseDown: " & m_Drawing & " - " & m_StartX & " - " & m_StartY & " - " & m_CurX & " - " & m_CurY)
End Sub
Private Sub controlResize_MouseUP(sender As Object, e As MouseEventArgs)
m_Drawing = False
Dim DrawLine As New LineList
DrawLine.X1 = m_StartX
DrawLine.Y1 = m_StartY
DrawLine.X2 = m_CurX
DrawLine.Y2 = m_CurY
MyLineArrows.Add(DrawLine)
End Sub
Private Sub controlResize_MouseMove(sender As Object, e As MouseEventArgs)
Dim g As Graphics = ctrlResize.CreateGraphics
Dim dashed_pen As New Pen(Color.Green, 1)
dashed_pen.DashStyle = DashStyle.Dash
m_CurX = e.X
m_CurY = e.Y
ctrlResize.Invalidate()
End Sub
Private Sub btn_arrow_Click(sender As Object, e As EventArgs) Handles btn_arrow.Click
ctrlResize.CanMove = False
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
End
End Sub
Private Function GetRectangle() As Rectangle
rect = New Rectangle With {
.X = Math.Min(StartLocation.X, EndLocation.X),
.Y = Math.Min(StartLocation.Y, EndLocation.Y),
.Width = Math.Abs(StartLocation.X - EndLocation.X),
.Height = Math.Abs(StartLocation.Y - EndLocation.Y)
}
Return rect
End Function
Protected Overrides ReadOnly Property CreateParams As CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H2000000
Return cp
End Get
End Property
End Class
This is an example of capturing the desktop, with the toolbox and also the control in the center of the image.
Any ideas what might have happened that I can't get these mouse events on my control?