基于MF系統的Windows SideShow界面是非常炫的(如下圖)。既然微軟能用.Net Micro Framework實現這么棒的界面效果,我想我們也能做到。
(SideShow模擬器界面和游戲程序中的右鍵菜單—注意菜單彈出后,其它的界面變暗了)
現在的任務是設計一套支持鼠標(或觸摸屏)的窗體框架(目前MF提供的Window類僅支持按鍵功能),所以正好把SideShow如此炫的界面元素也可以添加進來。
用過MF的人知道是用下面的方法來實現按鍵事件接收的,既然我們要支持鼠標功能,所以最好也用類似的機理實現。
???
- //按鍵事件 ?
- ????protected?override?void?OnButtonDown(ButtonEventArgs?e) ?
- ????{ ?
- ????????switch?(e.Button) ?
- ????????{ ?
- ????????????//按下確定鍵 ?
- ????????????case?Button.Select: ?
- ????????????????break; ?
- ????????????//按下左鍵 ?
- ????????????case?Button.Left: ?
- ????????????????break; ?
- ????????????//按下右鍵 ?
- ????????????case?Button.Right: ?
- ????????????????break; ?
- ????????????//按向上 ?
- ????????????case?Button.Up: ?
- ????????????????break; ?
- ????????????//按向下 ?
- ????????????case?Button.Down: ?
- ????????????????break; ?
- ????????????//按下菜單 ?
- ????????????case?Button.Menu: ?
- ????????????????break; ?
- ????????????//按下返回鍵 ?
- ????????????case?Button.Back: ?
- ????????????????break; ?
- ????????} ?
- ????????base.OnButtonDown(e); ?
- ????} ?
用反編譯工具仔細研究了MF底層庫代碼(.Net FrameWork 太龐大了,一個人絕對短時間內看不完,其實也很難看下去,但是對剛剛起步的MF來說,.Net Micro FrameWork就簡單多了),終于理清了頭緒。主要原理是在鼠標信息處理線程中通過Application.Current.Windows 屬性(該屬性存放了當前實例所有派生于Window類的窗體)和應用實例的this.Dispatcher屬性的BeginInvoke方法,外部調用窗體鼠標事件函數。充分利用基類虛函數的妙處來實現類似按鍵信息處理的功能。
在YFWindowBase類中聲明如下虛擬鼠標事件函數。
?
- //鼠標移動 ?
- ????public?virtual?void?OnMouseMove(object?sender,?MouseEventArgs?e) ?
- ????{ ?
- ????????if?(MouseMove?!=?null)?MouseMove(sender,?e); ?
- ????} ?
- ????//鼠標單擊 ?
- ????public?virtual?void?OnMouseClick(object?sender,?MouseEventArgs?e) ?
- ????{ ?
- ????????if?(MouseClick?!=?null)?MouseClick(sender,?e); ?
- ????} ?
- ????//按下 ?
- ????public?virtual?void?OnMouseDown(object?sender,?MouseEventArgs?e) ?
- ????{ ?
- ???????if?(MouseDown?!=?null)?MouseDown(sender,?e); ?
- ????} ?
- ????//抬起 ?
- ????public?virtual?void?OnMouseUp(object?sender,?MouseEventArgs?e) ?
- ????{ ?
- ????????if?(MouseUp?!=?null)?MouseUp(sender,?e); ?
- ????} ?
- ? ?
在鼠標信息處理函數中執行如下的代碼即可。
???
- //處理鼠標消息 ?
- ????private?static?void?TransactMouse(MouseState?state,?int?x,?int?y,?MouseButtons?button) ?
- ????{ ?
- ????????if?(Application.Current?==?null)?return; ?
- ????????for?(int?i?=?Application.Current.Windows.Count?-?1;?i?>=?0;?i--) ?
- ????????{ ?
- ????????????try?
- ????????????{ ?
- ????????????????YFWindowBase?mw?=?Application.Current.Windows[i]?as?YFWindowBase; ?
- ? ?
- ????????????????if?(mw.Enabled?&&?mw.IsVisible) ?
- ????????????????{ ?
- ????????????????????//判斷子窗體 ?
- ????????????????????bool?bReturn?=?false; ?
- ????????????????????for?(int?j?=?mw.Children.Count?-?1;?j?>=?0;?j--) ?
- ????????????????????{ ?
- ????????????????????????//僅最上層并且可視的控件接收鼠標消息 ?
- ????????????????????????YFControl?cl?=?mw.Children[j]; ?
- ????????????????????????if?(!bReturn?&&?cl.Visible?&&?IsRectContains(x,?y,?mw.Left?+?cl.Left,?mw.Top?+?cl.Top,?cl.Width,?cl.Height)) ?
- ????????????????????????{ ?
- ????????????????????????????if?(cl.Enable)?//Enable和Visible不一樣,Enable即使無效,下層控件也沒有機會獲得鼠標消息 ?
- ????????????????????????????{ ?
- ????????????????????????????????if?(!cl._EnterFlag) ?
- ????????????????????????????????{ ?
- ????????????????????????????????????cl._EnterFlag?=?true; ?
- ????????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseEnter),?cl,?new?MouseEventArgs(button,?x?-?cl.Left?-?mw.Left,?y?-?cl.Top?-?mw.Top)); ?
- ????????????????????????????????} ?
- ????????????????????????????????if?((state?&?MouseState.Move)?>?0) ?
- ????????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseMove),?cl,?new?MouseEventArgs(button,?x?-?cl.Left?-?mw.Left,?y?-?cl.Top?-?mw.Top)); ?
- ????????????????????????????????if?((state?&?MouseState.Down)?>?0) ?
- ????????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseDown),?cl,?new?MouseEventArgs(button,?x?-?cl.Left?-?mw.Left,?y?-?cl.Top?-?mw.Top)); ?
- ????????????????????????????????if?((state?&?MouseState.Up)?>?0) ?
- ????????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseUp),?cl,?new?MouseEventArgs(button,?x?-?cl.Left?-?mw.Left,?y?-?cl.Top?-?mw.Top)); ?
- ????????????????????????????????if?((state?&?MouseState.Click)?>?0) ?
- ????????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseClick),?cl,?new?MouseEventArgs(button,?x?-?cl.Left?-?mw.Left,?y?-?cl.Top?-?mw.Top)); ?
- ????????????????????????????} ?
- ????????????????????????????//向主窗體傳OnMouseEvent消息,為了繪制鼠標 ?
- ????????????????????????????if?((state?&?MouseState.Event)?>?0) ?
- ????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseEvent),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????????????bReturn?=?true; ?
- ????????????????????????} ?
- ????????????????????????else?
- ????????????????????????{ ?
- ????????????????????????????if?(cl._EnterFlag) ?
- ????????????????????????????{ ?
- ????????????????????????????????cl._EnterFlag?=?false; ?
- ????????????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(cl.OnMouseLeave),?cl,?new?MouseEventArgs(button,?x?-?cl.Left,?y?-?cl.Top)); ?
- ????????????????????????????} ?
- ????????????????????????} ?
- ????????????????????} ?
- ????????????????????if?(bReturn)?return; ?
- ????????????????} ?
- ? ?
- ????????????????//僅最上層并且可視的窗體接收鼠標消息 ?
- ????????????????if?(mw.IsVisible?&&?IsRectContains(x,?y,?mw.Left,?mw.Top,?mw.Width,?mw.Height)) ?
- ????????????????{ ?
- ????????????????????if?(!mw.Enabled)?return; ?
- ? ?
- ????????????????????if?((state?&?MouseState.Move)?>?0) ?
- ????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseMove),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????if?((state?&?MouseState.Down)?>?0) ?
- ????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseDown),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????if?((state?&?MouseState.Up)?>?0) ?
- ????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseUp),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????if?((state?&?MouseState.Click)?>?0) ?
- ????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseClick),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????if?((state?&?MouseState.Event)?>?0) ?
- ????????????????????????_dispatcher.BeginInvoke(new?MouseInputEventHandler(mw.OnMouseEvent),?mw,?new?MouseEventArgs(button,?x?-?mw.Left,?y?-?mw.Top)); ?
- ????????????????????return; ?
- ????????????????} ?
- ????????????} ?
- ????????????catch?(Exception?e) ?
- ????????????{ ?
- ????????????????throw?new?Exception(e.Message.ToString(),?e); ?
- ????????????} ?
- ????????} ?
- ????} ?
? 用戶程序的窗體類只要派生于YFWindowBase類,就可以直接支持鼠標和按鍵功能了。用戶代碼如下:
???
- //主窗體 ?
- ???internal?sealed?class?MFWindow?:YFWindowBase ?
- ???{ ?
- ???????public?YFLabel?label1; ?
- ???????YFButton?button1,?button2,?button3,?button4,?button5; ?
- ???????public?MFWindow() ?
- ???????{ ?
- ???????????//標簽 ?
- ???????????label1?=?new?YFLabel("就緒",?0,?Height?-?25,?Width,?25); ?
- ???????????label1.TextAlign?=?TextAlignment.Left; ?
- ???????????label1.BackColor?=?ColorUtility.ColorFromRGB(189,?235,?255); ?
- ???????????label1.BorderStyle?=?BorderStyle.FixedSingle; ?
- ???????????//添加按鈕 ?
- ???????????button1?=?new?YFButton("觸摸屏校準",?30,?35,?90,?40); ?
- ???????????button1.MouseClick?+=?new?MouseInputEventHandler(button_MouseClick); ?
- ???????????button2?=?new?YFButton("計算器",200,?35,?90,?40); ?
- ???????????button2.MouseClick?+=?new?MouseInputEventHandler(button_MouseClick); ?
- ???????????button3?=?new?YFButton("簡易記事本",?30,?135,?90,?40); ?
- ???????????button3.MouseClick?+=?new?MouseInputEventHandler(button_MouseClick); ?
- ???????????button4?=?new?YFButton("關于...",?200,?135,?90,?40); ?
- ???????????button4.MouseClick?+=?new?MouseInputEventHandler(button_MouseClick); ?
- ???????????button5?=?new?YFButton("主菜單",?125,?85,?70,?40); ?
- ???????????button5.MouseClick?+=?new?MouseInputEventHandler(button_MouseClick); ?
- ???????????Children.Add(button1); ?
- ???????????Children.Add(button2); ?
- ???????????Children.Add(button3); ?
- ???????????Children.Add(button4); ?
- ???????????Children.Add(button5); ?
- ???????????Children.Add(label1); ?
- ???????????button3.Enable?=?false; ?
- ???????????//button3.Visible?=?false; ?
- ???????????//設置菜單 ?
- ???????????Menu.AddItem(new?MenuItem("觸摸屏校準")); ?
- ???????????Menu.AddItem(new?MenuItem("-")); ?
- ???????????Menu.AddItem(new?MenuItem("計算器")); ?
- ???????????Menu.AddItem(new?MenuItem("簡易記事本")); ?
- ???????????Menu.AddItem(new?MenuItem("-")); ?
- ???????????Menu.AddItem(new?MenuItem("關于...")); ?
- ???????????Menu[3].Enabled?=?false; ?
- ???????????//Menu[3].Visible?=?false; ?
- ???????}???????? ?
- ???????//按鈕事件 ?
- ???????void?button_MouseClick(object?sender,?MouseEventArgs?e) ?
- ???????{ ?
- ???????????YFButton?button=((YFButton)sender); ?
- ???????????switch?(button.Text) ?
- ???????????{ ?
- ???????????????case?"主菜單": ?
- ???????????????????//彈出菜單 ?
- ???????????????????this.Menu.Show(); ?
- ???????????????????break; ?
- ???????????????default: ?
- ???????????????????OnMenuClick(new?MenuEventArgs(0,?button.Text)); ?
- ???????????????????break; ?
- ???????????}?????????????????????????? ?
- ???????} ?
運行后的界面如下:
?
圖1:主界面(按鈕即支持鼠標也可以用按鍵切換輸入焦點(right鍵等同于PC平臺上的Tab鍵),并用OK鍵觸發按鍵事件)
?
圖2:單擊主菜單按鈕或單擊“Menu”就可以彈出主菜單
?
圖3:不要小看了上圖的藍色小圓,是我費了好大勁才繪制出來的(目前MF僅支持矩形框的填充)。
?
- private?void?DrawCircle(Color?c,int?x,?int?y,?int?r,?DrawingContext?dc) ?
- ????{ ?
- ????????Pen?p=new?Pen(c); ?
- ????????SolidColorBrush?b?=?new?SolidColorBrush(c); ?
- ????????int?Offset45=(int)(0.707*r); ?
- ????????int?Offset30?=?r?/?2; ?
- ????????int?Offset60?=?(int)(0.866?*?r); ?
- ? ?
- ????????for?(int?i?=?Offset45;?i?<?r?+?1;?i++) ?
- ????????{ ?
- ????????????dc.DrawEllipse(null,?p,?x,?y,?i,?i); ?
- ????????} ?
- ????????dc.DrawRectangle(b,?null,?x?-?Offset45,?y?-?Offset45,Offset45*2,?Offset45*2); ?
- ????????dc.DrawRectangle(b,?null,?x?-?Offset60,?y?-?Offset30,?Offset60?*?2,?Offset30?*?2); ?
- ????????dc.DrawRectangle(b,?null,?x?-?Offset30,?y?-?Offset60,?Offset30?*?2,?Offset60?*?2); ?
- ? ?
- ????????dc.DrawLine(p,?x?-?Offset60,?y?-?Offset30,?x?-?Offset30,?y?-?Offset60); ?
- ????????dc.DrawLine(p,?x+?Offset60?,?y?+?Offset30,?x?+?Offset30?,y?+?Offset60?); ?
- ????????dc.DrawLine(p,?x?-?Offset60,?y?+?Offset30,?x?-?Offset30?,?y?+?Offset60); ?
- ????????dc.DrawLine(p,?x?+?Offset60,?y?-?Offset30,?x?+?Offset30,?y?-?Offset60); ?
- ???} ?
- ? ?
- ? ?
圖5:終于在MF上實現了計算器的功能,目前不僅支持鼠標,也可以用光標鍵和OK鍵進行輸入計算了。
別小看了計算器程序,由于MF僅有數字轉字符串功能,沒有實現字符串轉數字的功能,我自己自定義了一些函數,用了一些特殊的用法才編寫完成。
?
- //數字輸入的部分代碼 ?
- if?(strInput?==?"0.")?dblInput?=?0; ?
- ????????if?(strInput?!=?"0.") ?
- ????????{ ?
- ????????????strInput?+=?b.Text; ?
- ????????????if?(strInput.IndexOf('.')<1) ?
- ????????????{ ?
- ????????????????dblInput?*=?10; ?
- ????????????????dblInput?+=?ToDouble(b.Text); ?
- ????????????} ?
- ????????????else?
- ????????????{ ?
- ????????????????int?index?=?strInput.Length?-?strInput.LastIndexOf('.')?-?1; ?
- ????????????????dblInput?+=?ToDouble(b.Text)?/System.Math.Pow(10,index); ?
- ????????????} ?
- ????????} ?
- ????????else?if?(b.Text?!=?"0") ?
- ????????{ ?
- ????????????strInput?=?b.Text; ?
- ????????????dblInput?=?ToDouble(b.Text); ?
- ?????} ?
?? 下面是窗體的界面搭建部分,你絕對想不到用這么短的代碼就實現了上圖的界面布局(看過我以前.Net Micro Framework研究的網友,應該對MF本身提供的控件有印象,正是因為系統的控件不好用,我專門重新寫了一套MF控件類)。
???
- ?YFButton[]?button=new?YFButton[20]; ?
- ????YFLabel?lblInput?=?null; ?
- ????string[]?strText?=?new?string[]?{?"7",?"8",?"9",?"/",?"CE",?"4",?"5",?"6",?"*",?"%",?"1",?"2",?"3",?"-",?"1/x",?"0",?"+/-",?".",?"+",?"="?}; ?
- ????public?YFCalc(string?Title,int?Width,int?Height,YFWindowBase?Parent) ?
- ????????:?base(Title,?Width,?Height,?Parent) ?
- ????{ ?
- ????????int?x=ClientRect.X,y=ClientRect.Y; ?
- ? ?
- ????????lblInput?=?new?YFLabel("0.",?x?+?5,?y?+?5,?ClientRect.Width?-?10,?20); ?
- ????????lblInput.TextAlign?=?TextAlignment.Right; ?
- ????????Children.Add(lblInput);? ?
- ????????for?(int?i?=?0;?i?<?20;?i++) ?
- ????????{ ?
- ????????????if(i?%?5==0?&&?i!=0) ?
- ????????????{ ?
- ????????????????x?=?ClientRect.X; ?
- ????????????????y?=?y?+?32; ?
- ????????????} ?
- ????????????button[i]?=?new?YFButton("",?x?+?5,?y?+?32,?32,?28); ?
- ????????????button[i].Text?=?strText[i]; ?
- ????????????button[i].MouseClick?+=?new?MouseInputEventHandler(button_MouseClick);? ?
- ????????????x?+=?37; ?
- ????????????Children.Add(button[i]);? ?
- ????????}??????????????? ?
- ????} ?
- ????//按鈕單擊 ?
- ????void?button_MouseClick(object?sender,?MouseEventArgs?e) ?
- { ?
- } ?
其實這段時間以來,我一直在研究MF,雖然目前它還不是很成熟,但是隨著研究的深入,越來越對它癡迷,越來越發現很多MF的寶藏(如果你有耐心的話,一定要看看MF底層框架的源碼(通過反編譯工具Reflector),你會發現很多很有意思的功能)。
MF相對于Windows XP/Vista、Windows CE而言,還只能算一個嬰孩,但就是這樣,就如一個偉人所說:孩子就是未來的希望。所以有理由相信MF的明天會更好
本文轉自yefanqiu51CTO博客,原文鏈接:http://blog.51cto.com/yfsoft/322900,如需轉載請自行聯系原作者