我有一个很大的对话框,有一个子窗口 - 一个列表控件。当对话框重新调整大小时,我会重新调整列表控件的大小;它基本上固定在对话框的所有4个边上。问题是,在调整大小时,列表控件的边缘周围会出现明显的闪烁,尤其是当滚动条出现时。我是Win32 GUI中的新手,所以我不知道如何处理这个问题。我见过很多关于无闪烁绘图的文章,但它们都是关于个人自定义绘制的控件,而且它们都不涉及整个对话框的无闪烁绘图。我怎样才能使这个工作没有闪烁这么多?如何消除大型对话框上的闪烁?
我的实际对话框显然有多个控件,但这里是一个重现问题的最小代码示例(IDC_LIST1是报表视图中的列表控件,IDD_DIALOG2具有WS_CLIPCHILDREN样式集)。
#define NUM_COLUMNS 8
#define NUM_ROWS 32
RECT rcDialog2WindowOriginal;
RECT rcDialog2ClientOriginal;
RECT rcList1ClientOriginal;
INT_PTR Dialog2_OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
GetWindowRect(hDlg, &rcDialog2WindowOriginal);
GetClientRect(hDlg, &rcDialog2ClientOriginal);
GetWindowRect(GetDlgItem(hDlg, IDC_LIST1), &rcList1ClientOriginal);
ScreenToClient(hDlg, ((LPPOINT)&rcList1ClientOriginal));
ScreenToClient(hDlg, ((LPPOINT)&rcList1ClientOriginal) + 1);
SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
TCHAR szText[32];
// add some columns
LVCOLUMN col;
ZeroMemory(&col, sizeof(LVCOLUMN));
col.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
col.cx = 60;
col.pszText = szText;
for(int i = 0; i < NUM_COLUMNS; i++)
{
col.iSubItem = i;
_stprintf_s(szText, 32, _T("Column %d"), col.iSubItem);
SendDlgItemMessage(hDlg, IDC_LIST1, LVM_INSERTCOLUMN, col.iSubItem, LPARAM)&col);
}
// add some items
LVITEM item;
ZeroMemory(&item, sizeof(LVITEM));
item.mask = LVIF_TEXT;
item.pszText = szText;
for(int i = 0; i < NUM_ROWS; i++)
{
item.iItem = i;
for(int j = 0; j < NUM_COLUMNS; j++)
{
item.iSubItem = j;
_stprintf_s(szText, 32, _T("Item %d, SubItem %d"), i, j);
if(j == 0)
{
SendDlgItemMessage(hDlg, IDC_LIST1, LVM_INSERTITEM, 0, (LPARAM)&item);
}
else
{
SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETITEM, 0, (LPARAM)&item);
}
}
}
// autosize the columns
for(int i = 0; i < NUM_COLUMNS; i++)
{
SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE);
}
return TRUE;
}
INT_PTR Dialog2_OnGetMinMaxInfo(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
LPMINMAXINFO lpMinMaxInfo = (LPMINMAXINFO)lParam;
// don't allow dialog to be resized smaller than original size
lpMinMaxInfo->ptMinTrackSize.x = rcDialog2WindowOriginal.right - rcDialog2WindowOriginal.left;
lpMinMaxInfo->ptMinTrackSize.y = rcDialog2WindowOriginal.bottom - rcDialog2WindowOriginal.top;
return TRUE;
}
INT_PTR Dialog2_OnSize(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
int cx = LOWORD(lParam);
int cy = HIWORD(lParam);
// anchor the list control to all edges of the dialog
int left_delta = rcList1ClientOriginal.left - rcDialog2ClientOriginal.left;
int right_delta = rcDialog2ClientOriginal.right - rcList1ClientOriginal.right;
int top_delta = rcList1ClientOriginal.top - rcDialog2ClientOriginal.top;
int bottom_delta = rcDialog2ClientOriginal.bottom - rcList1ClientOriginal.bottom;
int left = left_delta;
int top = top_delta;
int width = cx - left_delta - right_delta;
int height = cy - top_delta - bottom_delta;
HWND hWndList1 = GetDlgItem(hDlg, IDC_LIST1);
SetWindowPos(hWndList1, NULL, left, top, width, height, SWP_NOZORDER);
return TRUE;
}
INT_PTR Dialog2_OnClose(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
EndDialog(hDlg, IDOK);
return TRUE;
}
INT_PTR CALLBACK Dialog2_DialogProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch(nMsg)
{
case WM_INITDIALOG:
return Dialog2_OnInitDialog(hDlg, wParam, lParam);
case WM_GETMINMAXINFO:
return Dialog2_OnGetMinMaxInfo(hDlg, wParam, lParam);
case WM_SIZE:
return Dialog2_OnSize(hDlg, wParam, lParam);
case WM_CLOSE:
return Dialog2_OnClose(hDlg, wParam, lParam);
}
return FALSE;
}
更新
在许多其它Windows应用程序(甚至是那些由微软写的)采取一看后,他们中的每单一个遭受同样闪烁的问题。从左上角的状态栏和滚动条调整窗口大小时尤其明显。我想我只能忍受它。
我真的没有任何闪烁(XP SP2,视觉风格开启和关闭)。哪个版本的Windows具有闪烁,并且Visual风格是否打开(exe文件中的清单)? – Anders 2009-10-11 21:56:03
XP SP3。我包含comctl32清单,但是我关闭了视觉样式。尝试从顶部/左侧而不是右下角调整大小;那是闪烁最差的地方。 – Luke 2009-10-11 22:25:26
是的,从顶部/左侧调整大小给出了一个“反弹”,它发生在大多数Windows应用程序,但我没有看到任何闪烁 – Anders 2009-10-12 14:55:01