1 重写Form关闭按钮在
protected override void WndProc(ref Message m){
const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;
if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE)
{
//捕捉关闭窗体消息
Application.ExitThread();
return;
}
base.WndProc(ref m);
}
2 退出系统
Application.Exit();//好像只在主线程可以起作用,而且当有线程,或是阻塞方法的情况下,很容易失灵
this.Close();//只是关闭当前窗体。
Application.ExitThread();//退出当前线程上的消息循环,并关闭该线程上的所有窗口。 也会失灵
Environment.Exit(0); //前面三种方法都不能很好的退出程序,此方法可以完全退出程序,这个要强制得多。
Process.GetCurrentProcess().Kill();//此方法完全奏效,绝对是完全退出。
3 路径
Winform获取应用程序的当前路径的方法集合,具体如下,值得收藏
//获取当前进程的完整路径,包含文件名(进程名)。
string str = this.GetType().Assembly.Location;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取新的Process 组件并将其与当前活动的进程关联的主模块的完整路径,包含文件名(进程名)。
string str = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取和设置当前目录(即该进程从中启动的目录)的完全限定路径。
string str = System.Environment.CurrentDirectory;
result: X:\xxx\xxx (.exe文件所在的目录)
//获取当前 Thread 的当前应用程序域的基目录,它由程序集冲突解决程序用来探测程序集。
string str = System.AppDomain.CurrentDomain.BaseDirectory;
result: X:\xxx\xxx\ (.exe文件所在的目录+"\")
//获取和设置包含该应用程序的目录的名称。
string str = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
result: X:\xxx\xxx\ (.exe文件所在的目录+"\")
//获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。
string str = System.Windows.Forms.Application.StartupPath;
result: X:\xxx\xxx (.exe文件所在的目录)
//获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。
string str = System.Windows.Forms.Application.ExecutablePath;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取应用程序的当前工作目录(不可靠)。
string str = System.IO.Directory.GetCurrentDirectory();
result: X:\xxx\xxx (.exe文件所在的目录)
4 打开文件对话框
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Excel文件.xls;*.xlsx)|*.xls;*.xlsx|所有文件|*.*";//提示1|类型1|提示2|类型2…
ofd.ValidateNames = true;//验证用户输入是否是一个有效的Windows文件名。
ofd.CheckPathExists = true;//验证路径有效性。
ofd.CheckFileExists = true;//验证文件有效性。
if (ofd.ShowDialog() == DialogResult.OK)
{
string strFileName = ofd.FileName;
//其他代码
}
5 保存文件对话框
SaveFileDialog sfd = new SaveFileDialog();
//设置文件类型
sfd.Filter = "数据库备份文件(*.bak)|*.bak|数据文件(*.mdf)|*.mdf|日志文件(*.ldf)|*.ldf";
//设置默认文件类型显示顺序
sfd.FilterIndex = 1;
//保存对话框是否记忆上次打开的目录
sfd.RestoreDirectory = true;
//设置默认的文件名
sfd.DefaultFileName = "YourFileName";
//点了保存按钮进入
if (sfd.ShowDialog() == DialogResult.OK)
{
string localFilePath = sfd.FileName.ToString(); //获得文件路径
string fileNameExt = localFilePath.Substring(localFilePath.LastIndexOf("\\") + 1); //获取文件名,不带路径
}
6 无边框移动
1.定义一个位置信息Point用于存储鼠标位置
private Point mPoint;
2.给窗体等控件增加MouseDown和MouseMove事件
/// <summary>
/// 鼠标按下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mPoint = new Point(e.X, e.Y);
}
/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Location = new Point(this.Location.X + e.X - mPoint.X, this.Location.Y + e.Y - mPoint.Y);
}
}
7 拖动窗体改变大小/双击最大化(无边框窗体)
[DllImport("user32.dll")]//命名空间System.Runtime.InteropServices;
public static extern bool ReleaseCapture();
[DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_MOVE = 0xF010;
public const int HTCAPTION = 0x0002;
public const int SC_MINIMIZE = 0xF020;
public const int SC_MAXIMIZE = 0xF030;
public const int SC_RESTORE = 0xF120;
public const int SC_SIZE = 0xF000;
//改变窗体大小,SC_SIZE+下面的值
public const int LEFT = 0x0001;//光标在窗体左边缘
public const int RIGHT = 0x0002;//右边缘
public const int UP = 0x0003;//上边缘
public const int LEFTUP = 0x0004;//左上角
public const int RIGHTUP = 0x0005;//右上角
public const int BOTTOM = 0x0006;//下边缘
public const int LEFTBOTTOM = 0x0007;//左下角
public const int RIGHTBOTTOM = 0x0008;//右下角
//双击事件
private void panel2_MouseDown(object sender, MouseEventArgs e)
{
if (e.Clicks <= 1)
{
//拖动窗体
ReleaseCapture();//释放label1对鼠标的捕捉
SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
else if (e.Clicks == 2)
{
if (this.WindowState == FormWindowState.Maximized)
{
//还原窗体
ReleaseCapture();
SendMessage(this.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
}
else if (this.WindowState == FormWindowState.Normal)
{
//最大化窗体
ReleaseCapture();
SendMessage(this.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}
}
}
//以下为拖动右下角改变窗体大小的处理。
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
if (e.Clicks <= 1)
{
this.Cursor = Cursors.SizeNWSE;
ReleaseCapture();
SendMessage(this.Handle, WM_SYSCOMMAND, SC_SIZE + RIGHTBOTTOM, 0);//拖动右下角改变窗体大小
}
}
8 窗体自适应
- 自适应类
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
class AutoSizeFormClass
{
//(1).声明结构,只记录窗体和其控件的初始位置和大小。
public struct controlRect
{
public int Left;
public int Top;
public int Width;
public int Height;
}
//(2).声明 1个对象
//注意这里不能使用控件列表记录 List nCtrl;,因为控件的关联性,记录的始终是当前的大小。
// public List oldCtrl= new List();//这里将西文的大于小于号都过滤掉了,只能改为中文的,使用中要改回西文
public List<controlRect> oldCtrl = new List<controlRect>();
int ctrlNo = 0;//1;
//(3). 创建两个函数
//(3.1)记录窗体和其控件的初始位置和大小,
public void controllInitializeSize(Control mForm)
{
controlRect cR;
cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
oldCtrl.Add(cR);//第一个为"窗体本身",只加入一次即可
AddControl(mForm);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
//this.WindowState = (System.Windows.Forms.FormWindowState)(2);//记录完控件的初始位置和大小后,再最大化
//0 - Normalize , 1 - Minimize,2- Maximize
}
private void AddControl(Control ctl)
{
foreach (Control c in ctl.Controls)
{ //**放在这里,是先记录控件的子控件,后记录控件本身
//if (c.Controls.Count > 0)
// AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
controlRect objCtrl;
objCtrl.Left = c.Left; objCtrl.Top = c.Top; objCtrl.Width = c.Width; objCtrl.Height = c.Height;
oldCtrl.Add(objCtrl);
//**放在这里,是先记录控件本身,后记录控件的子控件
if (c.Controls.Count > 0)
AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
}
}
//(3.2)控件自适应大小,
public void controlAutoSize(Control mForm)
{
if (ctrlNo == 0)
{ //*如果在窗体的Form1_Load中,记录控件原始的大小和位置,正常没有问题,但要加入皮肤就会出现问题,因为有些控件如dataGridView的的子控件还没有完成,个数少
//*要在窗体的Form1_SizeChanged中,第一次改变大小时,记录控件原始的大小和位置,这里所有控件的子控件都已经形成
controlRect cR;
// cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
cR.Left = 0; cR.Top = 0; cR.Width = mForm.PreferredSize.Width; cR.Height = mForm.PreferredSize.Height;
oldCtrl.Add(cR);//第一个为"窗体本身",只加入一次即可
AddControl(mForm);//窗体内其余控件可能嵌套其它控件(比如panel),故单独抽出以便递归调用
}
float wScale = (float)mForm.Width / (float)oldCtrl[0].Width;//新旧窗体之间的比例,与最早的旧窗体
float hScale = (float)mForm.Height / (float)oldCtrl[0].Height;//.Height;
ctrlNo = 1;//进入=1,第0个为窗体本身,窗体内的控件,从序号1开始
AutoScaleControl(mForm, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
}
private void AutoScaleControl(Control ctl, float wScale, float hScale)
{
int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;
//int ctrlNo = 1;//第1个是窗体自身的 Left,Top,Width,Height,所以窗体控件从ctrlNo=1开始
foreach (Control c in ctl.Controls)
{ //**放在这里,是先缩放控件的子控件,后缩放控件本身
//if (c.Controls.Count > 0)
// AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
ctrLeft0 = oldCtrl[ctrlNo].Left;
ctrTop0 = oldCtrl[ctrlNo].Top;
ctrWidth0 = oldCtrl[ctrlNo].Width;
ctrHeight0 = oldCtrl[ctrlNo].Height;
//c.Left = (int)((ctrLeft0 - wLeft0) * wScale) + wLeft1;//新旧控件之间的线性比例
//c.Top = (int)((ctrTop0 - wTop0) * h) + wTop1;
c.Left = (int)((ctrLeft0) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体,所以不能加 + wLeft1
c.Top = (int)((ctrTop0) * hScale);//
c.Width = (int)(ctrWidth0 * wScale);//只与最初的大小相关,所以不能与现在的宽度相乘 (int)(c.Width * w);
c.Height = (int)(ctrHeight0 * hScale);//
ctrlNo++;//累加序号
//**放在这里,是先缩放控件本身,后缩放控件的子控件
if (c.Controls.Count > 0)
AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
}
}
}
}
- 自适应
1.声明自适应类实例
AutoSizeFormClass asc = new AutoSizeFormClass();
2,在初始化的时候
asc.controllInitializeSize(this);
3,在SizeChanged事件中
asc.controlAutoSize(this);
9 窗体快捷键的使用
1.响应 Form窗体的 KeyDown 事件
需要设置Form窗体的 KeyPreview 属性为 true (默认false)
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.F1:
//...
break;
case Keys.Escape:
//...
break;
case Keys.O:
if (e.Control)
{
// Ctrl + O
}
break;
case Keys.Oemcomma: //逗号键
// ...
break;
case Keys.OemPeriod: //句号键
// ...
break;
case Keys.Oem1: // 分号
// ...
break;
case Keys.Oem7: // 引号
// ...
break;
case Keys.Up: // 无效
// ...
return true;
case Keys.Down: //无效
// ...
return true;
}
2.重载 ProcessCmdKey 方法
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Up:
// ...
return true;
case Keys.Down:
// ...
return true;
}
return false;
}
10.文件相关操作
- 创建文件夹
if (!Directory.Exists("文件夹名称"))
{
Directory.CreateDirectory("文件夹名称");
}
11.注册全局热键
internal class HotKey
{
//如果函数执行成功,返回值不为0。
//如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(
IntPtr hWnd, //要定义热键的窗口的句柄
int id, //定义热键ID(不能与其它ID重复)
KeyModifiers fsModifiers, //标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效
Keys vk //定义热键的内容
);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnregisterHotKey(
IntPtr hWnd, //要取消热键的窗口的句柄
int id //要取消热键的ID
);
//定义了辅助键的名称(将数字转变为字符以便于记忆,也可去除此枚举而直接使用数值)
[Flags()]
public enum KeyModifiers
{
None = 0,
Alt = 1,
Ctrl = 2,
Shift = 4,
WindowsKey = 8
}
}
注册热键
//注册热键Alt+M,Id号为102。HotKey.KeyModifiers.Alt也可以直接使用数字1来表示。
HotKey.RegisterHotKey(Handle, 102, HotKey.KeyModifiers.Alt, Keys.M);
释放热键
//注销Id号为102的热键设定
HotKey.UnregisterHotKey(Handle, 102);
捕获热键
protected override void WndProc(ref Message m)
{
const int WM_HOTKEY = 0x0312;
//按快捷键
switch (m.Msg)
{
case WM_HOTKEY:
switch (m.WParam.ToInt32())
{
case 102: //按下的是Alt+M
//执行相关操作
break;
}
break;
}
base.WndProc(ref m);
}