日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

为CListBox加上智能水平滚动条

發(fā)布時(shí)間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为CListBox加上智能水平滚动条 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在MFC中,用列表框(CListBox)來顯示多個(gè)字符串是一種很方便的方法。但缺省的列表框水平滾動(dòng)條不夠智能——這里智能的含義是:在應(yīng)該出現(xiàn)的時(shí)候出現(xiàn),不應(yīng)該出現(xiàn)的時(shí)候消失,而且應(yīng)能自動(dòng)調(diào)節(jié)自己的大小。本文通過實(shí)例說明了存在的問題和解決辦法。

一、問題演示

首先用Visual Studio應(yīng)用向?qū)?chuàng)建工程CustomCListBox。這是一個(gè)基于對(duì)話框的應(yīng)用,向?qū)峁┑乃锌蛇x參數(shù)均采用其缺省值。

在資源編輯器中將對(duì)主話框字體設(shè)為宋體12,插入一個(gè)CListBox控制,設(shè)其ID為IDC_LLISTTEST,大小為125 X 84。 請(qǐng)確認(rèn)列表框的垂直滾動(dòng)條、水平滾動(dòng)條有效,取消其排序風(fēng)格。

啟動(dòng)Class Wizard,選擇Member Variables選項(xiàng)卡,為列表框加入對(duì)應(yīng)的成員變量m_lListTest,在Category中選擇Control。

接下來在Workspace窗格中選擇ClassView,擴(kuò)展CCustomCListBoxDlg類并雙擊OnInitDialog(),在編輯窗格中找到注釋行“TODO: Add extra initialization here”,在該行下面加入以下內(nèi)容:

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("北國風(fēng)光,千里冰封,萬里雪飄。"));
m_lListTest.AddString(_T("Eight"));
m_lListTest.AddString(_T("Nine"));
m_lListTest.AddString(_T("Ten"));

編譯并運(yùn)行這個(gè)工程,可以發(fā)現(xiàn)列表框能夠正確顯示全部內(nèi)容。

如果在上述m_lListText.AddString(_T"Ten"))后面加入一行:

m_lListTest.AddString(_T("Eleven"));

重新編譯并運(yùn)行該工程,可以發(fā)現(xiàn)出現(xiàn)了一個(gè)垂直滾動(dòng)條。垂直滾動(dòng)條的出現(xiàn)使得列表框水平方向有效顯示寬度變小,第七行的內(nèi)容被切割而不能完整顯示。但此時(shí)水平滾動(dòng)條并沒有自動(dòng)出現(xiàn),第七行被切割部分就無法看到了。

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

由此可知,CListBox的水平滾動(dòng)條并不象垂直滾動(dòng)條那樣“聰明”:垂直滾動(dòng)條總是能夠在需要它的時(shí)候自動(dòng)出現(xiàn),并能夠自動(dòng)調(diào)節(jié)自身大小,而水平滾動(dòng)條不能。

二、解決問題

為提高代碼的可重用性,可以創(chuàng)建CListBox的派生類,在派生類中實(shí)現(xiàn)“智能”水平滾動(dòng)條。需要考慮的主要問題包括:跟蹤最大字符串寬度(應(yīng)能適應(yīng)不同場合下的字體變化),必要時(shí)計(jì)算垂直滾動(dòng)條寬度,自動(dòng)顯示和調(diào)節(jié)水平滾動(dòng)條的大小。

選菜單 Insert/New Class,設(shè)新創(chuàng)建類的名字為CDJListBox,其基類為CListBox,其它選項(xiàng)采用缺省值。單擊OK,Visual Studio自動(dòng)生成DJListBox.cpp和DJListBox.h兩個(gè)文件。

接下來將主對(duì)話框的列表框改為CDJListBox類型,即在CLassView擴(kuò)展CCustomListBoxDlg類并雙擊m_lListTest成員,在編輯窗格,修改

CListBox m_lListTest;

為:

CDJListBox m_lListTest;

然后,在類聲明代碼之前,插入

#include "DJListBox.h"

此時(shí)如果重新編譯并運(yùn)行,是無法看到任何實(shí)質(zhì)性的改變的,因?yàn)槲覀儾]有修改CDJListBox。所有對(duì)于CDJListBox的調(diào)用都直接傳遞給基類CListBox了。

跟蹤字符串最大寬度可以通過覆蓋CListBox::AddString()實(shí)現(xiàn)。打開DJListBox.h,緊接類的析構(gòu)函數(shù)加入如下聲明:

int AddString( LPCTSTR lpszItem );

并在實(shí)現(xiàn)文件DJListBox.cpp加入該函數(shù)框架:

int CDJListBox::AddString(LPCTSTR lpszItem)
{
//此處加入字符串寬度跟蹤、水平滾動(dòng)條顯示等代碼
}

字符串寬度跟蹤可以用整形成員變量m_nMaxWidth實(shí)現(xiàn)。在DjListBox.h的protected聲明區(qū)內(nèi),加入以下一行:

int m_nMaxWidth;

在DJListBox.cpp文件,找到CDJListBox的建構(gòu)函數(shù),為這個(gè)最大寬度作初始化:

m_nMaxWidth = 0;

現(xiàn)在可以改動(dòng)新加入的AddString()了。先應(yīng)該調(diào)用基類AddString(),并用nRet記錄其返回值:

int nRet = CListBox::AddString(lpszItem);

接下來調(diào)用GetScrollInfo()以獲得垂直滾動(dòng)條的相關(guān)信息。這些信息是通過一個(gè)SCROLLINFO結(jié)構(gòu)傳遞的,下面是對(duì)該結(jié)構(gòu)初始化并調(diào)用GetScrollInfo()的代碼:

SCROLLINFO scrollInfo;
memset(&scrollInfo, 0, sizeof(SCROLLINFO));
scrollInfo.cbSize = sizeof(SCROLLINFO);
scrollInfo.fMask = SIF_ALL;
GetScrollInfo(SB_VERT, &scrollInfo, SIF_ALL);

在調(diào)試器內(nèi)觀察SCROLLINFO,可以發(fā)現(xiàn)要獲得nMax和nPage的正確數(shù)值,列表框至少應(yīng)含有一個(gè)字符串。SCROLLINFO的成員nPage保存了列表框“每頁”能夠顯示的項(xiàng)目數(shù),nMax是列表框內(nèi)項(xiàng)目總數(shù)。當(dāng)nMax大于或等于nPage,就出現(xiàn)了垂直滾動(dòng)條。我們需要知道垂直滾動(dòng)條的寬度以正確計(jì)算列表框的有效顯示寬度。這里使用一個(gè)初始值為0的整數(shù)nScrollWidth表示,并在垂直滾動(dòng)條顯示時(shí)將它賦值:

int nScrollWidth = 0;
if(GetCount() > 1 && ((int)scrollInfo.nMax
> = (int)scrollInfo.nPage))
{
nScrollWidth = GetSystemMetrics(SM_CXVSCROLL);
}

接下來聲明一個(gè)SIZE變量sSize,并實(shí)例化對(duì)話框的CClientDC:

SIZE sSize;
CClientDC myDC(this);

對(duì)話框所采用的字體,有可能是缺省字體,也有可能是有目的的選擇。在對(duì)話框編輯器中右擊對(duì)話框,并選擇Properties可以查看當(dāng)前值。雖然MyDC是從列表框取得的,但列表框字體信息并未包含在MyDC中。也就是說,對(duì)話框創(chuàng)建時(shí)所用字體并沒有“選入”CClientDC。要從GetTextExtentPoint32()獲得真正的字符串大小,應(yīng)該先調(diào)用GetFont()獲得列表框的字體信息,然后將此字體選入MyDC,代碼為:

CFont* pListBoxFont = GetFont();
if(pListBoxFont != NULL)
{
CFont* pOldFont =
myDC.SelectObject(pListBoxFont);

現(xiàn)在可以調(diào)用GetTextExtendPoint32()函數(shù)來獲得字符串的寬度了。字符串的寬度由sSize結(jié)構(gòu)的cx成員返回,將該值和已有最大寬度相比較:

GetTextExtentPoint32(myDC.m_hDC,
lpszItem, strlen(lpszItem), &sSize);
m_nMaxWidth = max(m_nMaxWidth, (int)sSize.cx);

剩下的重要工作之一,就是設(shè)置水平滾動(dòng)條的大小了。這可以通過調(diào)用SetHorizontalExtent()完成。如果傳遞給它的整形參數(shù)比列表框本身寬度小,則水平滾動(dòng)條被隱藏。

這里有一個(gè)容易被忽略的地方。如果仔細(xì)觀察CListBox,可以發(fā)現(xiàn)文本左邊有一欄小小的空白,它的大小為3 。這部分寬度應(yīng)該加到文本寬度上。如果希望在文本右邊也同樣空出一欄,則可以在文本寬度上再加3。

SetHorizontalExtent(m_nMaxWidth + 3);

在結(jié)束之前,我們需要為MyDC選入原有字體。原有字體保存在pOldFont中:

myDC.SelectObject(pOldFont); }

return nRet;

編譯并執(zhí)行新的代碼,可以看到水平滾動(dòng)條終于能夠自動(dòng)顯示了。

三、其它問題

在實(shí)際應(yīng)用中,凡是改變列表框內(nèi)容的函數(shù)都可能影響水平滾動(dòng)條的顯示要求,因而也必須加以定制。但其基本過程——計(jì)算文本寬度并按指定大小顯示滾動(dòng)條等,和上述討論過程是相似的。

CListBox類能夠改變列表內(nèi)容的方法除AddString()外,還有DeleteString(),InsertString(),ResetContent()。其中InsertString()用于在指定位置插入字符串,在本文討論的主題內(nèi)它和AddString()是一樣的。

DeleteString()刪除一個(gè)字符串,在派生類中其參考代碼如下:

int CDJListBox::DeleteString(UINT nIndex)
{
RECT lRect;
GetWindowRect(&lRect);

int nRet = CListBox::DeleteString(nIndex);

int nBoxWidth = lRect.right - lRect.left;
m_nMaxWidth = nBoxWidth;

SIZE sSize;
CClientDC myDC(this);

int i;
char szEntry[257];

for (i = 0; i nBoxWidth) // 顯示水平滾動(dòng)條
{
ShowScrollBar(SB_HORZ, TRUE);
SetHorizontalExtent(m_nMaxWidth);
}
else
{
ShowScrollBar(SB_HORZ, FALSE);
}
return nRet;
}

ResetContent()用于清除列表框的全部內(nèi)容。在派生類中其參考代碼如下:

void CDJListBox::ResetContent()
{
CListBox::ResetContent();

m_nMaxWidth = 0;
SetHorizontalExtent(0);
}

總結(jié)

以上是生活随笔為你收集整理的为CListBox加上智能水平滚动条的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。