亚洲乱色熟女一区二区三区丝袜,天堂√中文最新版在线,亚洲精品乱码久久久久久蜜桃图片,香蕉久久久久久av成人,欧美丰满熟妇bbb久久久

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

QQ揭秘:如何實(shí)現(xiàn)托盤閃動(dòng)消息提醒?

admin
2017年2月7日 18:22 本文熱度 7038

  當(dāng)QQ收到好友的消息時(shí),托盤的圖標(biāo)會(huì)變成好友的頭像,并閃動(dòng)起來,點(diǎn)擊托盤,就會(huì)彈出與好友的聊天框,隨即,托盤恢復(fù)成QQ的圖標(biāo),不再閃動(dòng)。當(dāng)然,如果還有其它的好友的消息沒有提取,托盤的圖標(biāo)會(huì)變成另一個(gè)好友的圖標(biāo),并繼續(xù)閃動(dòng)。那么,QQ的這一效果是如何實(shí)現(xiàn)的了?我在QQ高仿GG2014中實(shí)現(xiàn)了同樣的效果,這里我就詳細(xì)地介紹一下。另外,文末最后會(huì)奉上GG最新版本4.1的源碼,這次甚至包含了JustLib項(xiàng)目的源碼哦!

      想要直接下載體驗(yàn)的朋友請(qǐng)點(diǎn)擊:“下載中心”

一.TwinkleNotifyIcon的實(shí)現(xiàn)原理

  這個(gè)會(huì)閃動(dòng)的托盤圖標(biāo),我將其定義為一個(gè)組件TwinkleNotifyIcon,我們先看TwinkleNotifyIcon的類圖:

  

   從TwinkleNotifyIcon類圖,我們已經(jīng)可以看出大致的實(shí)現(xiàn)方案:

(1)TwinkleNotifyIcon 內(nèi)部使用了NotifyIcon,以顯示在右下角的托盤。

(2)使用一個(gè)Timer定時(shí)器來控制托盤的閃動(dòng)。

(3)使用一個(gè)隊(duì)列friendQueue來存放待提取的好友消息。

(4)使用另一個(gè)隊(duì)列g(shù)roupQueue來存放待提取的群消息。

(5)當(dāng)網(wǎng)絡(luò)引擎接收到一個(gè)好友/群消息時(shí),我們就調(diào)用PushFriendMessage/PushGroupMessage方法,將其壓入friendQueue/groupQueue,并開始閃動(dòng)圖標(biāo)。

(6)當(dāng)托盤被點(diǎn)擊時(shí),就從Queue中提取最早的一個(gè)消息,并將其交給對(duì)應(yīng)的聊天窗口去處理。

二.TwinkleNotifyIcon 實(shí)現(xiàn)要點(diǎn)

  我們順著以下的順序來研究TwinkleNotifyIcon的實(shí)現(xiàn)代碼,就很容易了:

(1)壓入好友/群消息。

(2)點(diǎn)擊托盤,提取消息。

(3)重新判斷Queue中是否還有待提取的消息,以設(shè)置托盤的狀態(tài)。

1. 壓入消息

  我們以PushFriendMessage方法為例,PushGroupMessage的道理是一樣的。

復(fù)制代碼
    public void PushFriendMessage(string userID, int informationType, byte[] info, object tag)
    {           
        lock (this.locker)
        {
            try
            {
                this.twinkleNotifySupporter.PlayAudioAsyn(); //播放消息提示音
                //首先查看是否已經(jīng)存在對(duì)應(yīng)的聊天窗口
                IChatForm form = this.twinkleNotifySupporter.GetExistedChatForm(userID); 
                if (form != null)
                {
                    form.HandleReceivedMessage(informationType, info, tag);
                    return;
                }

                //接下來準(zhǔn)備將消息壓入queue
                UnhandleFriendMessageBox cache = null;
                lock (this.locker)
                {
                    //先查看queue中目標(biāo)好友對(duì)應(yīng)的Cache是否存在
                    for (int i = 0; i < this.friendQueue.Count; i++) 
                    {
                        if (this.friendQueue[i].User == userID)
                        {
                            cache = this.friendQueue[i];
                            break;
                        }
                    }

                    if (cache == null) //如果不存在,則為好友新建一個(gè)Cache
                    {
                        cache = new UnhandleFriendMessageBox(userID);
                        this.friendQueue.Add(cache);
                        //觸發(fā)UnhandleMessageOccured事件
                        if (this.UnhandleMessageOccured != null)
                        {
                            this.UnhandleMessageOccured(UnhandleMessageType.Friend, userID); 
                        }
                    }

                    cache.MessageList.Add(new Parameter<int, byte[], object>(informationType, info, tag));
                }

                string userName = this.twinkleNotifySupporter.GetFriendName(userID);
                this.notifyIcon1.Text = string.Format("{0}({1})  {2}條消息", userName, userID, cache.MessageList.Count);
                //獲取好友的頭像,將其作為托盤圖標(biāo)
                this.twinkleIcon = this.twinkleNotifySupporter.GetHeadIcon(userID);
                this.ControlTimer(true); //啟動(dòng)閃爍
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
            }
        }
    }
復(fù)制代碼

(1)在壓入消息的時(shí)候,先要播放消息提示音,以通知使用者收到了新的消息。

(2)首先要判斷消息的來源好友是否正在和自己聊天(已經(jīng)打開了與對(duì)方的聊天窗口),如果是,則直接將消息交給聊天窗口去顯示。否則,進(jìn)入下一步。

(3)看當(dāng)前的隊(duì)列中是否已經(jīng)存在了目標(biāo)好友的Cache,因?yàn)榭赡芤呀?jīng)有了待提取的來自該好友的消息了。如果已經(jīng)存在這個(gè)Cache,則將消息直接放入Cache,否則,為之新建一個(gè),再放入。

(4)之所以要觸發(fā)UnhandleMessageOccured事件,是為了通知外面,有待提取的消息出現(xiàn)了。比如,MainForm就會(huì)預(yù)定這個(gè)消息,然后使得好友列表中對(duì)應(yīng)的頭像閃動(dòng)。

復(fù)制代碼
    void notifyIcon_UnhandleMessageOccured(UnhandleMessageType type, string friendOrGroupID)
    {
        if (type == UnhandleMessageType.Friend)
        {
            this.friendListBox1.SetTwinkleState(friendOrGroupID, true); 
            this.recentListBox1.SetTwinkleState(friendOrGroupID, false, true);
            return;
        }

        if (type == UnhandleMessageType.Group)
        {
            this.groupListBox.SetTwinkleState(friendOrGroupID, true);
            this.recentListBox1.SetTwinkleState(friendOrGroupID, true, true);
            return;
        }
    }
復(fù)制代碼

  上面的UnhandleMessageOccured事件處理函數(shù),不僅僅使得好友列表中對(duì)應(yīng)的頭像閃動(dòng),即使是最近聯(lián)系人中,如果存在目標(biāo)好友,也會(huì)使其頭像閃動(dòng)。

(5)將托盤圖標(biāo)設(shè)置為目標(biāo)好友的頭像,并將ToolTip設(shè)置為好友的名稱及待提取的消息數(shù)量。

(6)使用定時(shí)器閃動(dòng)圖標(biāo)。

2.點(diǎn)擊托盤,提取消息

  如果托盤正在閃動(dòng),表明有待提取的消息,此時(shí)點(diǎn)擊托盤,將提取隊(duì)列中最早壓入的好友的消息。

復(fù)制代碼
    void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
    {
        try
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            lock (this.locker)
            {
                if (this.friendQueue.Count > 0)
                {
                    UnhandleFriendMessageBox cache = this.friendQueue[0];
                    this.friendQueue.RemoveAt(0);
                    IChatForm form = this.twinkleNotifySupporter.GetChatForm(cache.User);
                    if (form != null) //如果為null,表示剛刪除好友
                    {
                        form.HandleReceivedMessage(cache.MessageList);
                    }

                    this.DetectUnhandleMessage();

                    if (this.UnhandleMessageGone != null)
                    {
                        this.UnhandleMessageGone(UnhandleMessageType.Friend, cache.User);
                    }
                    return;
                }

                if (this.groupQueue.Count > 0)
                {
                    UnhandleGroupMessageBox cache = this.groupQueue[0];
                    this.groupQueue.RemoveAt(0);
                    IGroupChatForm form = this.twinkleNotifySupporter.GetGroupChatForm(cache.Group);
                    form.HandleReceivedMessage(cache.MessageList);

                    this.DetectUnhandleMessage();

                    if (this.UnhandleMessageGone != null)
                    {
                        this.UnhandleMessageGone(UnhandleMessageType.Group, cache.Group);
                    }
                    return;
                }
            }

            if (this.MouseClick != null)
            {
                this.MouseClick(sender, e);
            }
        }
        catch (Exception ee)
        {
            MessageBox.Show(ee.Message + " - " + ee.StackTrace);
        }
    }
復(fù)制代碼

(1)從上面代碼執(zhí)行的順序來看,是優(yōu)先提取好友消息,當(dāng)所有的好友消息提取完后,才提取群消息。

(2)提取消息時(shí),會(huì)調(diào)用twinkleNotifySupporter的GetChatForm方法來創(chuàng)建與目標(biāo)好友的聊天窗口,并將提取的消息交給這個(gè)窗口去處理。

(3)當(dāng)一個(gè)好友的消息被提取后,會(huì)觸發(fā)UnhandleMessageGone事件,以通知外部消息已經(jīng)被提取了。比如,MainForm就會(huì)預(yù)定這個(gè)消息,然后使得好友列表中對(duì)應(yīng)的頭像不再閃動(dòng)。

復(fù)制代碼
    void notifyIcon_UnhandleMessageGone(UnhandleMessageType type, string friendOrGroupID)
    {
        if (type == UnhandleMessageType.Friend)
        {
            this.friendListBox1.SetTwinkleState(friendOrGroupID, false); 
            this.recentListBox1.SetTwinkleState(friendOrGroupID, false, false);
            return;
        }

        if (type == UnhandleMessageType.Group)
        {
            this.groupListBox.SetTwinkleState(friendOrGroupID, false);
            this.recentListBox1.SetTwinkleState(friendOrGroupID, true, false);
            return;
        }
    }
復(fù)制代碼

(4)同時(shí),會(huì)重新掃描隊(duì)列中待提取消息的狀況,重設(shè)托盤圖標(biāo)的狀態(tài),這就是DetectUnhandleMessage方法做的事情。

3.重新判斷Queue中是否還有待提取的消息,以設(shè)置托盤的狀態(tài)

  每當(dāng)有消息被提取后,我們都需要重新掃描Queue中是否還有其它的待提取消息,DetectUnhandleMessage方法會(huì)被經(jīng)常調(diào)用。

復(fù)制代碼
    private void DetectUnhandleMessage()
    {
        if (this.friendQueue.Count == 0 && this.groupQueue.Count == 0)
        {
            this.ControlTimer(false);
        }
        else if (this.friendQueue.Count > 0)
        {
            UnhandleFriendMessageBox cache = this.friendQueue[0];
            string userName = this.twinkleNotifySupporter.GetFriendName(cache.User);
            this.notifyIcon1.Text = string.Format("{0}({1})  {2}條消息", cache.User, userName, cache.MessageList.Count);
            this.twinkleIcon = this.twinkleNotifySupporter.GetHeadIcon(cache.User);
        }
        else
        {
            UnhandleGroupMessageBox cache = this.groupQueue[0];
            string groupName = this.twinkleNotifySupporter.GetGroupName(cache.Group);
            this.notifyIcon1.Text = string.Format("{0}({1})  {2}條消息", groupName, cache.Group, cache.MessageList.Count);
            this.twinkleIcon = this.twinkleNotifySupporter.GroupIcon;
        }
    }
復(fù)制代碼

(1)如果好友消息的Queue和群消息的Queue當(dāng)中都沒有任何消息了,則不再閃動(dòng)托盤圖標(biāo)。

(2)再依次掃描好友消息的Queue和群消息的Queue,如果發(fā)現(xiàn)還有待提取的消息,則設(shè)置托盤圖標(biāo)的圖像,設(shè)置ToolTip,并開始閃動(dòng)圖標(biāo)。

三.GG V4.1 源碼 

   下載最新版本,請(qǐng)轉(zhuǎn)到這里。 

   


該文章在 2017/2/7 18:23:00 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved