Frage

Ich habe eine dialogbasierte Anwendung zu erstellen, anstelle der alten CFormView Art von Design. Aber CDialog produziert feste Größe Dialoge. Wie kann ich dialogbasierte Anwendungen mit veränderbaren Dialogen erstellen?

War es hilfreich?

Lösung

In der RC-Ressource-Datei, wenn der Dialog diesen Stil ähnlich dazu wird es eine feste Größe werden:

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

Wenn der Dialog diesen Stil hat, wird es beträchtlich sein:

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

Mit diesen beträchtlichen Rahmenoptionen wird der Dialog erneut beträchtlich sein, aber Sie müssen noch eine Menge Arbeit tun Umgang mit der WM_SIZE Nachricht, die die Dimensionierung eine Positionierung der Kontrollen im Dialog zu verwalten.

Andere Tipps

Neben der Einrichtung, den Stil WS_THICKFRAME, werden Sie wahrscheinlich wollen auch ein System haben, um die Kontrollen in einem Dialog zu bewegen und die Größe, wie der Dialog der Größe verändert wird. Für meinen eigenen persönlichen Gebrauch habe ich eine Basisklasse erstellt CDialog zu ersetzen, die diese Fähigkeit hat. Man leitet von dieser Klasse und in Ihrer Funktion InitDialog die AutoMove Funktion für jedes Kind Rufsteuerung zu definieren, wie viel es bewegen und soll, wie viel es sollte auf den übergeordneten Dialog relative Größe ändern. Die Größe des Dialogs in der Ressource-Datei wird als Mindestgröße verwendet wird.

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);
}

Wenn ein Dialog Vorlage dann öffnen Sie das Dialogvorlage in dem Ressource-Editor und stellen Sie die Style Eigenschaft auf Popup und Border Immobilien Ändern der Größe . Ich bin mir ziemlich sicher, dass dies das gleiche tun wie das, was jussij sagte und legen Sie die WS_POPUP und WS_THICKFRAME Stile. Um überschreiben diese dynamisch dann die PreCreateWindow-Funktion und fügen Sie den folgenden:

cs.style |= WS_POPUP | WS_THICKFRAME;

Es gibt keine einfache Möglichkeit, dies zu tun. Grundsätzlich müssen Sie dynamisch Layout steuert, wenn die Fenstergröße verändert wird.

Siehe http://www.codeproject.com/KB/dialog/resizabledialog. aspx für ein Beispiel

Da Visual Studio 2015 , können Sie Handhabung WM_GETMINMAXINFO ).

Dynamische Layout kann getan werden:

  • zur Entwurfszeit in Ressource-Editor, indem Sie die Steuerung der Auswahl und Einstellung der Bewegen Typ und Sizing Typ Eigenschaften (dies emittiert neue AFX_DIALOG_LAYOUT in RC-Datei);
  • oder programmatisch die CMFCDynamicLayout mit Klasse .

Dokumentation: Dynamisches Layout

Ich habe viele MFC-Layout-Bibliotheken versucht und fanden, dass dieses eine der besten: http: //www.codeproject.com/KB/dialog/layoutmgr.aspx . Schauen Sie sich die Kommentare dort für einige Fehlerkorrekturen und Verbesserungen (Disclaimer: Einige von ihnen von mir;)). Wenn Sie diese Bibliothek verwenden, die korrekten Resize-Flaggen auf Ihrem Fenster Einstellung wird für Sie behandelt werden.

Ich habe einige Blog Anweisungen , wie man einen sehr minimalistischen Re-beträchtlicher Dialog in MFC erstellen.

Es ist im Grunde eine Implementierung von Paulo Messina Posting bei Codeproject aber mit so viel Fremd Sachen wie möglich entfernt, nur um zu helfen, zu klären, wie es besser zu machen.

Es ist ziemlich einfach zu implementieren, wenn Sie ein bisschen Übung gehabt haben: die wichtigen Bits sind:

i. sicherzustellen, haben Sie seine Codeproject Bibliotheken usw. in das Projekt gezogen und alles kompiliert korrekt.

ii. tun, um die zusätzliche Initialisierung in der OnInitDialog-Methode erforderlich. macht die Greifer sichtbar, die maximale DILOG Größe, Ankerpunkte an die Dialogsteuerung Elemente, die Sie wollen zu ‚strecken‘ usw. hinzufügen

iii. Ersetzen Verwendung von CDialog mit CResizableDialog an den entsprechenden Stellen: im Dialogklassendefinition, Konstruktor, DoDataExchange, BEGIN_MESSAGE_MAP, OnInitDialog usw.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top