C 如何消除大对话框上的闪烁?
我有一个相当大的对话框,有一个子窗口——一个列表控件。当对话框重新调整大小时,我会适当地重新调整列表控件的大小;它基本上固定在对话框的所有4条边上。问题在于,在调整大小的过程中,列表控件的边缘会出现明显的闪烁,尤其是当存在滚动条时。我是Win32 GUI方面的新手,所以我真的不知道如何处理这个问题。我看过很多关于无闪烁绘图的文章,但它们都是关于单个自定义绘制控件的,没有一篇文章作为一个整体处理对话框的无闪烁绘图。我怎样才能让它工作而不闪烁这么多 我的实际对话框显然有多个控件,但这里有一个最小的代码示例再现了这个问题(IDC_LIST1是报表视图中的列表控件,IDD_DIALOG2设置了WS_CLIPCHILDREN样式)C 如何消除大对话框上的闪烁?,c,windows,C,Windows,我有一个相当大的对话框,有一个子窗口——一个列表控件。当对话框重新调整大小时,我会适当地重新调整列表控件的大小;它基本上固定在对话框的所有4条边上。问题在于,在调整大小的过程中,列表控件的边缘会出现明显的闪烁,尤其是当存在滚动条时。我是Win32 GUI方面的新手,所以我真的不知道如何处理这个问题。我看过很多关于无闪烁绘图的文章,但它们都是关于单个自定义绘制控件的,没有一篇文章作为一个整体处理对话框的无闪烁绘图。我怎样才能让它工作而不闪烁这么多 我的实际对话框显然有多个控件,但这里有一个最小的代
#定义NUM_列8
#定义NUM_行32
RECT rcDialog2WindowOriginal;
直肠肾盂;
直肠直肠1脾阴道;
INT\u PTR对话框2\u ONINITALOG(HWND hDlg、WPARAM WPARAM、LPARAM LPARAM)
{
GetWindowRect(hDlg和rcDialog2WindowOriginal);
GetClientRect(hDlg和RCDialog2Clientorginal);
GetWindowRect(GetDlgItem(hDlg、IDC_列表1)和RCList1Client-ginal);
ScreenToClient(hDlg、((LPPOINT)和RCList1Client-ginal));
ScreenToClient(hDlg、((LPPOINT)和RCList1客户端)+1;
Senddlgit消息(hDlg、IDC_列表1、LVM_SETEXTENDEDLISTVIEWSTYLE、LVS_EX_FULLROWSELECT、LVS_EX_FULLROWSELECT);
TCHAR szText[32];
//添加一些列
LVCOL柱;
零内存(&col,sizeof(LVCOLUMN));
col.mask=LVCF_子项| LVCF_文本| LVCF_宽度;
cx=60;
col.pszText=szText;
对于(int i=0;iptMinTrackSize.x=rcDialog2WindowOriginal.right-rcDialog2WindowOriginal.left;
lpMinMaxInfo->ptMinTrackSize.y=rcDialog2WindowOriginal.bottom-rcDialog2WindowOriginal.top;
返回TRUE;
}
INT_PTR对话框2_OnSize(HWND hDlg、WPARAM WPARAM、LPARAM LPARAM)
{
int cx=低ORD(LPRAM);
int-cy=HIWORD(lParam);
//将列表控件锚定到对话框的所有边缘
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=左_delta;
int top=top_delta;
int width=cx-左_delta-右_delta;
int height=cy-顶部_delta-底部_delta;
HWND hWndList1=GetDlgItem(hDlg,IDC_列表1);
设置窗口位置(hWndList1、空、左、顶、宽、高、SWP_NOZORDER);
返回TRUE;
}
INT_PTR对话框2_OnClose(HWND hDlg、WPARAM WPARAM、LPARAM LPARAM)
{
EndDialog(hDlg、IDOK);
返回TRUE;
}
INT_PTR回调对话框2_DialogProc(HWND hDlg、UINT nMsg、WPARAM WPARAM、LPARAM LPARAM)
{
交换机(nMsg)
{
案例WM_初始化对话框:
返回对话框2_OnInitDialog(hDlg、wParam、lParam);
案例WM_GETMINMAXINFO:
返回对话框2_OnGetMinMaxInfo(hDlg、wParam、lParam);
案例WM_大小:
返回对话框2_OnSize(hDlg、wParam、lParam);
案例WM_结束:
返回对话框2_OnClose(hDlg、wParam、lParam);
}
返回FALSE;
}
更新
在查看了许多其他Windows应用程序(甚至是由Microsoft编写的应用程序)之后,每一个应用程序都会遇到同样的问题。当从左上角同时使用状态栏和滚动条调整窗口大小时,这一点尤为明显。我想我只能接受它。很多闪烁来自WM_ERASEBKGRD,处理这个消息并返回TRUE 你可以做几件事
- 处理你自己。您可能仍然需要擦除一些背景,但是您可以在窗口的边缘绘制4个矩形来填充对话框的背景区域,而不必在儿童控件所在的中间画出矩形。
- 调用SetWindowPos后,尝试调用UpdateWindow()立即重新绘制窗口(在列表视图控件和您自己的窗口上都尝试)。这样可以最大限度地缩短更改大小和完成重新绘制之间的时间
- 另一种方法是双缓冲(您将整个窗口表面绘制为屏幕外位图,并仅在完成后才将其绘制到屏幕上。这将最小化屏幕上更新过程开始和结束之间的时间,从而减少闪烁。但使用对话框和windows控件很难实现这一点,因此在您的情况下并不真正适用)
- 一般来说,不要这样做
#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; }
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_ERASEBKGND: // Lie and tell Windows that this window has cleared its background. return (-1); case WM_PAINT: // Lie and tell Windows that this window has completed all its painting. ValidateRect(hwnd, nullptr); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }