usar - winapi tutorial
¿Cómo crear un CDialog redimensionable en MFC? (7)
En el archivo de recursos RC si el diálogo tiene este estilo similar a este, será de tamaño fijo:
IDD_DIALOG_DIALOG DIALOGEX 0, 0, 320, 201
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
Si el diálogo tiene este estilo, será considerable:
IDD_DIALOG_DIALOG DIALOGEX 0, 0, 320, 201
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
Con estas opciones de cuadro de gran tamaño, el diálogo será re-dimensionable, pero aún tendrá que trabajar mucho manejando el mensaje WM_SIZE para administrar el tamaño y el posicionamiento de los controles dentro del cuadro de diálogo.
Tengo que crear una aplicación basada en un diálogo, en lugar del viejo tipo de diseño CFormView. Pero CDialog produce diálogos de tamaño fijo. ¿Cómo puedo crear aplicaciones basadas en diálogos con diálogos redimensionables?
He probado muchas bibliotecas de diseño MFC y encontré esta la mejor: http://www.codeproject.com/KB/dialog/layoutmgr.aspx . Echa un vistazo a los comentarios de algunas correcciones de errores y mejoras (descargo de responsabilidad: algunos de ellos por mí;)). Cuando use esta biblioteca, la configuración de los indicadores de cambio de tamaño correctos en su ventana se manejará por usted.
No hay una manera fácil de hacer esto. Básicamente, necesitará controles de diseño dinámicos cuando se cambie el tamaño de la ventana.
Consulte http://www.codeproject.com/KB/dialog/resizabledialog.aspx para ver un ejemplo
Además de configurar el estilo en WS_THICKFRAME
, también es probable que desee tener un sistema para mover y cambiar el tamaño de los controles en un cuadro de diálogo a WS_THICKFRAME
que se WS_THICKFRAME
el tamaño del cuadro de diálogo. Para mi uso personal, he creado una clase base para reemplazar el CDialog que tiene esta capacidad. Derive de esta clase y en su función InitDialog
, llame a la función AutoMove
para cada control secundario para definir cuánto debe moverse y cuánto debe redimensionarse en relación con el diálogo principal. El tamaño del diálogo en el archivo de recursos se usa como tamaño mínimo.
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);
}
Si usa una plantilla de diálogo, abra la plantilla de diálogo en el editor de recursos y establezca la propiedad Estilo en Emergente y la propiedad Borde en Redimensionar . Estoy bastante seguro de que esto hará lo mismo que lo que dijo jussij y establecerá los estilos WS_POPUP y WS_THICKFRAME. Para configurarlos dinámicamente, anule la función PreCreateWindow y agregue lo siguiente:
cs.style |= WS_POPUP | WS_THICKFRAME;
Tengo algunas instrucciones de blog sobre cómo crear un diálogo re-considerable muy minimalista en MFC.
Básicamente es una implementación de la publicación de Paulo Messina en CodeProject, pero con la mayor cantidad de elementos extraños eliminados como sea posible, solo para ayudar a aclarar cómo hacerlo mejor.
Es bastante fácil de implementar una vez que has tenido un poco de práctica: los bits importantes son:
yo. asegúrese de tener sus bibliotecas de CodeProject, etc., en su proyecto y todo se compila correctamente.
ii. realice la inicialización adicional requerida dentro del método OnInitDialog: haga que la pinza sea visible, configure el tamaño máximo de inserción, agregue puntos de anclaje a los elementos de control de diálogo que desea "estirar", etc.
iii. Reemplace el uso de CDialog con CResizableDialog en los puntos apropiados: en la definición de la clase de diálogo, constructor, DoDataExchange, BEGIN_MESSAGE_MAP, OnInitDialog, etc.
Desde Visual Studio 2015 , puede utilizar el diseño de cuadros de diálogo dinámicos de MFC , pero parece que no hay forma de restringir el tamaño del diálogo al tamaño mínimo (solo sigue el método anterior manejando WM_GETMINMAXINFO ).
El diseño dinámico se puede hacer:
- en el momento del diseño en el editor de recursos seleccionando el control y configurando las propiedades Tipo de desplazamiento y Tipo de tamaño (esto emite la nueva sección AFX_DIALOG_LAYOUT en el archivo .rc);
- o usando programáticamente la clase CMFCDynamicLayout .
Documentación: Diseño dinámico