Как создать изменяемый CDialog в MFC?

Я должен создать приложение, основанное на диалоге, вместо старого типа дизайна CFormView. Но CDialog создает диалоги фиксированного размера. Как создать диалоговые приложения с изменяемыми диалогими?

В файле ресурсов RC, если диалог имеет этот стиль, похожий на это, будет фиксированный размер:

 IDD_DIALOG_DIALOG DIALOGEX 0, 0, 320, 201 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 

Если диалог имеет этот стиль, он будет значительным:

 IDD_DIALOG_DIALOG DIALOGEX 0, 0, 320, 201 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME 

Благодаря этим значительным параметрам кадра диалог будет значительным, но вам все равно придется выполнять большую работу по обработке сообщения WM_SIZE, чтобы управлять настройкой позиционирования элементов управления в диалоговом окне.

В дополнение к настройке стиля WS_THICKFRAME вы, вероятно, также захотите, чтобы система перемещала и изменяла размеры элементов управления в диалоговом окне при изменении размера диалога. Для моего личного использования я создал базовый class для замены CDialog, который имеет эту возможность. Вывод из этого classа и в функцию InitDialog функцию AutoMove для каждого дочернего AutoMove управления, чтобы определить, сколько он должен перемещаться и сколько он должен resize относительно родительского диалога. Размер диалога в файле ресурсов используется как минимальный размер.

BaseDialog.h:

 #if !defined(AFX_BASEDIALOG_H__DF4DE489_4474_4759_A14E_EB3FF0CDFBDA__INCLUDED_) #define AFX_BASEDIALOG_H__DF4DE489_4474_4759_A14E_EB3FF0CDFBDA__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include  class CBaseDialog : public CDialog { // Construction public: CBaseDialog(UINT nIDTemplate, CWnd* pParent = NULL); // standard constructor void AutoMove(int iID, double dXMovePct, double dYMovePct, double dXSizePct, double dYSizePct); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CBaseDialog) protected: //}}AFX_VIRTUAL protected: //{{AFX_MSG(CBaseDialog) virtual BOOL OnInitDialog(); afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); afx_msg void OnSize(UINT nType, int cx, int cy); //}}AFX_MSG DECLARE_MESSAGE_MAP() public: bool m_bShowGripper; // ignored if not WS_THICKFRAME private: struct SMovingChild { HWND m_hWnd; double m_dXMoveFrac; double m_dYMoveFrac; double m_dXSizeFrac; double m_dYSizeFrac; CRect m_rcInitial; }; typedef std::vector MovingChildren; MovingChildren m_MovingChildren; CSize m_szInitial; CSize m_szMinimum; HWND m_hGripper; }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_BASEDIALOG_H__DF4DE489_4474_4759_A14E_EB3FF0CDFBDA__INCLUDED_) 

BaseDialog.cpp:

 #include "stdafx.h" #include "BaseDialog.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CBaseDialog::CBaseDialog(UINT nIDTemplate, CWnd* pParent /*=NULL*/) : CDialog(nIDTemplate, pParent), m_bShowGripper(true), m_szMinimum(0, 0), m_hGripper(NULL) { } BEGIN_MESSAGE_MAP(CBaseDialog, CDialog) //{{AFX_MSG_MAP(CBaseDialog) ON_WM_GETMINMAXINFO() ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CBaseDialog::AutoMove(int iID, double dXMovePct, double dYMovePct, double dXSizePct, double dYSizePct) { ASSERT((dXMovePct + dXSizePct) <= 100.0); // can't use more than 100% of the resize for the child ASSERT((dYMovePct + dYSizePct) <= 100.0); // can't use more than 100% of the resize for the child SMovingChild s; GetDlgItem(iID, &s.m_hWnd); ASSERT(s.m_hWnd != NULL); s.m_dXMoveFrac = dXMovePct / 100.0; s.m_dYMoveFrac = dYMovePct / 100.0; s.m_dXSizeFrac = dXSizePct / 100.0; s.m_dYSizeFrac = dYSizePct / 100.0; ::GetWindowRect(s.m_hWnd, &s.m_rcInitial); ScreenToClient(s.m_rcInitial); m_MovingChildren.push_back(s); } BOOL CBaseDialog::OnInitDialog() { CDialog::OnInitDialog(); // use the initial dialog size as the default minimum if ((m_szMinimum.cx == 0) && (m_szMinimum.cy == 0)) { CRect rcWindow; GetWindowRect(rcWindow); m_szMinimum = rcWindow.Size(); } // keep the initial size of the client area as a baseline for moving/sizing controls CRect rcClient; GetClientRect(rcClient); m_szInitial = rcClient.Size(); // create a gripper in the bottom-right corner if (m_bShowGripper && ((GetStyle() & WS_THICKFRAME) != 0)) { SMovingChild s; s.m_rcInitial.SetRect(-GetSystemMetrics(SM_CXVSCROLL), -GetSystemMetrics(SM_CYHSCROLL), 0, 0); s.m_rcInitial.OffsetRect(rcClient.BottomRight()); m_hGripper = CreateWindow(_T("Scrollbar"), _T("size"), WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, s.m_rcInitial.left, s.m_rcInitial.top, s.m_rcInitial.Width(), s.m_rcInitial.Height(), m_hWnd, NULL, AfxGetInstanceHandle(), NULL); ASSERT(m_hGripper != NULL); if (m_hGripper != NULL) { s.m_hWnd = m_hGripper; s.m_dXMoveFrac = 1.0; s.m_dYMoveFrac = 1.0; s.m_dXSizeFrac = 0.0; s.m_dYSizeFrac = 0.0; m_MovingChildren.push_back(s); // put the gripper first in the z-order so it paints first and doesn't obscure other controls ::SetWindowPos(m_hGripper, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); } } return TRUE; // return TRUE unless you set the focus to a control } void CBaseDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { CDialog::OnGetMinMaxInfo(lpMMI); if (lpMMI->ptMinTrackSize.x < m_szMinimum.cx) lpMMI->ptMinTrackSize.x = m_szMinimum.cx; if (lpMMI->ptMinTrackSize.y < m_szMinimum.cy) lpMMI->ptMinTrackSize.y = m_szMinimum.cy; } void CBaseDialog::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); int iXDelta = cx - m_szInitial.cx; int iYDelta = cy - m_szInitial.cy; HDWP hDefer = NULL; for (MovingChildren::iterator p = m_MovingChildren.begin(); p != m_MovingChildren.end(); ++p) { if (p->m_hWnd != NULL) { CRect rcNew(p->m_rcInitial); rcNew.OffsetRect(int(iXDelta * p->m_dXMoveFrac), int(iYDelta * p->m_dYMoveFrac)); rcNew.right += int(iXDelta * p->m_dXSizeFrac); rcNew.bottom += int(iYDelta * p->m_dYSizeFrac); if (hDefer == NULL) hDefer = BeginDeferWindowPos(m_MovingChildren.size()); UINT uFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER; if ((p->m_dXSizeFrac != 0.0) || (p->m_dYSizeFrac != 0.0)) uFlags |= SWP_NOCOPYBITS; DeferWindowPos(hDefer, p->m_hWnd, NULL, rcNew.left, rcNew.top, rcNew.Width(), rcNew.Height(), uFlags); } } if (hDefer != NULL) EndDeferWindowPos(hDefer); if (m_hGripper != NULL) ::ShowWindow(m_hGripper, (nType == SIZE_MAXIMIZED) ? SW_HIDE : SW_SHOW); } 

Если вы используете шаблон диалога, откройте шаблон диалога в редакторе ресурсов и установите для свойства Style значение Popup и свойство Border для изменения размера . Я уверен, что это будет делать то же самое, что и сказал jussij, и установил стили WS_POPUP и WS_THICKFRAME. Чтобы установить их динамически, переопределите функцию PreCreateWindow и добавьте следующее:

 cs.style |= WS_POPUP | WS_THICKFRAME; 

Нет простого способа сделать это. В основном вам нужно будет динамически управлять макетами при изменении размера windows.

См. http://www.codeproject.com/KB/dialog/resizabledialog.aspx для примера.

Я пробовал много библиотек компоновки MFC и нашел это лучшим: http://www.codeproject.com/KB/dialog/layoutmgr.aspx . Ознакомьтесь с комментариями о некоторых исправлениях ошибок и улучшениях (отказ от ответственности: некоторые из них мной;)). Когда вы используете эту библиотеку, для вас будут установлены правильные флаги изменения размера в вашем окне.

У меня есть некоторые инструкции для блога о том, как создать очень минималистский диалог с возможностью изменения размера в MFC.

Это в основном реализация публикации Пауло Мессины в CodeProject, но с максимально возможным удалением посторонних материалов, чтобы помочь прояснить, как это сделать лучше.

Это довольно просто реализовать, как только у вас есть немного практики: важные бит:

я. убедитесь, что у вас есть библиотеки CodeProject и т. д., которые вставляются в ваш проект, и все они правильно компилируются.

II. выполните дополнительную инициализацию внутри метода OnInitDialog: сделайте захват видимым, установите максимальный размер дилога, добавьте опорные точки в элементы управления диалоговым окном, которые вы хотите «растянуть» и т. д.

III. Замените использование CDialog с помощью CResizableDialog в соответствующих точках: в определении classа диалога, конструкторе, DoDataExchange, BEGIN_MESSAGE_MAP, OnInitDialog и т. Д.

Начиная с Visual Studio 2015 вы можете использовать MFC Dynamic Dialog Layout , но, похоже, нет возможности ограничить размер диалогового windows минимальным размером (по-прежнему только старым способом, используя WM_GETMINMAXINFO ).

Динамическая компоновка может быть выполнена:

  • во время разработки в редакторе ресурсов, выбирая элемент управления и устанавливая свойства типа « Перемещение типа и размера» (это испускает новую секцию AFX_DIALOG_LAYOUT в файл .rc);
  • или программно, используя class CMFCDynamicLayout .

Документация: динамическая компоновка

  • Использование глобальной клавиатуры (WH_KEYBOARD_LL) в WPF / C #
  • Как создать контекст рендеринга OpenGL с прозрачным фоном?
  • Создание прозрачного windows в C ++ Win32
  • IntPtr, SafeHandle и HandleRef - Разъяснения
  • Невозможно преобразовать параметр из 'const char ' в 'LPCWSTR'
  • Как я могу получить дескриптор процесса по его имени в C ++?
  • Динамически загружать функцию из DLL
  • Системная ошибка. Код: 8. Недостаточно памяти для обработки этой команды
  • Как хранить и извлекать учетные данные из диспетчера учетных данных Windows Vault?
  • malloc () против HeapAlloc ()
  • Как отправить текст в Блокнот в C # / Win32?
  • Давайте будем гением компьютера.