c# winform程式設計轉例

wisdomone1發表於2012-07-13
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace openfiledialog
{
    class keytest:Form
    {
        public static void Main()
        {
            Application.Run(new keytest());
        }

        //列舉事件型別 不事的事件,如無,按下鍵,放開鍵,
        enum eventtype
        {
            none,
            keydown,
            keyup,
            keypress
        }

        //struct結構 輕型別的類,它是值型別 儲存事件型別名稱比如keypress及事件的引數,如:keyup(object sender,keyeventargs args)
        struct keyevent
        {
            public eventtype evttype;
            public EventArgs evtargs;
        }
        //const常整型常量
        const int inumlines = 25;
        int inumvalid = 0;
        int iinsertindex = 0;

        //STRUCT結構型別的陣列,而非類,如下陣列儲存?內容
        keyevent[] akeyevt=new keyevent[inumlines];//陣列宣告,引用上述的CONST常整常量

        //文字的位置,具體起何功能,再分析 如下的xevent為首行各個列頭顯示的座標
        int xevent, xchar, xcode, xmods, xdata, xshift, xctrl, xalt, xright;

        //建構函式 初始化窗體的基本元素資訊
        public keytest()
        {
            Text = "key test";
            BackColor = SystemColors.Window;
            ForeColor = SystemColors.WindowText;
            
            //初始化上述以X打頭的相關欄位,讓多個東東有關聯性,即是多個東東以其中某個東東為基礎,這樣就OK了
            xevent = 0;
            xchar = xevent + 5 * Font.Height;//在xevent及font字型行高的基礎,得到xchar
            xcode = xchar + 5 * Font.Height;
            xmods = xcode + 8 * Font.Height;
            xdata = xmods + 8 * Font.Height;
            xshift = xdata + 8 * Font.Height;
            xctrl = xshift + 5 * Font.Height;
            xalt = xctrl + 5 * Font.Height;
            xright = xalt + 5 * Font.Height;

            //clientsize為窗體工作區的大小 窗體工作區的大小取決於xright及字型行高和常量inumlines的關係
            ClientSize = new Size(xright,Font.Height*(inumlines+1));
            FormBorderStyle. = FormBorderStyle.Fixed3D;//formborderstyle窗體邊框樣式
            MaximizeBox = false;//maximizebox標題欄是否顯示最大化按鈕
        }

        //onkeydown為control事件 輸入protected override void後面的事件會自動提示彈出
        protected override void OnKeyDown(KeyEventArgs e)
        {
            akeyevt[iinsertindex].evttype = eventtype.keydown;//引用iinsertindex欄位
            akeyevt[iinsertindex].evtargs = e;
            onkey();//onkeydown按鍵事件會呼叫此自定義方法
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            akeyevt[iinsertindex].evttype = eventtype.keyup;
            akeyevt[iinsertindex].evtargs = e;
            onkey();
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            akeyevt[iinsertindex].evttype = eventtype.keypress;
            akeyevt[iinsertindex].evtargs = e;
            onkey();
        }

        void onkey()
        {
            if(inumvalid
            {
                //呼叫creategraphics與dispose必須成對出現
                Graphics gp = CreateGraphics();
                displaykeyinfo(gp,iinsertindex,iinsertindex);
                gp.Dispose();
            }
            else
            {
                scrolllines();
            }
            iinsertindex = (iinsertindex + 1) % inumlines;
            inumvalid = Math.Min(inumvalid+1,inumlines);//math.min返回兩個decimal較小的一個
        }

        //如下方法為滾屏方法,其實就是採取重繪,如何重繪呢,呼叫invalidate,然後會自動呼叫onpaint事件(即重繪方法),封裝
        //重繪區域大小及位置定位,
        protected virtual void scrolllines()
        {
            //rect為窗體工作區大小,不含首行,即首行列頭不重繪,第二行左上角座標(x,y)=(0,font.height)到右下角座標(x,y)=(clientsize.width,client.height-font.height),為何要-減,要少繪一個行高,故減 
            Rectangle rect = new Rectangle(0,Font.Height,ClientSize.Width,ClientSize.Height-Font.Height);
            Invalidate(rect);//invalidate方法會呼叫onpaint重繪控制元件
        }

        //scrolllines會呼叫此方法事件
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics gp = e.Graphics;

            //列印首列不同列頭文字,每個列頭文字的座標由(xevent,0)控制
            boldunderline(gp,"event",xevent,0);//注意如下行皆是同行不同列,這樣就把xevent,xchar等列印出來,以不同列同行方式
            boldunderline(gp, "keychar", xchar, 0);
            boldunderline(gp, "keycode", xcode, 0);
            boldunderline(gp, "modifiers", xmods, 0);
            boldunderline(gp, "keydata", xdata, 0);
            boldunderline(gp, "shift", xshift, 0);

            //總結:1,如下2行程式碼為何不顯示,方法1:註解掉  方法2:變換字串內容  方法3:
            boldunderline(gp, "control", xshift+50, 0);////////////////////////為何這個沒列印出來呢,??????? 原始碼經過分析,是此control文字的輸出座標在初始化(建構函式中)超出窗體工作區大小,故看不到了,修正即可
            boldunderline(gp, "alt", xalt, 0);

            //
            if (inumvalid < inumlines)
            {
                for (int i = 0; i < inumvalid; i++) //for迴圈如果內含一條語句,此語句不用{}括起來,類似於if後跟單語句一樣
                    displaykeyinfo(gp, i, i);//注意此displaykeyinfo方法屬於上述語句if及for,此方法會在內部更新inumvalid
            }
            else
            {
                for (int i = 0; i < inumlines; i++)
                    displaykeyinfo(gp,i,(iinsertindex+i)%inumlines);
            }
        }

        void boldunderline(Graphics gpis, string str, int x, int y)
        {
            //畫粗體文字
            Brush brush = new SolidBrush(ForeColor); //solidbrush單色畫筆,填充圖形形狀
            gpis.DrawString(str,Font,brush,x,y);//用何字型及畫筆(工具)在何座標畫出字串str
            gpis.DrawString(str,Font,brush,x+1,y);//再次繪製字串STR,但不同原來的座標,而是偏移一個畫素位置,這樣不加加粗文字了嗎
            
            //下劃線文字

            // 返回結果:
           // 此方法返回 System.Drawing.SizeF 結構,該結構表示 text 引數指定的、使用 font 引數繪製的字串的大小,單位由 System.Drawing.Graphics.PageUnit
           //     屬性指定。
            SizeF sizef=gpis.MeasureString(str,Font); //知形寬高度,在此對應字串的矩形大小,sizef

            //如何在每列文字下面加下劃線 ,注意每列文字x,y,那麼下劃線的座標 位置要考慮到字串的大小,字串的大小對應sizef
            gpis.DrawLine(new Pen(ForeColor),x,y+sizef.Height,x+sizef.Width,y+sizef.Height); //drawline畫一個連線兩個點的線,用工具pen

        }

        //顯示按鍵相關資訊的方法
        void displaykeyinfo(Graphics gp, int y, int i)
        {
            Brush br = new SolidBrush(ForeColor);//在此forecolor對應窗體的前景色
            y = (1 + y) * Font.Height;//font為控制元件顯示文字的字型
            gp.DrawString(akeyevt[i].evttype.ToString(), Font, br, xevent, y);//xevent,y為字串繪製位置座標,字串為akyeevt[i].evttype,引用列舉及結構型別STRRUCT
            if (akeyevt[i].evttype == eventtype.keypress)
            {
                //如果事件型別為keypress,事件型別為屬於什麼事件
                KeyPressEventArgs kpea = (KeyPressEventArgs)akeyevt[i].evtargs;//大轉化為小,也叫拆箱操作
                string str = string.Format("\x202D{0} (0X{1:X4}", kpea.KeyChar, (int)kpea.KeyChar);//用到了string.format對指定字元進行格式然後輸出
                gp.DrawString(str, Font, br, xchar, y);//基於上行str
            }
            else
            {
                KeyEventArgs kea = (KeyEventArgs)akeyevt[i].evtargs;
                string str = string.Format("",kea.KeyCode,(int)kea.KeyCode);//keyeventargs事件引數類有許多屬性如keycode,keydata等
                gp.DrawString(str, Font, br, xcode, y);//如下皆為同行不同列顯示對應的資訊
                gp.DrawString(kea.Modifiers.ToString(), Font, br, xmods, y);//modifiers為keydown,keyup事件按下ctrl,shift,alt按下鍵的組合,返回為keys
                gp.DrawString(kea.KeyData.ToString(), Font, br, xdata, y);//keydata為keydown,keyup事件的鍵資料
                gp.DrawString(kea.Shift.ToString(), Font, br, xcode, y);//keyeventargs.shift指示是否按下shift鍵,bool型
                gp.DrawString(kea.Control.ToString(), Font, br, xctrl, y);
                gp.DrawString(kea.Alt.ToString(),Font,br,xalt,y);
            }
        }
    }
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9240380/viewspace-735409/,如需轉載,請註明出處,否則將追究法律責任。

相關文章