程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#截屏問題及FORM間傳值

C#截屏問題及FORM間傳值

編輯:關於C語言

這個文章還是有一些可以借鑒的地方

-------------------------------------------------------------------------

最近在程序中做一動態截屏功能的小程序;
在完成過程中,遇到了許多問題,
現將其中重要的過程記錄如下:

1,要實現動態截屏的原理
剛開始並不知,以為可以得到桌面的句柄直接調用左右鼠標點擊得到.
哪有那麼如想像中的美事
看了許多別人的程序.,特別是QQ的動態截屏功能,
他們在截屏的時候桌面都是靜態的.
原來此時的背景是一個最大化的FORM,把其標題欄,按鈕等都取消了.
像做桌面保護程序那樣的風格.
在這個FORM中得到它的兩個坐標是很容易的事;
也就是說:先截全屏到一個FORM中顯示
在這個FORM中截你所想要的一部分並在第一個FORM中顯示所截部分;
這樣就出現了要在兩個之間傳值;
最初為了避免傳值(呵呵,當時不會傳值),我先把所截部分保存一張圖片,
在第一個FORM中檢測是晉中有圖片存在,有則顯示出來
功能是實現了,但有了新問題?只能截一次!
原因是,第二要截屏則要刪除保存的圖片,為第二次截屏准備,但異常顯示
圖片資源被調用,無法刪除.也是為什麼第二次截圖不能保存的原因.
mypicturebox.Image=null;這樣的操作也不行的.(有誰知道的怎麼樣消除調用資源的告訴我一下)
看來這個笨方法不工作了.
在網上找到兩種FORM間傳值的方法.
一]新建類過渡傳值.
二]傳遞第一個FORM的地址.

2具體實現
清楚了實現原理,就不難實現其功能了~*~
我先用第二個方法實現!
(1)先在第一個FORM中用一按鈕啟動截屏程序
            this.Hide();//隱藏主對話框.
            Thread.Sleep(150);//停止一下
           
            AllBitmap = Getallscreen();//調用動態截屏
           
            CaptureScreen CaptureS = new CaptureScreen(AllBitmap,this);// 傳遞全屏BITMAP和地址
            CaptureS.ShowDialog();
            this.Show();
其中調用了截全屏的函數Getallscreen()
        private Bitmap Getallscreen()
        {
            //建立屏幕Graphics
            Graphics grpScreen = Graphics.FromHwnd(IntPtr.Zero);
            //根據屏幕大小建立位圖
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, grpScreen);
            //建立位圖相關Graphics
            Graphics grpBitmap = Graphics.FromImage(bitmap);
            //建立屏幕上下文
            IntPtr hdcScreen = grpScreen.GetHdc();
            //建立位圖上下文
            IntPtr hdcBitmap = grpBitmap.GetHdc();
            //將屏幕捕獲保存在圖位中
            BitBlt(hdcBitmap, 0, 0, bitmap.Width, bitmap.Height, hdcScreen, 0, 0, 0x00CC0020);
            //關閉位圖句柄
            grpBitmap.ReleaseHdc(hdcBitmap);
            //關閉屏幕句柄
            grpScreen.ReleaseHdc(hdcScreen);
            //釋放位圖對像
            grpBitmap.Dispose();
            //釋放屏幕對像
            grpScreen.Dispose();
            //返回捕獲位圖
            return bitmap;
        }
在截全屏函數中用到了一個API函數.
則進行如下操作
using System.Runtime.InteropServices;

         [DllImportAttribute("gdi32.dll")]
         public static extern bool BitBlt(
         IntPtr hdcDest,    //目標設備的句柄
         int nXDest,        // 目標對象的左上角的X坐標
         int nYDest,        // 目標對象的左上角的X坐標
         int nWidth,        // 目標對象的矩形的寬度
         int nHeight,       // 目標對象的矩形的長度
         IntPtr hdcSrc,     // 源設備的句柄
         int nXSrc,         // 源對象的左上角的X坐標
         int nYSrc,         // 源對象的左上角的X坐標
         System.Int32 dwRop // 光柵的操作值
         );

(2)到了最重要的地方,要想把第二個FORM中的數據傳遞過來就得在第一個FORM中的相應的顯示處理程序
我用下列函數
        public void SetMyImage(Bitmap mybitmap)//注意是public類型
        {
            this.mypictureBox.Image = mybitmap;//顯示
            myimage = mybitmap;                //用於重畫
            PreBtn.Enabled = true;             //用於保存圖片
        }
第一個FORM中用到一些變量
        public Image myimage=null;
        public Bitmap AllBitmap;
(3)在第一個FORM中調用了第二個FORM,其中構造函數傳遞了全屏的BITMAP,
所以第二個FORM中加上一個構造函數:
        public CaptureScreen(Bitmap bit,Form parentForm)
        {
            InitializeComponent();
            this.allbitmap = bit;
            this._parentForm = parentForm;
        }
傳遞了圖片信息在FORM_LOAD中加載顯示
        private void CaptureScreen_Load(object sender, EventArgs e)
        {
            this.TopMost = true;//讓其最前顯示
            this.allpicture.Image = allbitmap;
      gg = this.allpicture.CreateGraphics();//創建一個Graphics為後面建立提示信息准備
        }
(4)要截部分屏幕,當然要確定一下范圍.用左右鼠標鍵來確定.
用到下面三個函數
        private void allpicture_MouseDown(object sender, MouseEventArgs e)
        {
            if (isdoubleclick == true)
            {
                point1.X = e.X;
                point1.Y = e.Y;
                isdraw = true;
                gg.DrawString("按Esc鍵退出截圖程序程序", new Font("Tahoma", 13, FontStyle.Underline),
                                  new SolidBrush(Color.Blue), e.X,e.Y);
            }
        }

        private void allpicture_MouseMove(object sender, MouseEventArgs e)
        {
            this.allpicture.Refresh();
            if (isdraw == true)
            {
                int hh,ww;         //計算截圖位置和開始點位置
                Point startpoint=new Point(0,0);
                if (e.X < point1.X && e.Y < point1.Y)
                {
                    startpoint.X = e.X;
                    startpoint.Y = e.Y;
                    hh = (int)(point1.X - e.X);
                    ww = (int)(point1.Y - e.Y);
                }
                if (e.X > point1.X && e.Y < point1.Y)
                {
                    startpoint.X = point1.X;
                    startpoint.Y = e.Y;
                    hh = (int)(e.X - point1.X);
                    ww = (int)(point1.Y - e.Y);
                }
                if (e.X < point1.X && e.Y > point1.Y)
                {
                    startpoint.X = e.X;
                    startpoint.Y = point1.Y;
                    hh = (int)(point1.X - e.X);
                    ww = (int)(e.Y - point1.Y);
                }
                else
                {
                    startpoint = point1;
                    hh = (int)(e.X - point1.X);
                    ww = (int)(e.Y - point1.Y);
                }
                gg.DrawRectangle(new Pen(Color.FromArgb(9, 247, 32)), startpoint.X,
                                            startpoint.Y, hh, ww);//截圖范圍示意圖
               
                int hhh, www;//顯示提示信息位置
                if ((int)(e.X - point1.X) > 0)
                    hhh = (int)(e.X - point1.X);
                else
                    hhh = (int)(point1.X - e.X);
                if ((int)(e.Y - point1.Y) > 0)
                    www = (int)(e.Y - point1.Y);
                else
                    www = (int)(point1.Y - e.Y);
                string mystr = "截取范圍:\n    寬:" + hhh + "\n    高:" + www;
                gg.DrawString(mystr, new Font("Tahoma", 10, FontStyle.Underline),
                                     new SolidBrush(Color.Red), e.X,e.Y);//h1, w1);
                gg.DrawString("按Esc鍵退出截圖程序程序", new Font("Tahoma", 13, FontStyle.Underline),
                                                         new SolidBrush(Color.Blue), point1.X, point1.Y-22);         
            }
        }

        private void allpicture_MouseUp(object sender, MouseEventArgs e)
        {
            if (isdoubleclick == true)
            {
                point2.X = e.X;
                point2.Y = e.Y;
                isdoubleclick = false;
            }
        }

第二個FORM中用到的變量:
        private Point  point1 = new Point();   //開始位置
        private Point  point2 = new Point();   //最後位置
        private bool   isdraw = false;         //是否開始畫直線
        private bool   isdoubleclick = true;    //是否可以雙擊
        public  Bitmap newbitmap;               //截的部分圖像
        private Bitmap allbitmap;              //全屏圖像
        private Form   _parentForm = null;
        private Graphics gg;

        public static int h1;//顯示提示位置
        public static int w1;
截屏用到的API函數:
        #region 導入函數
       
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateDC(string lpszDriver, string lpszDrivse, string lpszOutput, Int32 lpInitData);

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, Int32 nIndex);

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

        [DllImport("gdi32.dll")]
        private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        [DllImport("gdi32.dll")]
        private static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest,
                 int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, UInt32 dwRop);

        [DllImport("gdi32.dll")]
        private static extern int DeleteDC(IntPtr hdc);

        #endregion
(5)現在可以調用截取部分屏幕的函數  
        private void allpicture_DoubleClick(object sender, EventArgs e)
        {
            this.allpicture.Refresh();//先擦出提示信息,食品店提示信息什麼地方都可以顯示;
            newbitmap = GetPartScreen(point1, point2);
            ((MyTool)_parentForm).SetMyImage(newbitmap);//通過傳地址調用第一個FORM的圖片顯示函數
            this.Close();//該窗口關閉 // Application.Exit();應用程序退出
        }
下面是GetPartScreen函數的具體實現 private static Bitmap GetPartScreen(Point p, Point pp)
        {
            IntPtr hscrdc, hmemdc;
            IntPtr hbitmap, holdbitmap;
            int nx, ny, nxx, nyy;
            nx = nxx = ny = nyy = 0;
            int nwidth, nheight;
            int xscrn, yscrn;

            hscrdc = CreateDC("DISPLAY", null, null, 0);//(IntPtr)null);// 0);//創建DC句柄
            hmemdc = CreateCompatibleDC(hscrdc);//創建一個內存DC
            xscrn = GetDeviceCaps(hscrdc, 8);//*HORZRES*/);//獲取屏幕寬度//wingdi.h
            yscrn = GetDeviceCaps(hscrdc, 10);//*VERTRES*/);//獲取屏幕高度//wingdi.h

            nx = p.X;
            ny = p.Y;
            nxx = pp.X;
            nyy = pp.Y;    

            if (nx < 0)      //檢查數值合法性
                nx = 0;
            if (ny < 0)
                ny = 0;
            if (nxx > xscrn)
                nxx = xscrn;
            if (nyy > yscrn)
                nyy = yscrn;

            if (nxx - nx > 0)//截取范圍的寬度
            {
                nwidth = nxx - nx;
            }
            else
            {
                nwidth = nx - nxx;
            }
            if (nyy - ny > 0)//截取范圍的高度
            {
                nheight = nyy - ny;
            }
            else
            {
                nheight = ny - nyy;
            }

            if (nxx < nx && nyy < ny)
            {
                h1 = nx;
                w1 = ny;

                int k;
                k = nxx;
                nxx = nx;
                nx = k;

                k = nyy;
                nyy = ny;
                ny = k;
            }

            if (nxx < nx && nyy > ny)
            {
                h1 = nx;
                w1 = nyy;

                nx = nxx;
            }
            if (nx < nxx && ny > nyy)
            {
                h1=nx;
                w1 = nyy;

                ny = nyy;
            }

            hbitmap = CreateCompatibleBitmap(hscrdc, nwidth, nheight);//從內存DC復制到hbitmap句柄
            holdbitmap = SelectObject(hmemdc, hbitmap);
            BitBlt(hmemdc, 0, 0, nwidth, nheight, hscrdc, nx, ny, (UInt32)0xcc0020);
            hbitmap = SelectObject(hmemdc, holdbitmap);
            DeleteDC(hscrdc);//刪除用過的對象
            DeleteDC(hmemdc);//刪除用過的對象
            return Bitmap.FromHbitmap(hbitmap);//用Bitmap.FromHbitmap從hbitmap返回Bitmap
        }
(6)我們傳遞了地址.怎麼實現的傳地址呢.委托!(具體委托知識請查教程委托部分!)
在第一個FORM中申請委托:
public delegate void mydelegate(Bitmap mybitmap);//類外

全部功能實現,可你會發現傳遞的圖片沒有顯示在第一個FORM中的圖片控件中
為什麼呢,我可是花了七八個小時才知,因為那時我暈了
原來我們在截圖時隱藏了FORM1,又接著顯示,再關閉了FORM2,使顯示的圖片沒有更新,
所以現在你知道該怎麼做了吧.
重載OnPaint函數:
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (myimage != null)
                this.mypictureBox.Image = myimage;
            else
            {
                this.mypictureBox.Image = null;
                this.mypictureBox.Refresh();
            }
        }
(7)大功告成,不知你是否!
(8)現在簡單用過渡類實現一下傳值:
我只給出不相同的部分,有不明白的可以聯系我共同討論;
第一個FORM截屏時
            PassBitmap newpassbitmap = new PassBitmap();//注意這.
            newpassbitmap.PassBitmapEvent += new SendBitmap(this.SetMyImage);
           
            this.Hide();
            Thread.Sleep(150);
           
            AllBitmap = Getallscreen();//調用動態截屏
           
            CaptureScreen CaptureS = new CaptureScreen(AllBitmap, newpassbitmap);
            CaptureS.ShowDialog();
            this.Show();
第二個FORM的構造函數
        public CaptureScreen(Bitmap bit,PassBitmap bitmapss)
        {
            InitializeComponent();
            this.allbitmap = bit;
            this.bitmapss=bitmapss;
        }
雙擊截屏時:
            newbitmap = GetPartScreen(point1, point2);
            bitmapss.PassGetBitmap(newbitmap);

其中過渡類:
using System;
using System.Drawing;

namespace BoberTool
{
    public delegate void SendBitmap(Bitmap mybitmap);

    public class PassBitmap
    {
        public Bitmap mybitmaps;
        public event SendBitmap PassBitmapEvent;

        public void PassGetBitmap(Bitmap bitmaps)
        {
            if (bitmaps != null)
                PassBitmapEvent(bitmaps);
        }
    }
}

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