关于duilib CComboUI控件下拉框显示错误的问题

在ui资源文件中,如果包含了combo控件,如下:

<Combo name="cmb_http_proxy" width="183" height="34" font="1" itemfont="1" textpadding="11,0,0,0" normalimage="file='image\btn_set_normal.png' dest='153,2,183,32'" hotimage="file='image\btn_set_hover.png' dest='153,2,183,32'" pushedimage="file='image\btn_set_press.png' dest='153,2,183,32'" itemtextcolor="#FF333333" textcolor="#FF333333" itemselectedtextcolor="#FF333333" itemhottextcolor="#FF333333" bordersize="1" bordercolor="#FFD9D9D9" itemtextpadding="11,7,0,0" itemlinecolor="#FF333333">
  <ListLabelElement name="cmb_item_1" text="不使用代理"/>
  <ListLabelElement name="cmb_item_2" text="HTTP代理"/>
</Combo>

在窗体创建时,两个下拉选项会在create函数中创建出来,两个ListLabelElement的printmanager从combo控件赋值,combo的printmanager从窗体赋值,则ListLabelElement包含所有窗体所包含的属性,如字体等。
并且在combo属性中指定了itemfont属性,ListLabelElement 的高度就会根据该属性确定的字体大小自动计算,源码中的方法见下:

SIZE CListLabelElementUI::EstimateSize(SIZE szAvailable)
{
	if( m_pOwner == NULL ) return CDuiSize(0, 0);
	CDuiString sText = GetText();

	TListInfoUI* pInfo = m_pOwner->GetListInfo();
	SIZE cXY = m_cxyFixed;
	if( cXY.cy == 0 && m_pManager != NULL ) {
		cXY.cy = m_pManager->GetFontInfo(pInfo->nFont)->tm.tmHeight + 8;
		cXY.cy += pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
	}

	if( cXY.cx == 0 && m_pManager != NULL ) {
		RECT rcText = { 0, 0, 9999, cXY.cy };
		if( pInfo->bShowHtml ) {
			int nLinks = 0;
			CRenderEngine::DrawHtmlText(m_pManager->GetPaintDC(), m_pManager, rcText, sText, 0, NULL, NULL, nLinks, DT_SINGLELINE | DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
		}
		else {
			CRenderEngine::DrawText(m_pManager->GetPaintDC(), m_pManager, rcText, sText, 0, pInfo->nFont, DT_SINGLELINE | DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
		}
		cXY.cx = rcText.right - rcText.left + pInfo->rcTextPadding.left + pInfo->rcTextPadding.right;        
	}

	return cXY;
}

以下两句代码就确定了ListLabelElement 的高度

		cXY.cy = m_pManager->GetFontInfo(pInfo->nFont)->tm.tmHeight + 8;
		cXY.cy += pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;

其中GetFontInfo代码见下:

TFontInfo* CPaintManagerUI::GetFontInfo(int id)
{
	if (id < 0) return GetDefaultFontInfo();

	TCHAR idBuffer[16];
	::ZeroMemory(idBuffer, sizeof(idBuffer));
	_itot(id, idBuffer, 10);
	TFontInfo* pFontInfo = static_cast<TFontInfo*>(m_ResInfo.m_CustomFonts.Find(idBuffer));
	if (!pFontInfo) pFontInfo = static_cast<TFontInfo*>(m_SharedResInfo.m_CustomFonts.Find(idBuffer));
	if (!pFontInfo) pFontInfo = GetDefaultFontInfo();
	if (pFontInfo->tm.tmHeight == 0) 
	{
		HFONT hOldFont = (HFONT) ::SelectObject(m_hDcPaint, pFontInfo->hFont);
		::GetTextMetrics(m_hDcPaint, &pFontInfo->tm);
		::SelectObject(m_hDcPaint, hOldFont);
	}
	return pFontInfo;
}

确定控件高度是在创建下拉窗体时调用的,创建下拉窗体的方法见下:

void CComboWnd::Init(CComboUI* pOwner)
{
	m_bHitItem = false;
	m_pOwner = pOwner;
	m_pLayout = NULL;
	m_iOldSel = m_pOwner->GetCurSel();

	// Position the popup window in absolute space
	SIZE szDrop = m_pOwner->GetDropBoxSize();
	RECT rcOwner = pOwner->GetPos();
	RECT rc = rcOwner;
	rc.top = rc.bottom;		// 父窗口left、bottom位置作为弹出窗口起点
	rc.bottom = rc.top + szDrop.cy;	// 计算弹出窗口高度
	if( szDrop.cx > 0 ) rc.right = rc.left + szDrop.cx;	// 计算弹出窗口宽度

	SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
	int cyFixed = 0;
	for( int it = 0; it < pOwner->GetCount(); it++ ) {
		CControlUI* pControl = static_cast<CControlUI*>(pOwner->GetItemAt(it));
		if( !pControl->IsVisible() ) continue;
		SIZE sz = pControl->EstimateSize(szAvailable);
		cyFixed += sz.cy;
	}
	cyFixed += 4;
	rc.bottom = rc.top + MIN(cyFixed, szDrop.cy);

	::MapWindowRect(pOwner->GetManager()->GetPaintWindow(), HWND_DESKTOP, &rc);

	MONITORINFO oMonitor = {};
	oMonitor.cbSize = sizeof(oMonitor);
	::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
	CDuiRect rcWork = oMonitor.rcWork;
	if( rc.bottom > rcWork.bottom ) {
		rc.left = rcOwner.left;
		rc.right = rcOwner.right;
		if( szDrop.cx > 0 ) rc.right = rc.left + szDrop.cx;
		rc.top = rcOwner.top - MIN(cyFixed, szDrop.cy);
		rc.bottom = rcOwner.top;
		::MapWindowRect(pOwner->GetManager()->GetPaintWindow(), HWND_DESKTOP, &rc);
	}

	Create(pOwner->GetManager()->GetPaintWindow(), NULL, WS_POPUP, WS_EX_TOOLWINDOW, rc);
	// HACK: Don't deselect the parent's caption
	HWND hWndParent = m_hWnd;
	while( ::GetParent(hWndParent) != NULL ) hWndParent = ::GetParent(hWndParent);
	::ShowWindow(m_hWnd, SW_SHOW);
	::SendMessage(hWndParent, WM_NCACTIVATE, TRUE, 0L);
}

在创建窗体时,ListLabelElement 中的printmanager与combo中的相同,所有属性也与combo中的属性一致,但是在创建下拉窗体后(代码中Create(pOwner->GetManager()->GetPaintWindow(), NULL, WS_POPUP, WS_EX_TOOLWINDOW, rc);),会调到下拉窗体的初始化方法,在CComboWnd::HandleMessage中,见下:

if( uMsg == WM_CREATE ) {
	m_pm.SetForceUseSharedRes(true);
	m_pm.Init(m_hWnd);
	// The trick is to add the items to the new container. Their owner gets
	// reassigned by this operation - which is why it is important to reassign
	// the items back to the righfull owner/manager when the window closes.
	m_pLayout = new CVerticalLayoutUI;
	m_pLayout->SetManager(&m_pm, NULL, true);
	LPCTSTR pDefaultAttributes = m_pOwner->GetManager()->GetDefaultAttributeList(_T("VerticalLayout"));
	if( pDefaultAttributes ) {
		m_pLayout->ApplyAttributeList(pDefaultAttributes);
	}
	m_pLayout->SetInset(CDuiRect(1, 1, 1, 1));
	m_pLayout->SetBkColor(0xFFFFFFFF);
	m_pLayout->SetBorderColor(0xFFC6C7D2);
	m_pLayout->SetBorderSize(1);
	m_pLayout->SetAutoDestroy(false);
	m_pLayout->EnableScrollBar();
	m_pLayout->ApplyAttributeList(m_pOwner->GetDropBoxAttributeList());
	for( int i = 0; i < m_pOwner->GetCount(); i++ ) {
		m_pLayout->Add(static_cast<CControlUI*>(m_pOwner->GetItemAt(i)));
	}
	CShadowUI *pShadow = m_pOwner->GetManager()->GetShadow();
	pShadow->CopyShadow(m_pm.GetShadow());
	m_pm.GetShadow()->ShowShadow(m_pOwner->IsShowShadow());
	m_pm.AttachDialog(m_pLayout);
	m_pm.AddNotifier(this);
	return 0;
}

其中,在
m_pLayout->Add(static_cast<CControlUI*>(m_pOwner->GetItemAt(i)));
中会将传进来的ListLabelElement 控件的printmanager变量覆盖,此时会丢失掉combo的所有属性,包括字体属性等,在之后的窗体绘制中再次获取ListLabelElement 的高度属性时(前面的CListLabelElementUI::EstimateSize方法),此时的字体属性为空,字体高度返回默认值12,最终ListLabelElement 被绘制的高度与实际期望有所偏差,导致显示结果可能会有如下情形:
在这里插入图片描述
解决办法是在设置全局字体属性时,设置字体为共享字体,代码如下:

<Font id="1" name="微软雅黑" size="14" shared="true"/>

shared属性确定该字体为共享字体,此时,在CListLabelElementUI::EstimateSize方法获取字体属性时,在无法获取本地字体属性时,会获取共享字体,然后正确绘制ListLabelElement 的高度,效果如下:
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

砖农L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值