Завершение диалога - PullRequest
       2

Завершение диалога

1 голос
/ 02 апреля 2011

Я использовал стандартный метод для переноса диалоговых процедур, используя статическую диалоговую процедуру в классе, и чисто виртуальную диалоговую процедуру, которая выводится позже.Это прекрасно работает, но у меня есть некоторые вопросы дизайна.Рассмотрим определение моей статической диалоговой процедуры:

INT_PTR __stdcall ModalDialog::router(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
{
    ModalDialog *thisPtr = 0;

    if (msg == WM_INITDIALOG)
    {
        thisPtr = reinterpret_cast< ModalDialog *>(lp);

        ::SetWindowLongPtr(dlg, DWLP_USER, reinterpret_cast< LONG_PTR >(thisPtr));

        thisPtr->_dlg = dlg;

        return static_cast< INT_PTR >(TRUE);
    }
    else
        thisPtr = reinterpret_cast< ModalDialog *>(::GetWindowLongPtr(dlg, DWLP_USER));

    if (thisPtr)
        //the virtual procedure from which to derive from
        return thisPtr->proc(msg, wp, lp);
    else
        //return false when not processing a message, look we should
        return static_cast< INT_PTR >(FALSE);
}

Допустим, я хочу добавить следующие виртуальные методы в базовый класс ModalDialog:

virtual bool onInitDialog(HWND dlg) = 0;
virtual bool onCommand(HWND dlg, int high_word, int low_word) = 0;
virtual bool onClose(HWND dlg) = 0;

Будет ли все в порядке, если яотказались от процедуры виртуального диалога и изменили статическое состояние следующим образом:

INT_PTR __stdcall ModalDialog::router(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
{
    ModalDialog *thisPtr = 0;

    if (msg == WM_INITDIALOG)
    {
        thisPtr = reinterpret_cast< ModalDialog *>(lp);

        ::SetWindowLongPtr(dlg, DWLP_USER, reinterpret_cast< LONG_PTR >(thisPtr));

        thisPtr->_dlg = dlg;

        //ADDED
        onInitDialog(dlg);

        return static_cast< INT_PTR >(TRUE);
    }
    else
        thisPtr = reinterpret_cast< ModalDialog *>(::GetWindowLongPtr(dlg, DWLP_USER));

    //ADDED
    switch (msg)
    {
    case WM_COMMAND:
        if (thisPtr && thisPtr->onCommand(dlg, HIWORD(wp), LOWORD(lp)))
            return static_cast< INT_PTR >(TRUE);
        break;
    case WM_CLOSE:
        if (thisPtr && thisPtr->onClose(dlg))
            return static_cast< INT_PTR >(TRUE);
        break;
    defualt:
        return static_cast< INT_PTR >(FALSE);

    //if (thisPtr)
    //    return thisPtr->proc(msg, wp, lp);
    //else
    //    return static_cast< INT_PTR >(FALSE);
}

Таким образом, в базовом классе мне нужно только переопределить виртуальные команды "on ..."?Я также заметил, что :: EndDialog (thisPtr -> _ dlg, 0) работает только на WM_CLOSE?Мне все еще нужно назначить _dlg из thisPtr следующим образом: thisPtr -> _ dlg = dlg?

Спасибо за любую помощь, которую вы можете оказать.

1 Ответ

2 голосов
/ 02 апреля 2011

Это дает вам меньшую гибкость - было бы лучше вызывать обработчики событий из виртуальной диалоговой процедуры, позволяющей вам переопределить поведение для отдельных подклассов. Если вы хотите, чтобы эти «обработчики событий» вызывались по умолчанию для всех подклассов ModalDialog, просто не делайте процедуру виртуального диалога чисто виртуальной - реализуйте ее также для ModalDialog и явно вызывайте ее из подклассов.

ModalDialog::dialogProc(...) {
  switch (...) {
  case ...: onInitDialog(...); break;
  }
}

ModalDialogSubClass::dialogProc(...) {
  switch (...) {
  case ...: break;
  default: return ModalDialog::dialogProc(...);
}

Учитывая этот сценарий, вы можете принять решение , а не , вызвать onInitDialog для определенного базового класса в dialogProc для этого базового класса.

Как правило, то, что вы хотите сделать в статической процедуре, это просто:

if (is first message) {
  SetWindowLong...
}
((ModalDialog *) GetWindowLong())->dialogProc(); // Also for the initial message
...