Мне нужно создать приложение на основе диалогов вместо старого дизайна типа CFormView. Но CDialog создает диалоги фиксированного размера. Как я могу создавать приложения на основе диалогов с изменяемыми размерами диалогов?
Возможно, добавьте к этому тег Win32, материал RC-файла - это базовый Win32, а не даже MFC.
@Aardvark: материал RC может не быть специфичным для MFC, но в заголовке указывается MFC, CDialog (указанный в вопросе) - это класс MFC (см. Справку MSVS), и некоторые хорошие ответы требуют значительного взаимодействия с методами MFC - так что это был прав, оставив это в силе. Что касается C++, MSVS генерирует код C++ для MFC, но делает ли он это для любого другого языка? В противном случае [C++] был не совсем неуместным - но излишним, так что честно.
@PJTraill Право оставлять то, что стоит, тег MFC? Я предложил (может быть, много лет назад, почему вы сейчас вмешиваетесь в это?) Добавить тег win32 / winapi, а не удалять тег MFC.
@Aardvark: Да, правильно, чтобы метка оставалась неизменной. Я ответил, потому что использовал "Даже не для MFC" для обозначения всего вопроса. Я не думаю, что возраст комментария имеет значение. Мой комментарий был столько же для всех, кто думает о вопросе + комментарии + теги, так и для вас, надеюсь, вас не выставили.





Нет простого способа сделать это. По сути, вам нужно будет динамически разметить элементы управления при изменении размера окна.
См. Пример http://www.codeproject.com/KB/dialog/resizabledialog.aspx.
В файле ресурсов 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, чтобы управлять изменением размера и расположением элементов управления в диалоговом окне.
Я нет рекомендую вам редактировать файлы .rc напрямую - хотя формат кажется достаточно простым, синтаксический анализатор очень привередлив. Кроме того, поскольку вы используете MFC, можно с уверенностью предположить, что вы также используете Visual Studio. В этом случае вы должны просто открыть ресурс диалогового окна в Visual Studio и в свойствах диалогового окна выбрать «Изменение размера» для свойства «Граница».
Я пробовал много библиотек компоновки MFC и нашел эту: http://www.codeproject.com/KB/dialog/layoutmgr.aspx. Ознакомьтесь с комментариями, чтобы узнать о некоторых исправлениях ошибок и улучшениях (отказ от ответственности: некоторые из них сделаны мной;)). Когда вы используете эту библиотеку, установка правильных флагов изменения размера вашего окна выполняется за вас.
Если вы используете шаблон диалогового окна, откройте его в редакторе ресурсов и установите для свойства Стиль значение Выскакивать, а для свойства Граница - значение Изменение размера. Я почти уверен, что это сделает то же самое, что сказал Юссидж, и установит стили WS_POPUP и WS_THICKFRAME. Чтобы установить их динамически, переопределите функцию PreCreateWindow и добавьте следующее:
cs.style |= WS_POPUP | WS_THICKFRAME;
В дополнение к установке стиля WS_THICKFRAME вы, вероятно, также захотите иметь систему для перемещения и изменения размеров элементов управления в диалоговом окне при изменении размера диалогового окна. Для личного использования я создал базовый класс для замены CDialog, имеющего такую возможность. Унаследованный от этого класса, и в вашей функции InitDialog вызовите функцию AutoMove для каждого дочернего элемента управления, чтобы определить, насколько он должен перемещаться и насколько он должен изменять размер относительно родительского диалогового окна. Размер диалогового окна в файле ресурсов используется как минимальный.
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 <vector>
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<SMovingChild> 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);
}
+1 Приятно и просто использовать. Я написал это в блоге: Technical-recipes.com/…
@AndyUK, правильная ссылка - Technical-recipes.com/2011/…
У меня есть инструкции блога о том, как создать очень минималистичный диалог с изменяемым размером в MFC.
По сути, это реализация Сообщение Пауло Мессины на CodeProject но с удалением как можно большего количества посторонних вещей, просто чтобы прояснить, как это сделать лучше.
Это довольно просто реализовать, если вы немного попрактикуетесь: важны следующие моменты:
я. убедитесь, что в ваш проект включены его библиотеки CodeProject и т. д., и все это правильно компилируется.
II. выполните дополнительную инициализацию, требуемую внутри метода OnInitDialog: сделайте захват видимым, установите максимальный размер дилога, добавьте точки привязки к элементам управления диалогового окна, которые вы хотите «растянуть» и т. д.
iii. Замените использование CDialog на CResizableDialog в соответствующих точках: в определении класса диалога, конструкторе, DoDataExchange, BEGIN_MESSAGE_MAP, OnInitDialog и т. д.
Начиная с Visual Studio 2015, вы можете использовать Макет динамического диалогового окна MFC, но кажется, что нет способа ограничить размер диалогового окна минимальным размером (по-прежнему только старый способ умение обращатьсяWM_GETMINMAXINFO).
Динамический макет можно сделать:
Документация: Динамический макет
Вопрос не имеет отношения к C++. Следовательно, я удалил этот тег.