亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#實現任務欄通知窗口

2020-01-24 01:25:21
字體:
來源:轉載
供稿:網友

想必大部分網友都使用過QQ、MSN等聊天程序,它們的界面都相當華麗,尤其是當網友上線以及消息提示時會有一個浮動的窗體從屏幕的右下方緩慢升起,既美觀又人性化。本文主要講解用C#來實現任務欄通知窗口。
簡介

QQ和MSN的任務欄通知窗口很人性化,它可以在不丟失主窗體焦點的前提下顯示一個具備皮膚Skin的通知窗體,當它顯示一段時間后會自動消失,所以用戶根本不用干預它。

這樣的通知窗體和一般的具備標題欄、系統圖標和按鈕的窗體沒有太大的區別,窗體表面其實就是畫上去的一張位圖而已,而窗體的浮動則會復雜一點,我們會用到.Net框架的雙重緩沖區繪圖技術(參見作者編譯文章“Windows窗體的.Net框架繪圖技術”)來保證移動窗體時所顯示的內容平滑且不閃爍,以及使用P/Invoke平臺調用進行對Win32API

函數的調用來完成不獲得焦點的窗體顯示和非標題欄窗體拖動。兩種位圖的皮膚運行時的界面如下:

背景知識

通知窗口就是將一般的窗體附加上一層皮膚,這里所謂的皮膚就是一張位圖圖片,該位圖圖片通過窗體的OnPaintbackground事件被繪制到窗體表面,在附加位圖之前需要調整窗體的可視屬性,由于繪制操作是針對于窗體客戶區域的,所謂客戶區域就是指窗體標題欄下方以及窗體邊框以內的所有區域,所以需要將窗體的邊框和外觀屬性FormBorderStyle調整為:None,這樣所繪制的圖像就會填充整個窗體。

首先,我們會用到Region對象,Region對象可以精確的描繪出任意形狀的輪廓范圍,通過一個位圖圖像創建Region對象后再將其傳遞給窗體的Region屬性就可以使窗體按照Region所定義的輪廓顯示出來。作為皮膚使用的位圖文件可以通過任何圖像編輯軟件諸如:Photeshop來創建和編輯,只是注意一點,需要將圖片的背景色調成特定顏色以便程序繪制時將其清除,我們在這里使用的背景色為粉紅色。為了能夠讓Region對象按照圖像中感興趣的內容邊框來創建窗體,我們還需要使用GraphicsPath類將圖像輪廓按照一定路徑標注下來,稍后便按照該路徑創建Region對象。

然后通過窗體的繪圖事件將位圖的內容顯示在窗體表面,我們沒有直接使用OnPaintbackground事件而是重載了該方法,這樣做的好處就是一些低層的繪制操作還繼續交由.Net框架運行時來處理,我們只考慮實際需要的繪制操作即可。在OnPaintbackground方法中我們啟用了雙重緩沖區繪圖技術,所謂該技術就是指先在內存中的一塊畫布上把將要顯示的圖像顯示出來或進行處理,等到操作完成再將該畫布上所顯示的圖像放置到窗體表面,這樣的機制可以非常有效的降低閃爍的出現,使圖像顯示更加平滑。

通知窗體從屏幕的右下方進行升起停留一段時間后再慢慢回落,這里需要用到返回屏幕區域的大小范圍的.Net框架方法Screen.GetWorkingArea(WorkAreaRectangle),通過一定算法計算出通知窗體顯示前的初始位置。

最后,我們將要顯示的文本按照一定格式和Rectangle對象所指定的區域范圍繪制到窗體表面。通知窗體的關閉操作是通過設定一個區域,當用戶用鼠標單擊時檢測單擊坐標是否在該區域內,若在區域內就可以執行隱藏通知窗體的代碼。

我們注意了,當QQ和MSN的通知窗口顯示時其主窗體的焦點沒有丟失,也就是說程序沒有將自身的焦點轉移到顯示的通知窗體上。經過測試,我們無論怎么樣調用.Net框架提供的窗體顯示例程譬如:Form.Show都無法保證主窗體的焦點不丟失,在VC環境下我們可以使用Win32API的 ShowWindows函數來完成復雜的窗體顯示操作,但是.Net框架根本沒有提供類似的方法,那么我們能否通過.Net框架調用該API函數來顯示窗體呢?

幸好.Net框架提供了P/Invoke平臺調用,利用平臺調用這種服務,托管代碼就可以調用在動態鏈接庫中實現的非托管函數,并可以封送其參數,我們可以輕松的顯示但不獲得焦點的窗體。程序中用到的Windows API以及常量的定義都保存在WinUser.h頭文件中,其對應的動態鏈接庫文件就是user32.dll,使用.Net框架提供的 DllImportAttribute類對導入的函數進行定義,然后就可以非常方便的在程序中調用該函數了。

由于我們將通知窗體的標題欄隱藏了,所以對窗體拖動操作還需要我們自己動手進行處理。本文介紹了如何更加高效的進行拖動窗體操作,有些網友在對于非標題欄拖動窗體編程時偏向組合使用鼠標事件來進行,這樣做的本質沒有任何不妥,但是頻繁的事件響應和處理反而使程序性能有所降低。我們將繼續使用 Win32API的底層處理方法來解決該問題,就是向窗體發送標題欄被單擊的消息,模擬實際的拖動操作。

我們會通過2個計時器來完成窗體的顯示、停留和隱藏,通過設置速度變量可以改變窗口顯示和隱藏的速度。

[DllImportAttribute("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); //發送消息//winuser.h 中有函數原型定義 [DllImportAttribute("user32.dll")] public static extern bool ReleaseCapture(); //釋放鼠標捕捉winuser.h [DllImportAttribute("user32.dll")] //winuser.h private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); 

SendMessage向消息循環發送標題欄被按下的消息來模擬窗體的拖動,ShowWindow用來將特定句柄的窗體顯示出來,注意第二個參數 nCmdShow,它表示窗體應該怎樣顯示出來,而我們需要窗體不獲得焦點顯示出來,SW_SHOWNOACTIVATE可以滿足我們要求,繼續在 WinUser.h文件中搜索找到該常量對應的值為4,于是我們就可以這樣調用來顯示窗體了:

ShowWindow(this.Handle, 4); 
我們創建了一個自定義函數ShowForm用來封裝上面的ShowWindow用來是顯示窗體,同時傳遞了所用到的幾個Rectangle矩形區域對象,最后調用ShowWindows函數將窗體顯示出來,代碼片段如下:

public void ShowForm(string ftitletext, string fcontenttext, Rectangle fRegionofFormTitle, Rectangle fRegionofFormTitlebar, Rectangle fRegionofFormContent, Rectangle fRegionofCloseBtn) { titleText = ftitletext; contentText = fcontenttext; WorkAreaRectangle = Screen.GetWorkingArea(WorkAreaRectangle); this.Top = WorkAreaRectangle.Height + this.Height; FormBorderStyle. = FormBorderStyle.None; WindowState = FormWindowState.Normal; this.SetBounds(WorkAreaRectangle.Width - this.Width, WorkAreaRectangle.Height - currentTop, this.Width, this.Height); CurrentState = 1; timer1.Enabled = true; TitleRectangle = fRegionofFormTitle; TitlebarRectangle = fRegionofFormTitlebar; ContentRectangle = fRegionofFormContent; CloseBtnRectangle = fRegionofCloseBtn; ShowWindow(this.Handle, 4); //#define SW_SHOWNOACTIVATE } 

CurrentState變量表示窗體的狀態是顯示中、停留中還是隱藏中,兩個計時器根據窗體不同狀態對窗體的位置進行更改,我們會使用SetBounds來執行該操作:

this.SetBounds(WorkAreaRectangle.Width - this.Width, WorkAreaRectangle.Height - currentTop, this.Width, this.Height);  
當窗體需要升起時將窗體的Top屬性值不斷減少,而窗體回落時將Top屬性值增加并超過屏幕的高度窗體就消失了,雖然原理很簡單但仍需精確控制。
SetBackgroundBitmap函數首先將窗體背景圖像保存到BackgroundBitmap變量中,然后根據該位圖圖像輪廓和透明色創建Region,BitmapToRegion就用于完成Bitmap到Region的轉換,程序再將這個Region付值給窗體的Region屬性以完成不規則窗體的創建。

public void SetBackgroundBitmap(Image image, Color transparencyColor)  {  BackgroundBitmap = new Bitmap(image);  Width = BackgroundBitmap.Width;  Height = BackgroundBitmap.Height;  Region = BitmapToRegion(BackgroundBitmap, transparencyColor);  }  public Region BitmapToRegion(Bitmap bitmap, Color transparencyColor)  {  if (bitmap == null)  throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");  int height = bitmap.Height;  int width = bitmap.Width;  GraphicsPath path = new GraphicsPath();  for (int j = 0; j < height; j++)  for (int i = 0; i < width; i++)  {  if (bitmap.GetPixel(i, j) == transparencyColor)  continue;  int x0 = i;  while ((i < width) && (bitmap.GetPixel(i, j) != transparencyColor))  i++;  path.AddRectangle(new Rectangle(x0, j, i - x0, 1));  }  Region region = new Region(path);  path.Dispose();  return region;  } 

通知窗體背景以及文字的繪制在重載的OnPaintBackground方法中完成,而且利用了雙重緩沖區技術來進行繪制操作,代碼如下:

protected override void OnPaintBackground(PaintEventArgs e) { Graphics grfx = e.Graphics; grfx.PageUnit = GraphicsUnit.Pixel; Graphics offScreenGraphics; Bitmap offscreenBitmap; ffscreenBitmap = new Bitmap(BackgroundBitmap.Width, BackgroundBitmap.Height); ffScreenGraphics = Graphics.FromImage(offscreenBitmap); if (BackgroundBitmap != null) { offScreenGraphics.DrawImage(BackgroundBitmap, 0, 0, BackgroundBitmap.Width, BackgroundBitmap.Height); } DrawText(offScreenGraphics); grfx.DrawImage(offscreenBitmap, 0, 0); } 

 上述代碼首先返回窗體繪制表面的Graphics并保存在變量grfx中,然后創建一個內存Graphics對象 offScreenGraphics和內存位圖對象offscreenBitmap,將內存位圖對象的引用付值給offScreenGraphics,這樣所有對offScreenGraphics的繪制操作也都同時作用于offscreenBitmap,這時就將需要繪制到通知窗體表面的背景圖像 BackgroundBitmap繪制到內存的Graphics對象上,DrawText函數根據需要顯示文字的大小和范圍調用 Graphics.DrawString將文字顯示在窗體的特定區域。最后,調用Graphics.DrawImage將內存中已經繪制完成的圖像顯示到通知窗體表面。

我們還需要捕獲窗體的鼠標操作,有三個操作在這里進行,1、處理拖動窗體操作,2、處理通知窗體的關閉操作,3、內容區域的單擊操作。三個操作都需要檢測鼠標的當前位置與每個Rectangle區域的包含關系,只要單擊落在特定區域我們就進行相應的處理,代碼如下:

private void TaskbarForm_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (TitlebarRectangle.Contains(e.Location)) //單擊標題欄時拖動 { ReleaseCapture(); //釋放鼠標捕捉 SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); //發送左鍵點擊的 //消息至該窗體(標題欄) } if (CloseBtnRectangle.Contains(e.Location)) //單擊Close按鈕關閉 { this.Hide(); currentTop = 1; } if (ContentRectangle.Contains(e.Location )) //單擊內容區域 { System.Diagnostics.Process.Start("http://www.Rithia.com"); } } } 

結論

該程序可以很好的進行通知窗體的顯示、停留和隱藏操作,并且具備簡單的換膚機制,在利用了雙重緩沖區繪圖技術后,可以保證窗體的繪制平滑且沒有閃爍。

如何利用C#實現任務欄通知窗口,大家通過本文都有了大概的了解了吧,希望能夠有所收獲吧1

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人网在线免费看| 51ⅴ精品国产91久久久久久| 日韩中文有码在线视频| 一区二区三区四区视频| 国产精品偷伦视频免费观看国产| 久久久久国产精品免费网站| 欧美视频专区一二在线观看| 国产成人精品久久二区二区| 国产精品久久久久久久久久久久久| 91精品久久久久久久久青青| 成人免费看黄网站| 黄色成人在线免费| 日本精品久久久| 日韩精品在线免费| 一本色道久久综合狠狠躁篇的优点| 久久国产精品电影| 色综合久久中文字幕综合网小说| 国产精品日韩欧美综合| 欧美亚洲在线播放| 国内外成人免费激情在线视频网站| 久久久久久久国产精品视频| 91在线视频九色| 日韩精品在线免费观看视频| 国产精品视频内| 亚洲免费视频一区二区| 主播福利视频一区| 亚洲欧美精品suv| 欧美高清性猛交| 国产精品h在线观看| 国产精彩精品视频| 1769国内精品视频在线播放| 91精品国产综合久久久久久蜜臀| 日韩在线观看视频免费| 成人免费网站在线观看| 欧美黑人狂野猛交老妇| 97在线精品国自产拍中文| 日韩美女福利视频| 欧美与黑人午夜性猛交久久久| 在线视频欧美日韩| 欧美国产精品va在线观看| 国产欧美日韩精品丝袜高跟鞋| 亚洲一区免费网站| 成人福利在线视频| 欧美亚洲成人精品| 欧美裸体xxxx| 久久精品免费电影| 亚洲精品久久久久久久久久久久久| 在线观看成人黄色| 欧美精品电影在线| 国产精品视频免费在线| 55夜色66夜色国产精品视频| 亚洲精品在线观看www| 色悠悠国产精品| 最近的2019中文字幕免费一页| 欧美电影免费观看高清完整| 国产精品91在线| 欧亚精品中文字幕| 在线精品视频视频中文字幕| 性欧美长视频免费观看不卡| 国产精品自拍小视频| 成人黄色大片在线免费观看| 91精品国产综合久久久久久蜜臀| 久久免费少妇高潮久久精品99| 欧美日韩国产综合视频在线观看中文| 国产一区二区三区精品久久久| 日韩一二三在线视频播| 日韩电视剧免费观看网站| 清纯唯美亚洲激情| 日韩av电影在线播放| 日韩欧美中文第一页| 欧美日韩国产一区二区三区| 久久福利网址导航| 亚洲丁香久久久| 成人午夜在线视频一区| 久久91精品国产| 国产成人精品日本亚洲专区61| 韩日精品中文字幕| 日韩精品极品毛片系列视频| 在线日韩日本国产亚洲| 日韩一区二区三区在线播放| www.日韩不卡电影av| 成人免费观看49www在线观看| 亚洲免费视频观看| 亚洲欧美激情精品一区二区| 国模视频一区二区三区| 日本一区二区三区在线播放| 国产精品69精品一区二区三区| 91社区国产高清| 国产精品av电影| 亚洲最大激情中文字幕| 精品网站999www| 国产成人福利网站| 久久综合九色九九| 国产精品精品久久久久久| 一区二区三区回区在观看免费视频| 中文字幕日韩视频| 97在线免费观看视频| 久久精品中文字幕免费mv| 一本一本久久a久久精品牛牛影视| 日韩大陆毛片av| 热久久99这里有精品| 狠狠久久五月精品中文字幕| 成人精品一区二区三区电影免费| 久久久精品视频在线观看| 亚洲乱码国产乱码精品精天堂| 国产精品1区2区在线观看| 国产精品久久久久高潮| 欧美丰满片xxx777| 成人激情视频免费在线| 欧美电影《睫毛膏》| 欧美电影在线观看完整版| 日本aⅴ大伊香蕉精品视频| 狠狠色狠狠色综合日日小说| 2018中文字幕一区二区三区| 亚洲男人天堂古典| 91精品免费看| 最近2019年手机中文字幕| 91久久精品久久国产性色也91| 久久久久国色av免费观看性色| www.国产一区| 国产精品久久久久久超碰| 久久在线精品视频| 在线精品国产成人综合| 久久久电影免费观看完整版| 性金发美女69hd大尺寸| 国产日产久久高清欧美一区| 亚洲人精选亚洲人成在线| 欧美亚洲国产另类| 亚洲aⅴ日韩av电影在线观看| 国产成人精品午夜| 久久精品99国产精品酒店日本| 国产91露脸中文字幕在线| 日韩中文在线中文网在线观看| 亚洲sss综合天堂久久| 清纯唯美亚洲综合| 国产精品情侣自拍| 国产精品香蕉av| 91久久久久久久久久久| 亚洲va久久久噜噜噜久久天堂| 26uuu另类亚洲欧美日本老年| 亚洲性av网站| 精品小视频在线| 亚洲欧美另类人妖| 亚洲sss综合天堂久久| 另类天堂视频在线观看| 亚洲精品成人久久久| 亚洲欧美在线一区| 日韩人在线观看| 91av在线免费观看| 国内精品小视频在线观看| 欧美激情xxxxx| 欧美在线观看视频| 欧美乱大交做爰xxxⅹ性3| 成人福利网站在线观看| 亚洲欧美中文日韩v在线观看| 亚洲毛片在线看| 91在线观看免费高清| 日韩国产精品一区| 日韩精品欧美激情| 国a精品视频大全| 色无极影院亚洲| 精品动漫一区二区| 色偷偷亚洲男人天堂| 久久精品2019中文字幕|