Dialog ohne Template

jokey2

Erfahrenes Mitglied
Hallo Gemeinde

ich würde gerne einen Dialog völlig dynamisch, also ohne Template aus den Resourcen erzeugen. Es soll eine Message-Box werden, bei der man die Anzahl und die Texte der Buttons selber frei festlegen kann. Leider kriege ich das einfach nicht hin!

Bisher habe ich das so probiert:
Ich habe eine Klase von CWnd abgeleitet, die Im Konstruktor u.A. Informationen über die anzuzeigenden Buttons bekommt. Diese Klasse hat dann eine Funktion 'ShowMessageBox' in der das Fenster erzeugt und angezeigt werden soll:
Code:
int CExtMessageBox::ShowMessageBox()
{
 if(((m_iType & MB_EXTTYPEMASK) == MB_DYNAMIC) ||
  ((m_iType & MB_EXTTYPEMASK) == MB_YES_ALL_NO_ALL) ||
  ((m_iType & MB_EXTTYPEMASK) == MB_YES_ALL_NO_ALL_CANCEL))
  {
    CreateMessageBox();
    ShowWindow(SW_SHOW);
    EnableWindow();
    return RunModalLoop();
  }
  else
    return AfxMessageBox(m_cstrMessage, m_iType);
}
 
int CExtMessageBox::ShowMessageBox(LPCTSTR lpszText, UINT iType, LPCTSTR lpszButtonText)
{
  m_cstrMessage = lpszText;
  m_iType = iType;
  InitButtonTextList(lpszButtonText);
  return ShowMessageBox();
}
 
void CExtMessageBox::CreateMessageBox()
{
  //Titelzeile erzeugen
  CString cstrTitle;
  CWinApp *pParentApp = AfxGetApp();
  if(pParentApp)
    cstrTitle = pParentApp->m_pszAppName;
  else
  {
    TCHAR szAppName[_MAX_PATH];
    DWORD dwLen = GetModuleFileName(NULL, szAppName, _MAX_PATH);
    if (dwLen == _MAX_PATH)
      szAppName[_MAX_PATH - 1] = '\0';
    cstrTitle = szAppName;
  }
 
  //Fenster erzeugen
  if(m_pParent == NULL)
    m_pParent = AfxGetApp()->GetMainWnd();
  if(!CreateEx(WS_EX_CONTROLPARENT | WS_EX_DLGMODALFRAME | WS_EX_TOPMOST,
    NULL,
    cstrTitle,
    WS_CAPTION | WS_CHILD,
    EMB_MIN_SIZE_WND_RECT,
    m_pParent,
    EXT_MESSAGE_BOX_WND_ID,
    NULL))
  {
    AfxMessageBox("Error creating message box window!", MB_OK | MB_ICONEXCLAMATION);
    AfxThrowUserException();
    return;
  }
  //CStatic mit Text erzeugen
  CSize sizeStatic = GetDC()->GetOutputTextExtent(m_cstrMessage);
  CRect rectStatic(CPoint(EMB_STATIC_LEFT, EMB_STATIC_TOP), sizeStatic);
  if(!m_staticText.Create(m_cstrMessage, WS_CHILD | WS_VISIBLE | SS_CENTER, rectStatic, this))
  {
    AfxMessageBox("Error creating message box child window!", MB_OK | MB_ICONEXCLAMATION);
    DestroyWindow();
    AfxThrowUserException();
    return;
  }
  //Buttons erzeugen
  POSITION pos = m_listButtonText.GetHeadPosition();
  int iButtonID = ID_BUTTON_MIN;
  while(pos != NULL)
  {
    CString cstrText(m_listButtonText.GetNext(pos));
    CButton* pButton = new CButton();
    ASSERT(pButton != NULL);
    if(!pButton->Create(cstrText, WS_CHILD | WS_VISIBLE | WS_TABSTOP, EMB_SIZE_BUTTON_RECT, this, iButtonID))
    {
      AfxMessageBox("Error creating message box button!", MB_OK | MB_ICONEXCLAMATION);
      DeleteButtons();
      m_staticText.DestroyWindow();
      DestroyWindow();
      AfxThrowUserException();
      return;
    }
    m_listDynButtons.AddTail(pButton);
  }
 
  //Fenstergröße und -position errechnen und setzen
  //Länge der Button-Zeile
  int iButtonLineWidth = (EMB_BUTTON_WIDTH * (int)m_listDynButtons.GetCount()) +  (EMB_BUTTON_DIST * ((int)m_listDynButtons.GetCount() - 1));
  int iWindowWidth = rectStatic.Width() + (2 * EMB_STATIC_LEFT);
  int iButtonLeft;
  if((iButtonLineWidth + (2 * EMB_BUTTON_LEFT)) > iWindowWidth)
  {
    iButtonLeft = EMB_BUTTON_LEFT;
    iWindowWidth = iButtonLineWidth + (2 * EMB_BUTTON_LEFT);
    //Textposition neu setzen
    rectStatic.left = (iWindowWidth / 2) - (rectStatic.Width() / 2);
    m_staticText.MoveWindow(rectStatic, FALSE);
  }
  else
    iButtonLeft = (iWindowWidth / 2) - (iButtonLineWidth / 2);
 
  //Text anzeigen
  m_staticText.ShowWindow(SW_SHOW);
  //Buttonpositionen setzen und Buttons anzeigen
  POSITION posButton = m_listDynButtons.GetHeadPosition();
  while(pos != NULL)
  {
    CButton *pButton = m_listDynButtons.GetNext(pos);
    pButton->MoveWindow(iButtonLeft, rectStatic.bottom + EMB_VERT_DIST, EMB_BUTTON_WIDTH, EMB_BUTTON_HEIGHT, FALSE);
    pButton->ShowWindow(SW_SHOW);
    pButton->EnableWindow();
    iButtonLeft += EMB_BUTTON_WIDTH + EMB_BUTTON_DIST;
  }
}

Aus irgendeinem Grund haut das allerdings so nicht hin. Ist vielleicht auch nicht die beste Lösung, das mit einem CWnd zu machen. Ich hab's acuh mit einer von CDialog abgeleiteten Klasse versucht, aber da habe ich dann eben das Problem mit dem Template.

Was ich erreichen möchte ist, daß ich eine modale MessageBox anzeige, die mehr kann als die Standard-Windows-Messagebox. Außerdem wüßte ich prinzipiell gerne, ob es möglich ist, einen Dialog völlig Dynamisch, also ohne Template, zu erzeugen.

Kann mir evtl. der Eine oder Andere ein paar Tips geben, wie ich so etwas machen könnte? Ich wäre wie immer sehr dankbar.

P.S.: Es kann sein, daß die Berechnung der Größen und Positionen noch nicht stimmt, aber das ist erstmal zweitrangig. Darum werde ich mich kümmern, wenn ich den Dialog bzw. das Fenster angezeigt bekomme.
 
Hi Jokey2,

leite deine Klasse von CDialog ab.
Dem gibst du dann einfach ein leeres Template.

Nach dem du eine Instanz erzeugt hast, fügst du die Dimensionen und Stile deiner Controls hinzu und speicherst sie dir in deiner Klasse, erzeugen kannst du Sie hier noch nicht, da der Dialog selbst noch nicht erzeugt wurde.

Hast du alle Controls hinzugefügt, rufst du die DoModal()-Methode auf.

In der OnInitDialog() Methode kannst du dann alle deine Controls instanziieren und positionieren.

Das funktioniert. Habs selber schon mehrmals gemacht.

Wenn du Probleme hast, schreibs, ich schick dir dann mal n bissl Code!

Grüße,

Peter
 
Hallo,

im Prinzip läuft es darauf hinaus, die Methode "DoModal" zu überladen und dafür ein im Speicher generiertes Template zu verwenden. Initialisierung dann wie gehabt in "OnInitDialog()".
Hier mal der Code aus einem meiner Projekte:
C++:
int CMyDialog::DoModal() 
{
    DLGTEMPLATE dlgTempl;

    dlgTempl.style              = WS_CAPTION | WS_VISIBLE | WS_POPUP | DS_CENTER;
    dlgTempl.dwExtendedStyle    = WS_EX_DLGMODALFRAME;
    dlgTempl.cdit               = 0;
    dlgTempl.x                  = 0;
    dlgTempl.y                  = 0;
    dlgTempl.cx                 = 0;
    dlgTempl.cy                 = 0;

    int     nBufferSize = sizeof(DLGTEMPLATE) + (5 * sizeof(WORD));
    HLOCAL  hLocal      = LocalAlloc(LHND, nBufferSize);
    
    if (hLocal != NULL)
    {
        BYTE* pBuffer = (BYTE *)LocalLock(hLocal);
        
        if (pBuffer == NULL)
        {
            LocalFree(hLocal);
            return (-1);
        }

        memset(pBuffer, 0, nBufferSize);
        memcpy(pBuffer, &dlgTempl, sizeof(DLGTEMPLATE));

        InitModalIndirect((LPDLGTEMPLATE)pBuffer, m_pParent);
    
        int iRet = CDialog::DoModal();

        LocalUnlock(hLocal);
        LocalFree(hLocal);

        return iRet;
    }

    return (-1);
}
Gruß
MCoder
 
Vielen Dank für die prompten Antworten!

Ich muß ja gestern wie vernagelt gewesen sein! Ich habe jetzt tatsächlich einfach eine neue Klasse von CDialog abgeleitet, von der ich eine Instanz erzeugen kann, die ich einfach mit DoModal aufrufen kann.
Ich habe auch DoModal überschrieben, aber nur dahingehend, daß auch die normale Messagebox angezeigt werden kann, wenn als Typ z.B. MB_OK angegeben wird. In diesem Fall rufe ich nicht CDialog::DoModal auf sondern AfxMessageBox mit Typ und Text.

Was etwas störend ist, ist daß die Buttons OK und Abbrechen standardmäßig vorhanden sind. Die muß ich im InitInstance entfernen.
 

Neue Beiträge

Zurück