Domanda

Devo creare un'applicazione basata su dialog, invece del vecchio tipo di design CFormView. Ma CDialog produce dialoghi di dimensioni fisse. Come posso creare applicazioni basate su finestre di dialogo con finestre di dialogo ridimensionabili?

È stato utile?

Soluzione

Nel file di risorse RC se la finestra di dialogo ha questo stile simile a questo, avrà dimensioni fisse:

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

Se la finestra di dialogo ha questo stile sarà considerevole:

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

Con queste opzioni di frame considerevoli la finestra di dialogo sarà ridimensionabile, ma sarà comunque necessario fare molto lavoro gestendo il messaggio WM_SIZE per gestire il dimensionamento di un posizionamento dei controlli all'interno della finestra di dialogo.

Altri suggerimenti

Oltre a impostare lo stile su WS_THICKFRAME , probabilmente vorrai anche avere un sistema per spostare e ridimensionare i controlli in una finestra di dialogo quando la finestra viene ridimensionata. Per uso personale ho creato una classe base per sostituire CDialog con questa funzionalità. Deriva da questa classe e nella tua funzione InitDialog chiama la funzione AutoMove per ciascun controllo figlio per definire quanto deve spostare e quanto deve ridimensionare rispetto alla finestra di dialogo principale. La dimensione della finestra di dialogo nel file di risorse viene utilizzata come dimensione minima.

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

Se si utilizza un modello di finestra di dialogo, aprire il modello di finestra di dialogo nell'editor delle risorse e impostare la proprietà Stile su Popup e la proprietà Bordo a Ridimensionamento . Sono abbastanza sicuro che questo farà lo stesso di quello che ha detto jussij e ha impostato gli stili WS_POPUP e WS_THICKFRAME. Per impostarli in modo dinamico, quindi sovrascrivere la funzione PreCreateWindow e aggiungere quanto segue:

cs.style |= WS_POPUP | WS_THICKFRAME;

Non esiste un modo semplice per farlo. Fondamentalmente, sarà necessario dinamicamente i controlli di layout quando si modificano le dimensioni della finestra.

Vedi http://www.codeproject.com/KB/dialog/resizabledialog. aspx per un esempio

Da Visual Studio 2015 , puoi utilizzare Layout della finestra di dialogo dinamica MFC , ma sembra che non ci sia modo di limitare la dimensione della finestra di dialogo alla dimensione minima (ancora solo alla vecchia maniera di gestione WM_GETMINMAXINFO ).

È possibile eseguire il layout dinamico:

  • in fase di progettazione nell'editor delle risorse selezionando il controllo e impostando le proprietà Tipo di movimento e Tipo di ridimensionamento (questo emette la nuova sezione AFX_DIALOG_LAYOUT in .rc file);
  • o in modo programmatico utilizzando la CMFCDynamicLayout class .

Documentazione: Layout dinamico

Ho provato molte librerie di layout MFC e ho trovato questa la migliore: http: //www.codeproject.com/KB/dialog/layoutmgr.aspx . Controlla i commenti lì per alcune correzioni di bug e miglioramenti (disclaimer: alcuni da me;)). Quando usi questa libreria, l'impostazione dei flag di ridimensionamento corretti sulla tua finestra verrà gestita per te.

Ho alcune istruzioni sul blog su come creare una finestra di dialogo ridimensionabile molto minimalista in MFC.

È sostanzialmente un'implementazione di La pubblicazione di Paulo Messina su CodeProject ma rimuovendo quante più cose estranee possibile, solo per chiarire come farlo meglio.

È abbastanza semplice da implementare una volta che hai avuto un po 'di pratica: i bit importanti sono:

i. assicurati di avere le sue librerie CodeProject ecc. inserite nel tuo progetto e che tutto si compili correttamente.

II. eseguire l'inizializzazione aggiuntiva richiesta all'interno del metodo OnInitDialog: rendere visibile la pinza, impostare la dimensione massima del dilog, aggiungere punti di ancoraggio agli elementi di controllo della finestra di dialogo che si desidera "allungare" ecc.

III. Sostituisci l'utilizzo di CDialog con CResizableDialog nei punti appropriati: nella definizione della classe di dialogo, costruttore, DoDataExchange, BEGIN_MESSAGE_MAP, OnInitDialog ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top