程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 用C#實現截圖功能(3)(類似QQ截圖)

用C#實現截圖功能(3)(類似QQ截圖)

編輯:關於C#

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)
    {
      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);
      }
    }
至此,ScreenBody窗口完成,QQ截圖功能可以通過熱鍵觸發,下面為本程序添加熱鍵

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目錄下添加相應圖片。如路徑不同,請在代碼中自行更改。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved