2,建立截圖主窗口
核心類MyRectangle已經完成,剩下的工作就是使用改類實現預想的截圖功能。
用VS2005 新建Project,命名為ScreenCutter。將主窗口命名為MainForm,新建一個窗口命名為ScreenBody,將其 ShowInTaskbar屬性設置為False,TopMost屬性設置為True,FormBorderStyle屬性設置為None,在 ScreenBody上添加一個panel控件panel1,設置BackColor屬性為藍色,在panel1上添加相應個數的label,如 labelLocation、labelWidth、labelHeight等,用於指示當前選區位置和大小,panel1最終樣式為:
修改ScreenBody的引用命名空間為:
using System;
using System.Drawing;
using System.Windows.Forms;
在ScreenBody類中添加如下私有成員:
private Graphics MainPainter; //the main painter
private bool isDowned; //check whether the mouse is down
private bool RectReady; //check whether the rectangle is finished
private Image baseImage; //the back ground of the screen
private Point moveModeDownPoint; //the mouse location when you move the rectangle
private MyRectangle myRectangle; //the rectangle
private bool moveMode; //check whether the rectangle is on move mode or not
private bool changeSizeMode; //check whether the rectangle is on change size mode or not
修改ScreenBody構造函數:
public ScreenBody()
{
InitializeComponent();
panel1.Location = new Point(this.Left, this.Top);
myRectangle = new MyRectangle();
moveModeDownPoint = new Point();
this.Cursor = myRectangle.MyCursor;
}
添加ScreenBody窗口的DoubleClick、MouseDown、MouseUp、MouseMove及Load事件代碼:
private void ScreenBody_DoubleClick(object sender, EventArgs e)
{
if (((MouseEventArgs)e).Button == MouseButtons.Left && myRectangle.Contains(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y))
{
panel1.Visible = false;
MainPainter.DrawImage(baseImage, 0, 0);
Image memory = new Bitmap(myRectangle.Width, myRectangle.Height);
Graphics g = Graphics.FromImage(memory);
g.CopyFromScreen(myRectangle.X, myRectangle.Y, 0, 0, myRectangle.Size);
Clipboard.SetImage(memory);
this.Close();
}
}
private void ScreenBody_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDowned = true;
if (!RectReady)
{
myRectangle.DownPointX = e.X;
myRectangle.DownPointY = e.Y;
myRectangle.X = e.X;
myRectangle.Y = e.Y;
}
if (RectReady == true)
{
moveModeDownPoint = new Point(e.X, e.Y);
}
}
if (e.Button == MouseButtons.Right)
{
if (!RectReady)
{
this.Close();
return;
}
MainPainter.DrawImage(baseImage, 0, 0);
myRectangle.Initialize(0, 0, 0, 0);
myRectangle.setAllModeFalse();
this.Cursor = myRectangle.MyCursor;
RectReady = false;
}
}
private void ScreenBody_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDowned = false;
RectReady = true;
}
}
private void ScreenBody_MouseMove(object sender, MouseEventArgs e)
{
labelWidth.Text = myRectangle.Width.ToString();
labelHeight.Text = myRectangle.Height.ToString();
labelLocation.Text = "X "+myRectangle.X.ToString() + ", Y " + myRectangle.Y.ToString();
if (!RectReady)
{
if (isDowned)
{
myRectangle.Draw(e, this.BackColor);
}
}
else
{
myRectangle.CheckMouseLocation(e);
this.Cursor = myRectangle.MyCursor;
this.changeSizeMode = myRectangle.ChangeSizeMode;
this.moveMode = myRectangle.MoveMode&&myRectangle.Contains(moveModeDownPoint.X,moveModeDownPoint.Y);
if (changeSizeMode)
{
this.moveMode = false;
myRectangle.Draw(BackColor);
myRectangle.ChangeSize(e);
myRectangle.Draw(BackColor);
}
if (moveMode)
{
this.changeSizeMode = false;
myRectangle.Draw(BackColor);
myRectangle.X = myRectangle.X + e.X - moveModeDownPoint.X;
myRectangle.Y = myRectangle.Y + e.Y - moveModeDownPoint.Y;
moveModeDownPoint.X = e.X;
moveModeDownPoint.Y = e.Y;
myRectangle.Draw(this.BackColor);
}
}
}
private void ScreenBody_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
MainPainter = this.CreateGraphics();
isDowned = false;
baseImage = this.BackgroundImage;
panel1.Visible = true;
RectReady = false;
changeSizeMode = false;
moveMode = false;
}
為了不至截到panel1,添加panel1的MouseEnter事件如下:
private void panel1_MouseEnter(object sender, EventArgs e)
至此,ScreenBody窗口完成,QQ截圖功能可以通過熱鍵觸發,下面為本程序添加熱鍵
{
if (panel1.Location==new Point(this.Left,this.Top))
{
panel1.Location = new Point(this.Right-panel1.Width, this.Top);
}
else
{
panel1.Location = new Point(this.Left,this.Top);
}
}
3,創建熱鍵類
網上有許多這方面的資料,本程序中這段代碼取自互聯網,如有版權問題請給我留言,我會盡快刪除。
添加類HotKey
HotKey.cs文件內容如下
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ScreenCutter
{
class HotKey
{
//如果函數執行成功,返回值不為0。
//如果函數執行失敗,返回值為0。要得到擴展錯誤信息,調用GetLastError。
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(
IntPtr hWnd, //要定義熱鍵的窗口的句柄
int id, //定義熱鍵ID(不能與其它ID重復)
uint 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
}
}
}
4,使用熱鍵及托盤區圖標
為了使程序更方便使用,程序啟動的時候最下化到托盤區,在按下程序熱鍵時會啟動截圖功能。這些功能在程序的主窗口MainForm類中實現。
為了在托盤區顯示圖標,為MainForm添加一個NotifyIcon控件,為其指定一Icon圖標,並設定visable屬性為true
為了實現可以更改熱鍵,首先在項目屬性的Setting中添加如下圖成員:
MainForm.cs文件代碼如下:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using ScreenCutter.Properties;
namespace ScreenCutter
{
public enum KeyModifiers //組合鍵枚舉
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8
}
public partial class MainForm : Form
{
private ContextMenu contextMenu1;
private MenuItem menuItem1;
private MenuItem menuItem2;
private ScreenBody body;
public MainForm()
{
InitializeComponent();
this.components = new Container();
this.contextMenu1 = new ContextMenu();
this.menuItem2 = new MenuItem();
this.menuItem1 = new MenuItem();
this.contextMenu1.MenuItems.AddRange(
new MenuItem[] { this.menuItem1,this.menuItem2 });
this.menuItem1.Index = 1;
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new EventHandler(this.menuItem1_Click);
this.menuItem2.Index = 0;
this.menuItem2.Text = "S&et HotKey";
this.menuItem2.Click += new EventHandler(this.menuItem2_Click);
notifyIcon1.ContextMenu = this.contextMenu1;
notifyIcon1.Text = "Screen Cutter";
notifyIcon1.Visible = true;
body = null;
}
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.Hide();
this.notifyIcon1.Visible = true;
}
}
private void CutScreen()
{
Image img = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(img);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
body = new ScreenBody();
body.BackgroundImage = img;
body.Show();
}
private void ProcessHotkey(Message m) //按下設定的鍵時調用該函數
{
IntPtr id = m.WParam; //IntPtr用於表示指針或句柄的平台特定類型
string sid = id.ToString();
switch (sid)
{
case "100":
CutScreen();
break;
default:
break;
}
}
private void MainForm_Load(object sender, EventArgs e)
{
uint ctrHotKey = (uint)KeyModifiers.Control;
if (Settings.Default.isAltHotKey)
{
ctrHotKey =(uint)(KeyModifiers.Alt | KeyModifiers.Control);
}
HotKey.RegisterHotKey(Handle, 100, ctrHotKey, Settings.Default.HotKey); //這時熱鍵為Alt+CTRL+A
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
HotKey.UnregisterHotKey(Handle, 100); //卸載第1個快捷鍵
}
//重寫WndProc()方法,通過監視系統消息,來調用過程
protected override void WndProc(ref Message m)//監視Windows消息
{
const int WM_HOTKEY = 0x0312; //如果m.Msg的值為0x0312那麼表示用戶按下了熱鍵
switch (m.Msg)
{
case WM_HOTKEY:
ProcessHotkey(m); //按下熱鍵時調用ProcessHotkey()函數
break;
}
base.WndProc(ref m); //將系統消息傳遞自父類的WndProc
}
private void menuItem1_Click(object Sender, EventArgs e)
{
HotKey.UnregisterHotKey(Handle, 100); //卸載第1個快捷鍵
this.notifyIcon1.Visible = false;
this.Close();
}
private void menuItem2_Click(object Sender, EventArgs e)
{
SetHotKey setHotKey = new SetHotKey();
setHotKey.ShowDialog();
}
}
}
5,添加設定熱鍵功能:
新建窗口,命名為SetHotkey,該窗口樣式及主要控件命名如下圖所示
設定窗口主體FormBorderStyle屬性值為FixedToolWindow,Text屬性為SetHotKey,MaximizeBox和MinimizeBox屬性為false。
添加checkBox1的(ApplicationSettings)-(PropertyBinding)-Checked為isCtrlHotKey,CheckState為Checked,Enable屬性為false,Text屬性為Ctrl
添加checkBox2的(ApplicationSettings)-(PropertyBinding)-Checked為isAltHotKey,CheckState為Checked,Enable屬性為true,Text屬性為Alt
comboBox1的Items值為
A
Z
X
為按鈕btnDefault添加click事件
private void btnDefault_Click(object sender, EventArgs e)
{
Settings.Default.HotKey = Keys.A;
Settings.Default.Save();
this.Close();
}
為按鈕btnOk添加click事件
private void btnOK_Click(object sender, EventArgs e)
{
switch (comboBox1.SelectedIndex)
{
case 0:
Settings.Default.HotKey = Keys.A;
break;
case 1:
Settings.Default.HotKey = Keys.Z;
break;
case 2:
Settings.Default.HotKey = Keys.X;
break;
default:
break;
}
Settings.Default.Save();
this.Close();
}
為按鈕btnCancel添加click事件
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
為SetHotkey窗口添加load事件
private void SetHotKey_Load(object sender, EventArgs e)
{
comboBox1.Text = Settings.Default.HotKey.ToString();
}
6,防止程序多次運行
同樣,網上有許多這方面的資料,本部分代碼基本來自互聯網,如有版權問題請給我留言,我將立即刪除
為防止程序多次運行,修改Program.cs文件內容如下:
using System;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ScreenCutter
{
static class Program
{
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int WS_SHOWNORMAL = 1;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Process instance = RunningInstance();
if (instance == null)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
else
{
HandleRunningInstance(instance);
}
}
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
//Loop through the running processes in with the same name
foreach (Process process in processes)
{
//Ignore the current process
if (process.Id != current.Id)
{
//Make sure that the process is running from the exe file.
if (Assembly.GetExecutingAssembly().Location.Replace("/", """) ==
current.MainModule.FileName)
{
//Return the other process instance.
return process;
}
}
}
//No other instance was found, return null.
return null;
}
public static void HandleRunningInstance(Process instance)
{
//Make sure the window is not minimized or maximized
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
//Set the real intance to foreground window
SetForegroundWindow(instance.MainWindowHandle);
}
}
}
至此,該截圖程序基本完成,實現了類似QQ截圖的功能。(默認熱鍵為Ctrl+Alt+A)
注意:程序中用到了一些圖片,Icon文件和cur文件,請復制系統目錄(C:"WINDOWS"Cursors)下的hcross.cur、 move_m.cur、size1_m.cur、size2_m.cur、size3_m.cur、size4_m.cur文件到.." ScreenCutter"ScreenCutter"Cursors目錄下,在.."ScreenCutter"ScreenCutter"Icons 目錄下添加相應圖標,在.."ScreenCutter"ScreenCutter"Images目錄下添加相應圖片。如路徑不同,請在代碼中自行更改。