MFC에서 크기 조정 가능한 CDialog를 만드는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/138040

  •  02-07-2019
  •  | 
  •  

문제

이전 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, 대화 상자가 크기가 크게 조정 될 때 대화 상자에서 컨트롤을 움직이고 크기를 조정하는 시스템을 원할 수도 있습니다. 내 자신의 개인 용도를 위해 나는이 기능이있는 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);
}

대화 상자 템플릿을 사용하는 경우 리소스 편집기에서 대화 상자 템플릿을 열고 스타일 속성 팝업 그리고 국경 속성 크기 조정. 나는 이것이 무엇과 똑같이 할 것이라고 확신한다 Jussij WS_POPUP 및 WS_THICKFRAME 스타일을 말하고 설정하십시오. 이러한 동적으로 설정하려면 precreatewindow 함수를 무시하고 다음을 추가하십시오.

cs.style |= WS_POPUP | WS_THICKFRAME;

이 작업을 수행하는 쉬운 방법은 없습니다. 기본적으로 창 크기가 변경되면 동적 레이아웃 컨트롤이 필요합니다.

보다 http://www.codeproject.com/kb/dialog/resizabledialog.aspx 예를 들어

부터 Visual Studio 2015, 당신이 사용할 수있는 MFC 동적 대화 상자 레이아웃, 그러나 대화 상자 크기를 최소 크기로 제한하는 방법이없는 것 같습니다 (여전히 오래된 방법 만 손질 wm_getminmaxinfo).

동적 레이아웃을 수행 할 수 있습니다.

  • 컨트롤을 선택하고 설정하여 리소스 편집기의 설계 시간에 이동 유형 그리고 사이징 유형 속성 (이것은 새롭게 방출됩니다 AFX_DIALOG_LAYOUT .rc 파일로 섹션);
  • 또는 프로그래밍 방식을 사용합니다 cmfcdynamiclayout 수업.

선적 서류 비치: 동적 레이아웃

많은 MFC 레이아웃 라이브러리를 시도했는데 이것이 가장 좋은 것으로 나타났습니다. http://www.codeproject.com/kb/dialog/layoutmgr.aspx. 일부 버그 수정 및 개선 사항에 대해서는 의견을 확인하십시오 (면책 조항 : 일부는 나에 의해;)). 이 라이브러리를 사용하면 창에 올바른 크기 조정 플래그를 설정하면 처리됩니다.

나는 약간있다 블로그 지침 MFC에서 매우 미니멀리스트 재조정 대화 상자를 만드는 방법에 대해.

기본적으로 구현입니다 Codeproject에 Paulo Messina의 게시그러나 가능한 한 많은 외부 물건을 제거하면 더 나은 방법을 명확히하는 데 도움이됩니다.

약간의 연습을 한 후에는 구현하는 것이 매우 간단합니다. 중요한 비트는 다음과 같습니다.

나. 그의 코드 리젝트 라이브러리 등이 프로젝트에 들어가고 모든 것이 올바르게 컴파일되어 있는지 확인하십시오.

II. OninitDialog 메소드 내에서 필요한 추가 초기화를 수행하십시오. 그립퍼를 보이고 최대 딜로 크기를 설정하고 '스트레칭'등을 원하는 대화 상자 제어 항목에 앵커 포인트를 추가하십시오.

III. CDIALOG 사용을 적절한 지점에서 CresizableDialog로 바꾸십시오 : 대화 상자 클래스 정의, 생성자, dodataexchange, begin_message_map, oninitdialog 등.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top