欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#實現(xiàn)任務(wù)欄通知窗口

 更新時間:2015年10月14日 10:24:07   投稿:lijiao  
作為程序員在享受的同時我們也不禁要問:這到底是怎么實現(xiàn)的呢?本文就利用Visual Studio .Net C# 2005以及.Net框架繪圖技術(shù)來實現(xiàn)這種任務(wù)欄通知窗口。

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

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

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

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

背景知識

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

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

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

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

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

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

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

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

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

[DllImportAttribute("user32.dll")] 
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 
//發(fā)送消息//winuser.h 中有函數(shù)原型定義 
[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向消息循環(huán)發(fā)送標題欄被按下的消息來模擬窗體的拖動,ShowWindow用來將特定句柄的窗體顯示出來,注意第二個參數(shù) nCmdShow,它表示窗體應(yīng)該怎樣顯示出來,而我們需要窗體不獲得焦點顯示出來,SW_SHOWNOACTIVATE可以滿足我們要求,繼續(xù)在 WinUser.h文件中搜索找到該常量對應(yīng)的值為4,于是我們就可以這樣調(diào)用來顯示窗體了:

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

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變量表示窗體的狀態(tài)是顯示中、停留中還是隱藏中,兩個計時器根據(jù)窗體不同狀態(tài)對窗體的位置進行更改,我們會使用SetBounds來執(zhí)行該操作:

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

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方法中完成,而且利用了雙重緩沖區(qū)技術(shù)來進行繪制操作,代碼如下:

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中,然后創(chuàng)建一個內(nèi)存Graphics對象 offScreenGraphics和內(nèi)存位圖對象offscreenBitmap,將內(nèi)存位圖對象的引用付值給offScreenGraphics,這樣所有對offScreenGraphics的繪制操作也都同時作用于offscreenBitmap,這時就將需要繪制到通知窗體表面的背景圖像 BackgroundBitmap繪制到內(nèi)存的Graphics對象上,DrawText函數(shù)根據(jù)需要顯示文字的大小和范圍調(diào)用 Graphics.DrawString將文字顯示在窗體的特定區(qū)域。最后,調(diào)用Graphics.DrawImage將內(nèi)存中已經(jīng)繪制完成的圖像顯示到通知窗體表面。

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

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); //發(fā)送左鍵點擊的 
//消息至該窗體(標題欄) 
} 
if (CloseBtnRectangle.Contains(e.Location)) //單擊Close按鈕關(guān)閉 
{ 
this.Hide(); 
currentTop = 1; 
} 
if (ContentRectangle.Contains(e.Location )) //單擊內(nèi)容區(qū)域 
{ 
System.Diagnostics.Process.Start("http://www.Rithia.com"); } 
} 
} 

結(jié)論

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

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

相關(guān)文章

  • C#如何實現(xiàn)圖片的剪裁并保存

    C#如何實現(xiàn)圖片的剪裁并保存

    基于c#實現(xiàn)圖片的裁剪并保存功能,實現(xiàn)方法非常簡單的,前端采用的cropper插件,但是在本文中沒有給大家多介紹,需要的朋友可以到腳本之家去查找這個插件。好了,如果大家對c#實現(xiàn)圖片裁剪并保存功能感興趣的朋友一起看看吧
    2016-11-11
  • C#實現(xiàn)時間戳的簡單方法

    C#實現(xiàn)時間戳的簡單方法

    這篇文章主要介紹了C#實現(xiàn)時間戳的簡單方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-04-04
  • 一則C#簡潔瀑布流代碼

    一則C#簡潔瀑布流代碼

    最近想實現(xiàn)數(shù)據(jù)的延遲加載,網(wǎng)上找一下有很多例子,看了Masonry的例子啟發(fā),自己寫了一個很簡潔的代碼。分享給大家
    2014-06-06
  • C#使用DirectX.DirectSound播放語音

    C#使用DirectX.DirectSound播放語音

    這篇文章主要為大家詳細介紹了C#使用DirectX.DirectSound播放語音,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Unity3D實現(xiàn)甜品消消樂游戲

    Unity3D實現(xiàn)甜品消消樂游戲

    這篇文章主要介紹了通過C# Unity3D繪制一個甜品消消樂游戲,文中的示例代碼講解詳細,對我們學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以學(xué)習(xí)一下
    2021-12-12
  • 探秘C# 6.0 的新特性

    探秘C# 6.0 的新特性

    本文的內(nèi)容包括引入C#6.0中的新的語言特性有哪些. 還有已經(jīng)被引入的代碼名稱為 “Roslyn”新編譯器. 編譯器是開放源碼的,并且可以從 codeplex 網(wǎng)站的這個地址下載到源代碼:https://roslyn.codeplex.com/.
    2015-03-03
  • C# XmlDocument操作XML案例詳解

    C# XmlDocument操作XML案例詳解

    這篇文章主要介紹了C# XmlDocument操作XML案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C#中的只讀結(jié)構(gòu)體(readonly struct)詳解

    C#中的只讀結(jié)構(gòu)體(readonly struct)詳解

    這篇文章主要給大家介紹了關(guān)于C#中只讀結(jié)構(gòu)體(readonly struct)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • C#用timer實現(xiàn)背單詞小程序

    C#用timer實現(xiàn)背單詞小程序

    這篇文章主要為大家詳細介紹了C#用timer實現(xiàn)背單詞小程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • C#重載運算符詳解

    C#重載運算符詳解

    這篇文章主要介紹了C#重載運算符,是進行C#程序設(shè)計中非常重要的一個技巧,需要的朋友可以參考下
    2014-08-08

最新評論