I have a WinForms project. I have a panel on the top of my window. I want that panel to be able to move the window, when the user clicks on it and then drags.
How can I do this?
Add the following declerations to your class:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HTCAPTION = 0x2;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
Put this in your panel's MouseDown event:
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
}
Related
I have a User Control that contains one Panel filling the entire UC. Within the panel there is a PctureBox and a Label. My issue is trying to make it so that no matter which control my cursor moves across, the backcolor on the panel will change as an indicator. I've made it possible in this way (see code below), but I'm sure this isn't the best way of doing it? Keep in mind I'm going to add maybe a hundred of these, so I'm aiming for it to be fairly optimized.
private void PMain_MouseMove(object sender, MouseEventArgs e)
{
Panel pan = sender as Panel;
pan.BackColor = Color.DimGray;
}
private void PMain_MouseLeave(object sender, EventArgs e)
{
Panel pan = sender as Panel;
pan.BackColor = originalBackColor;
}
private void PbIcon_MouseMove(object sender, MouseEventArgs e)
{
pMain.BackColor = Color.DimGray;
}
private void PbIcon_MouseLeave(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
private void LTitle_MouseMove(object sender, MouseEventArgs e)
{
pMain.BackColor = Color.DimGray;
}
private void LTitle_MouseLeave(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
If I'm getting you correctly you are trying to do something like the following
in order to do that without having to do it for every control that your user control has, you can insert a thread WH_GETMESSAGE hook to your main thread and check WM_MOUSEHOVER, WM_MOUSELEAVE, WM_MOUSEMOVE messages for your user control and its children
Below is the code sample for UserControl1 which has one Panel filling the entire UC, one PictureBox (koala in it) and one Label (written label1 on it)
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApp1
{
public partial class UserControl1 : UserControl
{
const int WH_GETMESSAGE = 0x03;
const int WM_MOUSEHOVER = 0x02A1;
const int WM_MOUSELEAVE = 0x02A3;
const int WM_MOUSEMOVE = 0x0200;
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
IntPtr _hook;
HookProc _hookProc;
public UserControl1()
{
InitializeComponent();
this.HandleCreated += (sender, e) =>
{
_hookProc = new HookProc(GetMsgHookProc);
_hook = SetWindowsHookEx(
WH_GETMESSAGE,
_hookProc,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
GetWindowThreadProcessId(this.Handle, IntPtr.Zero));
};
this.Disposed += (sender, e) =>
{
UnhookWindowsHookEx(_hook);
};
}
private bool IsOurChild(Control ctl)
{
if (ctl == null)
return false;
if (ctl.Handle == this.Handle || ctl.Parent?.Handle == this.Handle)
return true;
return IsOurChild(ctl.Parent);
}
private int GetMsgHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hook, nCode, wParam, lParam);
Message m = Marshal.PtrToStructure<Message>(lParam);
Control ctl = Control.FromHandle(m.HWnd);
if (IsOurChild(ctl))
{
if (m.Msg == WM_MOUSEHOVER || m.Msg == WM_MOUSEMOVE)
this.BackColor = Color.Red;
if (m.Msg == WM_MOUSELEAVE)
this.BackColor = Color.Blue;
}
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
}
}
Maybe you can do like this. Example:
Designer
//SomeButton
this.SomeButton.Click += delegate(object sender, EventArgs e)
{ SomeUserControl_Event(sender, e); };
//SomeLabel
this.SomeButton.Click += delegate(object sender, EventArgs e)
{ SomeUserControl_Event(sender, e); };
Cs
private void SomeUserControl_Event(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
Its only a example
It works on other winform programs, but not in the game itself.
I'm trying to make an extra menu or "mod menu" but it's invisible.
The button for message box to test if winform works. When I click "nowhere" in up left corner, it shows me the "hello" in the message box.
I tried editing the code but unable to find the problem. What should I do?
namespace myapp
{
public partial class Form1 : Form
{
[System.ComponentModel.Browsable(false)]
public bool AllowTransparency { get; set; }
[System.ComponentModel.Browsable(false)]
public bool AllowTransparencykey { get; set; }
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public static int GWL_STYLE = -16;
public static int WS_CHILD = 0x40000000;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Process hostProcess = Process.GetProcessesByName("game").FirstOrDefault();
if (hostProcess != null)
{
Hide();
FormBorderStyle = FormBorderStyle.None;
SetBounds(0, 0, 0, 0, BoundsSpecified.Location);
IntPtr hostHandle = hostProcess.MainWindowHandle;
IntPtr guestHandle = this.Handle;
SetWindowLong(guestHandle, GWL_STYLE, GetWindowLong(guestHandle, GWL_STYLE) | WS_CHILD);
SetParent(guestHandle, hostHandle);
Show();
FormBorderStyle = FormBorderStyle.None;
SetBounds(0, 0, 0, 0, BoundsSpecified.Location);
}
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
}
}
I am writing an application that needs to draw outside of it's main window area. I already have to code to actually do the drawing:
[DllImport("User32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("User32.dll")]
public static extern void ReleaseDC(IntPtr hwnd, IntPtr dc);
IntPtr desktopPtr = GetDC(IntPtr.Zero);
Graphics g = Graphics.FromHdc(desktopPtr);
g.DrawLine(Pens.White, 0, 0, Screen.FromControl(this).WorkingArea.Width, Screen.FromControl(this).WorkingArea.Height);
g.Dispose();
ReleaseDC(IntPtr.Zero, desktopPtr);
However the on paint event is an unsuitable place to put the code because it's not called when something outside of the form is redrawn. So my question is, where could this code be placed so it is called whenever part of the screen is redrawn?
If you want content painted on the screen, you should always create a window to hold that content. Painting on the desktop (a window that you don't own) is a bad idea.
The solution is to create a window, with the extended style WS_EX_NOACTIVATE and draw on that in response to WM_PAINT messages. For a WinForms application, the runtime calls Form.OnPaint when you get a WM_PAINT so you can handle that event and do the painting there. To demonstrate:
[DllImport("User32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int index);
[DllImport("User32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int index, IntPtr value);
[DllImport("User32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOZORDER = 0x0004;
private const uint SWP_FRAMECHANGED = 0x0020;
private const uint StyleUpdateFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED;
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.Paint += Form1_Paint;
this.Shown += Form1_Shown;
}
private void Form1_Shown(object sender, EventArgs e)
{
IntPtr currentStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
int current = currentStyle.ToInt32();
current |= WS_EX_NOACTIVATE;
SetWindowLong(this.Handle, GWL_EXSTYLE, new IntPtr(current));
SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0, StyleUpdateFlags);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Black);
}
If you want your window to float on top set the form's TopMost property to true. If you want your window to stick to the bottom of the Z-Order (the exact opposite of TopMost) then add the following logic to your form:
private struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;
}
private const int WM_WINDOWPOSCHANGING = 0x0046;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINDOWPOSCHANGING)
{
if (m.LParam != IntPtr.Zero)
{
WINDOWPOS posInfo = Marshal.PtrToStructure<WINDOWPOS>(m.LParam);
posInfo.hwndInsertAfter = HWND_BOTTOM;
Marshal.StructureToPtr(posInfo, m.LParam, true);
m.Result = IntPtr.Zero;
return;
}
}
base.WndProc(ref m);
}
This handles the WM_WINDOWPOSCHANGING window message, and prevents the window from moving up in the Z-Order by telling the window manager to put it at the bottom.
Is it possible to change caret size for RichTextBox?
I want to change the Width of Caret.
you may try this.
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void richTextBox1_KeyUp(object sender, KeyEventArgs e)
{
CreateCaret(richTextBox1.Handle, IntPtr.Zero, 10, richTextBox1.Font.Height);
ShowCaret(richTextBox1.Handle);
}
}
Source
I have this System.Windows.Forms.Panel that I want to enable so that if the user click and drags the mouse drags the window around to.
Can I do this? Do i have to implement multiple events?
The Solution that works best for me is using unmanaged code, which gives you smooth window movements unlike the answer posted by HatSoft.
3 small steps to drag your window on Panel movement
using System.Runtime.InteropServices;
add these six lines inside your class
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
and your MouseMove event on Panel should look like this
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
posted it a little late :) , who knows we might need it again in future.
You can achieve it by using the MouseMove Event of the panel
Example should be something like this (Sorry have not tested it)
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Location = new Point(Cursor.Position.X + e.X , Cursor.Position.Y + e.Y);
}
}
You might want to take a look at this component that I pasted here:
http://pastebin.com/5ufJmuay
It is a component that you will be able to drop on a form, and then drag the form by dragging inside it.
Currently Set For A Panel. VS C# Just Messing About Seems to work for me as I wanted
Sets application left-top corner to mouse position while left-click is pressed.
public form1()
{
InitializeComponent();
this.panel2.MouseMove += new MouseEventHandler(panel2_MouseMove);
}
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
private void panel2_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point loc1 = MousePosition;
this.Location = loc1;
}
}
Hey Hope this works for you
First you have to put a panel on your form and dock it to top
Then add these lines of codes
using System.Runtime.InteropServices;
public partial class Main_FM : Form
{
[DllImport("user32.dll", EntryPoint = "ReleaseCapture")]
private extern static void ReleaseCapture();
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private extern static void SendMessge(System.IntPtr hwnd, int wmsg, int wparam, int lparam);
}
The create the MouseDown event on the panel and add these codes:
private void Top_PNL_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
SendMessge(this.Handle, 0x112, 0xf012, 0);
}
Bravo's code works perfectly fine but I couldn't get this working until i explicitly made MouseMove event enable in panel's->properties->event section of my panel i wanted to move.