為CListBox加上智慧型水平滾動條

2021-03-31 08:56:58 字數 3826 閱讀 4681

在mfc中,用列表框(clistbox)來顯示多個字串是一種很方便的方法。但預設的列表框水平滾動條不夠智慧型——這裡智慧型的含義是:在應該出現的時候出現,不應該出現的時候消失,而且應能自動調節自己的大小。本文通過例項說明了存在的問題和解決辦法。

一、問題演示

首先用visual studio應用嚮導建立工程customclistbox。這是乙個基於對話方塊的應用,嚮導提供的所有可選引數均採用其預設值。

在資源編輯器中將對主話框字型設為宋體12,插入乙個clistbox控制,設其id為idc_llisttest,大小為125 x 84。 請確認列表框的垂直滾動條、水平滾動條有效,取消其排序風格。

啟動class wizard,選擇member variables選項卡,為列表框加入對應的成員變數m_llisttest,在category中選擇control。

接下來在workspace窗格中選擇classview,擴充套件ccustomclistboxdlg類並雙擊oninitdialog(),在編輯窗格中找到注釋行「todo: add extra initialization here」,在該行下面加入以下內容:

m_llisttest.addstring(_t("one"));

m_llisttest.addstring(_t("two"));

m_llisttest.addstring(_t("three"));

m_llisttest.addstring(_t("four"));

m_llisttest.addstring(_t("five"));

m_llisttest.addstring(_t("six"));

m_llisttest.addstring(_t("北國風光,千里冰封,萬里雪飄。"));

m_llisttest.addstring(_t("eight"));

m_llisttest.addstring(_t("nine"));

m_llisttest.addstring(_t("ten"));

編譯並執行這個工程,可以發現列表框能夠正確顯示全部內容。

如果在上述m_llisttext.addstring(_t"ten"))後面加入一行:

m_llisttest.addstring(_t("eleven"));

重新編譯並執行該工程,可以發現出現了乙個垂直滾動條。垂直滾動條的出現使得列表框水平方向有效顯示寬度變小,第七行的內容被切割而不能完整顯示。但此時水平滾動條並沒有自動出現,第七行被切割部分就無法看到了。

如果我們刪除最後加入的語句,把第七行漢字加長到超出列表框顯示寬度為止,也可以發現水平滾動條不會自動出現。被切割部分仍舊無法看到。

由此可知,clistbox的水平滾動條並不象垂直滾動條那樣「聰明」:垂直滾動條總是能夠在需要它的時候自動出現,並能夠自動調節自身大小,而水平滾動條不能。

二、解決問題

為提高**的可重用性,可以建立clistbox的派生類,在派生類中實現「智慧型」水平滾動條。需要考慮的主要問題包括:跟蹤最大字串寬度(應能適應不同場合下的字型變化),必要時計算垂直滾動條寬度,自動顯示和調節水平滾動條的大小。

選選單 insert/new class,設新建立類的名字為cdjlistbox,其基類為clistbox,其它選項採用預設值。單擊ok,visual studio自動生成djlistbox.cpp和djlistbox.h兩個檔案。

接下來將主對話方塊的列表框改為cdjlistbox型別,即在classview擴充套件ccustomlistboxdlg類並雙擊m_llisttest成員,在編輯窗格,修改

clistbox m_llisttest;

為: cdjlistbox m_llisttest;

然後,在類宣告**之前,插入

#include "djlistbox.h"

此時如果重新編譯並執行,是無法看到任何實質性的改變的,因為我們並沒有修改cdjlistbox。所有對於cdjlistbox的呼叫都直接傳遞給基類clistbox了。

跟蹤字串最大寬度可以通過覆蓋clistbox::addstring()實現。開啟djlistbox.h,緊接類的析構函式加入如下宣告:

int addstring( lpctstr lpszitem );

並在實現檔案djlistbox.cpp加入該函式框架:

int cdjlistbox::addstring(lpctstr lpszitem)

int m_nmaxwidth;

在djlistbox.cpp檔案,找到cdjlistbox的建構函式,為這個最大寬度作初始化:

m_nmaxwidth = 0;

現在可以改動新加入的addstring()了。先應該呼叫基類addstring(),並用nret記錄其返回值:

int nret = clistbox::addstring(lpszitem);

scrollinfo scrollinfo;

memset(&scrollinfo, 0, sizeof(scrollinfo));

scrollinfo.cbsize = sizeof(scrollinfo);

scrollinfo.fmask = sif_all;

getscrollinfo(sb_vert, &scrollinfo, sif_all);

在偵錯程式內觀察scrollinfo,可以發現要獲得nmax和npage的正確數值,列表框至少應含有乙個字串。scrollinfo的成員npage儲存了列表框「每頁」能夠顯示的專案數,nmax是列表框內專案總數。當nmax大於或等於npage,就出現了垂直滾動條。我們需要知道垂直滾動條的寬度以正確計算列表框的有效顯示寬度。這裡使用乙個初始值為0的整數nscrollwidth表示,並在垂直滾動條顯示時將它賦值:

int nscrollwidth = 0;

if(getcount() > 1 && ((int)scrollinfo.nmax

> = (int)scrollinfo.npage))

接下來宣告乙個size變數ssize,並例項化對話方塊的cclientdc:

size ssize;

cclientdc mydc(this);

對話方塊所採用的字型,有可能是預設字型,也有可能是有目的的選擇。在對話方塊編輯器中右擊對話方塊,並選擇properties可以檢視當前值。雖然mydc是從列表框取得的,但列表框字型資訊並未包含在mydc中。也就是說,對話方塊建立時所用字型並沒有「選入」cclientdc。要從gettextextentpoint32()獲得真正的字串大小,應該先呼叫getfont()獲得列表框的字型資訊,然後將此字型選入mydc,**為:

cfont* plistboxfont = getfont();

if(plistboxfont != null)

return nret;

編譯並執行新的**,可以看到水平滾動條終於能夠自動顯示了。

三、其它問題

在實際應用中,凡是改變列表框內容的函式都可能影響水平滾動條的顯示要求,因而也必須加以定製。但其基本過程——計算文字寬度並按指定大小顯示滾動條等,和上述討論過程是相似的。

clistbox類能夠改變列表內容的方法除addstring()外,還有deletestring(),insertstring(),resetcontent()。其中insertstring()用於在指定位置插入字串,在本文討論的主題內它和addstring()是一樣的。

int cdjlistbox::deletestring(uint nindex)

else

return nret;

} void cdjlistbox::resetcontent()

「後大資料」時代,給資料加上智慧型

今年是人工智慧大火之年,不僅有3月份alphago 與李世石的人機大戰讓普羅大眾知道了人工智慧的巨大進步,更有各種有關自動駕駛 無人汽車的新聞不斷給人工智慧 添柴加火 人工智慧的大火似乎讓大資料有些相形見絀。不過,在大資料專業人士talkingdata ceo崔曉波看來,人工智慧這一輪 也可以納入大...

企業為什麼要上智慧型倉儲系統?

智慧型倉儲裝備系統是綜合利用計算機 自動化 雲計算 網際網路和物聯網等高科技技術,將高位立體貨架 巷道堆垛機 公升降裝置 自動出入庫輸送裝備 自動分揀系統裝備 室內搬運車 機械人等裝置進行系統整合,形成具有一定感知能力 自行推理判斷能力 自動操作能力的智慧型系統。智慧型倉儲裝備系統具有管理系統化 操...

CRM怎樣才算得上智慧型化

with artificial intelligence,turn data into information.ai將資料轉換成有用的資訊。智慧型化和人工智慧現在變得炙手可熱,大家都宣傳 標榜自己的產品是ai賦能的 智慧型化的,那麼,什麼是ai,ai在crm中如何應用,基於ai的智慧型化如何實現?人...