问题
Listboxes do not auto-resize. The best we've got is:
SendMessage(my_listbox, LB_SETHORIZONTALEXTENT, 1000, 0);
MS helpfully notes that "...a list box does not update its horizontal extent dynamically."
(why the heck not...but I digress)
How can the width be set dynamically to avoid truncating the text of a message longer than 1000px?
回答1:
if I understand the question... :-)
You'll essentially need to measure all of the items in the list box and calculate the maximum width of the list box contents, and then adjust the width of the listbox.
Here's some code from this project (that adds a automatic horizontal scrollbar to listboxes). This snippet is called when the font changes but it demonstrates (roughly) what's needed:
static void OnSetFont( HWND hwnd, HFONT hFont )
//
// Font has changed!
// We need to measure all of our items and reset the horizontal extent of the listbox
{
CData *pData = reinterpret_cast< CData * >( ::GetProp( hwnd, g_pcszDataProperty ) );
pData->m_hFont = hFont;
//
// Set up a HDC...
HDC hdc = GetDC( hwnd );
HGDIOBJ hOld = SelectObject( hdc, pData->m_hFont );
//
// Record the average width for use as our 'fudge factor' later.
TEXTMETRIC tm;
GetTextMetrics( hdc, &tm );
pData->m_nAvergeCharWidth = tm.tmAveCharWidth;
pData->m_nMaxWidth = 0;
//
// This is used as our item buffer. Saves us from having to handle the reallocation
// for different string lengths
CArray< TCHAR, TCHAR > arrBuffer;
//
// Quick reference to make the code below read better
CArray< int, int > &arrWidth = pData->m_arrItemWidth;
//
// The main loop. Iterate over the items, get their text from the listbox and measure
// it using our friendly little helper function.
const UINT uCount = arrWidth.GetSize();
for( UINT u = 0; u < uCount; u++ )
{
const int nLength = ::SendMessage( hwnd, LB_GETTEXTLEN, u, 0 );
arrBuffer.SetSize( nLength + 1 );
::SendMessage( hwnd, LB_GETTEXT, u, (WPARAM)arrBuffer.GetData() );
const int nItemWidth = BaseMeasureItem( pData, hwnd, hdc, arrBuffer.GetData() );
pData->m_arrItemWidth.SetAt( u, nItemWidth );
if( nItemWidth > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = nItemWidth;
}
}
//
// Now, either set the horizontal extent or not, depending on whether we think we need it.
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
else
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, 0, 0 );
}
//
// The usual release of resources.
SelectObject( hdc, hOld );
ReleaseDC( hwnd, hdc );
}
and...
static int BaseMeasureItem( CData *pData, HWND hwnd, HDC hdc, LPCTSTR pcszText )
//
// Measure and item and adjust the horizontal extent accordingly.
// Because the HDC is already set up we can just do it.
// We return the width of the string so our caller can use it.
{
SIZE size;
::GetTextExtentPoint32( hdc, pcszText, _tcslen( pcszText ), &size );
if( size.cx > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = size.cx;
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
}
return size.cx;
}
来源:https://stackoverflow.com/questions/13679277/listbox-change-width-dynamically