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

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

Вопрос не имеет отношения к C++. Следовательно, я удалил этот тег.

Ashwin Nanjappa 26.09.2008 12:18

Возможно, добавьте к этому тег Win32, материал RC-файла - это базовый Win32, а не даже MFC.

Aardvark 26.09.2008 19:41

@Aardvark: материал RC может не быть специфичным для MFC, но в заголовке указывается MFC, CDialog (указанный в вопросе) - это класс MFC (см. Справку MSVS), и некоторые хорошие ответы требуют значительного взаимодействия с методами MFC - так что это был прав, оставив это в силе. Что касается C++, MSVS генерирует код C++ для MFC, но делает ли он это для любого другого языка? В противном случае [C++] был не совсем неуместным - но излишним, так что честно.

PJTraill 27.06.2016 17:20

@PJTraill Право оставлять то, что стоит, тег MFC? Я предложил (может быть, много лет назад, почему вы сейчас вмешиваетесь в это?) Добавить тег win32 / winapi, а не удалять тег MFC.

Aardvark 05.07.2016 17:34

@Aardvark: Да, правильно, чтобы метка оставалась неизменной. Я ответил, потому что использовал "Даже не для MFC" для обозначения всего вопроса. Я не думаю, что возраст комментария имеет значение. Мой комментарий был столько же для всех, кто думает о вопросе + комментарии + теги, так и для вас, надеюсь, вас не выставили.

PJTraill 05.07.2016 18:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
5
51 946
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

См. Пример 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 и в свойствах диалогового окна выбрать «Изменение размера» для свойства «Граница».

Nik Bougalis 30.11.2012 00:31

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

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

cs.style |= WS_POPUP | WS_THICKFRAME;
flounder.com/getminmaxinfo.htm has a visual example of changing the Border using the dialog's Properties (in the beginning of the page).
JHowzer 12.07.2012 17:53

В дополнение к установке стиля 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 27.08.2011 15:38

@AndyUK, правильная ссылка - Technical-recipes.com/2011/…

Mark Ransom 04.04.2012 07:46

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

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

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

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

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

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

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

Динамический макет можно сделать:

  • во время разработки в редакторе ресурсов путем выбора элемента управления и установки свойств Тип движения и Тип размера (это создает новый раздел AFX_DIALOG_LAYOUT в файле .rc);
  • или программно с использованием CMFCDynamicLayoutкласс.

Документация: Динамический макет

Другие вопросы по теме