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);
}
}
}
}