#include "StdAfx.h" #include "UITileLayout.h" namespace DuiLib { IMPLEMENT_DUICONTROL(CTileLayoutUI) CTileLayoutUI::CTileLayoutUI() : m_nColumns(1) { m_szItem.cx = m_szItem.cy = 0; } LPCTSTR CTileLayoutUI::GetClass() const { return _T("TileLayoutUI"); } LPVOID CTileLayoutUI::GetInterface(LPCTSTR pstrName) { if( _tcsicmp(pstrName, DUI_CTR_TILELAYOUT) == 0 ) return static_cast(this); return CContainerUI::GetInterface(pstrName); } SIZE CTileLayoutUI::GetItemSize() const { if(m_pManager != NULL) return m_pManager->GetDPIObj()->Scale(m_szItem); return m_szItem; } void CTileLayoutUI::SetItemSize(SIZE szItem) { if( m_szItem.cx != szItem.cx || m_szItem.cy != szItem.cy ) { m_szItem = szItem; NeedUpdate(); } } int CTileLayoutUI::GetColumns() const { return m_nColumns; } void CTileLayoutUI::SetColumns(int nCols) { if( nCols <= 0 ) return; m_nColumns = nCols; NeedUpdate(); } void CTileLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) { if( _tcsicmp(pstrName, _T("itemsize")) == 0 ) { SIZE szItem = { 0 }; LPTSTR pstr = NULL; szItem.cx = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr); szItem.cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); SetItemSize(szItem); } else if( _tcsicmp(pstrName, _T("columns")) == 0 ) SetColumns(_ttoi(pstrValue)); else CContainerUI::SetAttribute(pstrName, pstrValue); } void CTileLayoutUI::SetPos(RECT rc, bool bNeedInvalidate) { CControlUI::SetPos(rc, bNeedInvalidate); rc = m_rcItem; // 内边距调整 RECT rcInset = GetInset(); rc.left += rcInset.left; rc.top += rcInset.top; rc.right -= rcInset.right; rc.bottom -= rcInset.bottom; if (m_items.GetSize() == 0) { ProcessScrollBar(rc, 0, 0); return; } // 预留滚动条空间 if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) rc.right -= m_pVerticalScrollBar->GetFixedWidth(); if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight(); // ========== 核心:固定子控件尺寸(不再动态计算) ========== SIZE szItem = GetItemSize(); // 确保ItemSize有效,避免除0 if (szItem.cx <= 0) szItem.cx = 100; // 兜底默认宽度 if (szItem.cy <= 0) szItem.cy = 100; // 兜底默认高度 // ========== 核心:固定列数计算(基于固定宽度+水平间距) ========== int cxItemWithPadding = szItem.cx + m_iChildPadding; // 单个子控件占宽(含水平间距) m_nColumns = (rc.right - rc.left) / cxItemWithPadding; if (m_nColumns <= 0) m_nColumns = 1; // 滚动条兼容处理 if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) { int nTotalWidth = rc.right - rc.left + m_pHorizontalScrollBar->GetScrollRange(); m_nColumns = nTotalWidth / cxItemWithPadding; if (m_nColumns <= 0) m_nColumns = 1; } // 布局初始化 int cyNeeded = 0; int iCount = 0; POINT ptTile = { rc.left, rc.top }; // 垂直滚动条偏移 if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) ptTile.y -= m_pVerticalScrollBar->GetScrollPos(); // 水平滚动条偏移 int iPosX = rc.left; if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) { iPosX -= m_pHorizontalScrollBar->GetScrollPos(); ptTile.x = iPosX; } // ========== 遍历子控件:固定宽高+固定间距布局 ========== for (int it1 = 0; it1 < m_items.GetSize(); it1++) { CControlUI* pControl = static_cast(m_items[it1]); if (!pControl->IsVisible()) continue; if (pControl->IsFloat()) { SetFloatPos(it1); continue; } // ========== 核心1:固定子控件位置(无动态尺寸计算) ========== RECT rcTile = { ptTile.x, // 左 ptTile.y, // 上 ptTile.x + szItem.cx, // 右(固定宽度) ptTile.y + szItem.cy // 下(固定高度) }; // 忽略子控件自身padding,强制使用固定尺寸(如需保留padding可删除此段) // RECT rcPadding = pControl->GetPadding(); // rcTile.left += rcPadding.left; // rcTile.right -= rcPadding.right; // rcTile.top += rcPadding.top; // rcTile.bottom -= rcPadding.bottom; // ========== 核心2:强制子控件尺寸为ItemSize(覆盖所有动态计算) ========== RECT rcPos = { rcTile.left, rcTile.top, rcTile.left + szItem.cx, rcTile.top + szItem.cy }; pControl->SetPos(rcPos, bNeedInvalidate); // ========== 核心3:固定间距更新坐标 ========== iCount++; // 换行:重置X坐标,Y坐标 += 固定高度 + 垂直间距 if (iCount % m_nColumns == 0) { ptTile.x = iPosX; ptTile.y += szItem.cy + m_iChildPadding; // 垂直间距 = m_iChildPadding } // 不换行:X坐标 += 固定宽度 + 水平间距 else { ptTile.x += szItem.cx + m_iChildPadding; // 水平间距 = m_iChildPadding } // 更新总高度(用于滚动条) cyNeeded = ptTile.y - rc.top + szItem.cy; if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) cyNeeded += m_pVerticalScrollBar->GetScrollPos(); } // 处理滚动条 ProcessScrollBar(rc, 0, cyNeeded); } }