[原創][開源] SunnyUI.Net 開發日誌:ListBox 增加跟隨滑鼠滑過高亮

来源:https://www.cnblogs.com/yhuse/archive/2020/05/21/12933885.html
-Advertisement-
Play Games

SunnyUI.Net 開發日誌:ListBox 增加跟隨滑鼠滑過高亮,這可是在別人兩年的基礎上再改進的,哈哈!~ ...


 

SunnyUI.Net, 基於 C# .Net WinForm 開源控制項庫、工具類庫、擴展類庫、多頁面開發框架

 

 SunnyUI.Net 開發日誌:ListBox 增加跟隨滑鼠滑過高亮

 

 QQ群里,寸木說,ListBox滑鼠移動時,當前行需要焦點,我想了想,不難實現啊

不就是在滑鼠移動時重繪Item嘛,何況選中的Item已經改了顏色了。

見UIListBox代碼:

protected override void OnDrawItem(DrawItemEventArgs e)
        {
            base.OnDrawItem(e);
            BeforeDrawItem?.Invoke(this, Items, e);
            if (Items.Count == 0)
            {
                return;
            }

            e.DrawBackground();

            if (e.Index < 0 || e.Index >= Items.Count)
            {
                return;
            }

            StringFormat sStringFormat = new StringFormat();
            sStringFormat.LineAlignment = StringAlignment.Center;

            Color backColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected ? ItemSelectBackColor : BackColor;
            Color foreColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected ? ItemSelectForeColor : ForeColor;

            Rectangle rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1);
            e.Graphics.FillRectangle(BackColor, e.Bounds);
            e.Graphics.FillRoundRectangle(backColor, rect, 5);
            e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
        }

看:(e.State & DrawItemState.Selected) == DrawItemState.Selected 選中行狀態嘛

看了e.State有e.State == DrawItemState.HotLight,不就是高亮的麽,於是開始擼代碼,加狀態判斷

Run

暈。。。沒變,這HotLight不起作用,好吧,問度娘。。。

翻山越嶺,跋山涉水。。。

找到這篇:https://www.jb51.cc/csharp/101121.html

其中提到:

   我在我的WinForms應用程式中使用OwnerDrawFixed作為DrawMode用於自定義ListBox控制項.當用戶將滑鼠懸停在列表框項目上時,我希望重新繪製ListBoxItem的背景(或執行其他操作),即在MouseMove …DrawItemState.HotLight永遠不適用於ListBox,所以我想知道如何模擬它,如何解決這個問題.

DrawItemState.HotLight永遠不適用於ListBox,是永遠。。。怎麼這麼遠。。。

繼續往下看:

解決方法

我花了兩年時間為你找到答案,但這裡是:

DrawItemState.HotLight僅適用於所有者繪製的菜單,而不適用於列表框.對於ListBox,您必須自己跟蹤項目:

public partial class Form1 : Form
{
  private int _MouseIndex = -1;
 
  public Form1()
  { InitializeComponent(); }
 
  private void listBox1_DrawItem(object sender,DrawItemEventArgs e)
  {
    Brush textBrush = SystemBrushes.WindowText;
 
    if (e.Index > -1)
    {
      if (e.Index == _MouseIndex)
      {
        e.Graphics.FillRectangle(SystemBrushes.HotTrack,e.Bounds);
        textBrush = SystemBrushes.HighlightText;
      }
      else
      {
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
          e.Graphics.FillRectangle(SystemBrushes.Highlight,e.Bounds);
          textBrush = SystemBrushes.HighlightText;
        }
        else
          e.Graphics.FillRectangle(SystemBrushes.Window,e.Bounds);
      }
      e.Graphics.DrawString(listBox1.Items[e.Index].ToString(),e.Font,textBrush,e.Bounds.Left + 2,e.Bounds.Top);
    }
  }
 
  private void listBox1_MouseMove(object sender,MouseEventArgs e)
  {
    int index = listBox1.IndexFromPoint(e.Location);
    if (index != _MouseIndex)
    {
      _MouseIndex = index;
      listBox1.Invalidate();
    }
  }
 
  private void listBox1_MouseLeave(object sender,EventArgs e)
  {
    if (_MouseIndex > -1)
    {
      _MouseIndex = -1;
      listBox1.Invalidate();
    }
  }
}

兄弟們,人家這花兩年時間解決的,應該有用,繼續再找找,又找到一篇洋文的:

https://stackoverflow.com/questions/1316027/listbox-drawitem-hotlight-state-in-the-ownerdraw-mode

It took me only two years to find the answer for you, but here it is:

The DrawItemState.HotLight only applies to owner drawn menus, not the listbox.

For the ListBox, you have to keep track of the item yourself:

看看,也是兩年,估計上面中文的從這個翻譯過來。

除了這倆,還真沒找到。

繼續擼代碼,果真管用。不過還是有問題,滑鼠滑快了,ListBox閃爍的厲害。

分析代碼  listBox1.Invalidate(); 這是刷新全部的。滑鼠滑過也就和本次選中和上次選中的有關係。

就刷這兩個Item就行,有了思路,擼代碼三連發:

        private int lastIndex = -1;
        private int mouseIndex = -1;

        [Browsable(false)]
        public int MouseIndex
        {
            get => mouseIndex;
            set
            {
                if (mouseIndex != value)
                {
                    if (lastIndex >= 0 && lastIndex != SelectedIndex)
                    {
                        OnDrawItem(new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(lastIndex), lastIndex, DrawItemState.Grayed));
                    }

                    mouseIndex = value;
                    if (mouseIndex >= 0 && mouseIndex != SelectedIndex)
                    {
                        OnDrawItem(new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(value), value, DrawItemState.HotLight));
                    }

                    lastIndex = mouseIndex;
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            MouseIndex = IndexFromPoint(e.Location);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            MouseIndex = -1;
        }

其中 new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(value), value, DrawItemState.HotLight) 

第一個參數Graphics,也找了一會兒,後來看這篇:

https://www.cnblogs.com/yuanyeguhong/archive/2013/09/20/3330606.html

 

其實就是Graphics對象的DrawString方法,而參數e中的Graphics是如何來的呢。
我們接著分析DrawItemEventArgs這個類,他既然是對listBox1某一項的屬性的打包,
那麼我估計其中的Graphics對象就是由listBox1.creatgraphics而來的。
好了,到此我們就可以自定義重繪listbox某項的函數了,可任意調用的哦!

好了,至此,問題都已找到答案,再捋一下思路,把邏輯理順。擼代碼,調試,OK!!!

主要代碼如下:

protected override void OnDrawItem(DrawItemEventArgs e)
        {
            base.OnDrawItem(e);

            BeforeDrawItem?.Invoke(this, Items, e);
            if (Items.Count == 0)
            {
                return;
            }

            bool otherState = e.State == DrawItemState.Grayed || e.State == DrawItemState.HotLight;
            if (!otherState)
            {
                e.DrawBackground();
            }

            if (e.Index < 0 || e.Index >= Items.Count)
            {
                return;
            }

            StringFormat sStringFormat = new StringFormat();
            sStringFormat.LineAlignment = StringAlignment.Center;

            bool isSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
            Color backColor = isSelected ? ItemSelectBackColor : BackColor;
            Color foreColor = isSelected ? ItemSelectForeColor : ForeColor;

            Rectangle rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1);
            if (!otherState)
            {
                e.Graphics.FillRectangle(BackColor, e.Bounds);
                e.Graphics.FillRoundRectangle(backColor, rect, 5);
                e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
            }
            else
            {
                if (e.State == DrawItemState.Grayed)
                {
                    backColor = BackColor;
                    foreColor = ForeColor;
                }

                if (e.State == DrawItemState.HotLight)
                {
                    backColor = HoverColor;
                    foreColor = ForeColor;
                }

                e.Graphics.FillRectangle(BackColor, e.Bounds);
                e.Graphics.FillRoundRectangle(backColor, rect, 5);
                e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
            }

            AfterDrawItem?.Invoke(this, Items, e);
        }

看,DrawItemState.HotLight咱也給實現了,DrawItemState.Grayed 我是隨便選的狀態,區別於其他。

想看全部代碼,看我的開源項目吧,https://gitee.com/yhuse/SunnyUI ,哎,客官別走嘛,點個Star先。

 

原創文章,轉載請保留鏈接 Sunny's blog


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 準備鏡像 我使用的centos系統,docker-ce最新版本。 先準備好三個鏡像 docker pull mysql:5.7 docker pull php:5.6-fpm docker pull nginx:latest 註意,mysql和php不要使用最新版本,坑很多。 docker imag ...
  • 在上一篇文章中我們介紹了JDK1.8的新特性有以下幾項。 1.Lambda表達式 2.方法引用 3.函數式介面 4.預設方法 5.Stream 6.Optional類 7.Nashorm javascript引擎 8.新的日期時間API 9.Base64 並且學習了JDK1.8最重要的特性--Lam ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 Step1:基礎數據準備(通過爬蟲獲取到),以下是從第一期03年雙色球開獎號到今天的所有數據整理,截止目前一共2549期,balls.txt 文件內容如下 : 備註:想要現成 ...
  • 給大家分享這幾個月整理出來的Java程式員面試筆試真題,順便給大家分享一本電子書《Java程式員面試筆試寶典》需要的可以掃描文末的二維碼即可,話不多說給大家看看部分截圖。 ...
  • 這份資源我自己歷經三年才整理歸類出來,現在免費分享給大家; 面試題有:螞蟻金服、拼多多、阿裡雲、百度、唯品會、攜程、豐巢科技、樂信、軟通動力、OPPO、銀盛支付、中國平安等初,中級,高級Java面試題集合。 面試題以及答案,已經整理成PDF電子書形式打包在網盤; 面試題領取微信掃一掃,加好友請備註“ ...
  • 在秒殺,搶購等併發場景下,可能會出現超賣的現象,在 PHP 語言中並沒有原生提供併發的解決方案,因此就需要藉助其他方式來實現併發控制。 列出常見的解決方案有: 使用隊列,額外起一個進程處理隊列,併發請求都放到隊列中,由額外進程串列處理,併發問題就不存在了,但是要額外進程支持以及處理延遲嚴重,本文不先 ...
  • 6.32(游戲:贏取雙骰子賭博游戲的機會)修改編程練習題6.30使該程式運行10000次,然後顯示贏得游戲的次數 6.32(Game: chance of winning at craps)Revise Exercise 6.30 to run it 15,000 times and display ...
  • 異常有可能導致某些資源沒有釋放到,這時可以使用using或者finally來釋放資源。 有些異常的可能會間歇性的發生,不影響業務運行的,可以視為正常的邏輯,那在異常可能發生前,應該使用判斷邏輯。 if (conn.State != ConnectionState.Closed) { conn.Clo ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...