Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Переключение видов в сплиттере


Автор: voov 23.7.2008, 14:39
MDI приложение, сплиттер. Правый вид переключается между следующими видами 
Код

class CMnemoView : public CView
...

class CPropertiesView : public CFormView
...

Само переключение делаю так
Код

void CChildFrame::OnSwitchView()
{
    UINT nCmdID = LOWORD(GetCurrentMessage()->wParam);

    if (nCmdID == ID_SHOW_MNEMO && m_currentView == CURRENT_VIEW_MNEMO) return;
    if (nCmdID == ID_SHOW_PROPS && m_currentView == CURRENT_VIEW_PROPS) return;

    if (nCmdID == ID_SHOW_MNEMO) {
        m_wndSplitter.DeleteView(0, 1);
        m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMnemoView), CSize(100, 100), NULL);
        m_currentView = CURRENT_VIEW_MNEMO;

    } else if (nCmdID == ID_SHOW_PROPS) {
        m_wndSplitter.DeleteView(0, 1);
        m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CPropertiesView), CSize(100, 100), NULL);
        m_currentView = CURRENT_VIEW_PROPS;
    }

    m_wndSplitter.RecalcLayout();
}

Запускаю приложение и переключаюсь туда-сюда. Несколько переключений происходит нормально. На n-ом переключении вылетает на асерте в одном из этих видов
Код

    CMacDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

при этом в аутпуте пишутся такие варнинги
Код

Warning: Next pane is not a view - calling SetFocus.
Warning: Creating a pane with no CDocument.


В чем может быть дело?

Автор: voov 23.7.2008, 16:30
заметил, что переключаться можно сколь угодно долго, если вид не делать активным. Если клацнуть по виду (сделать его активным), то следующее переключение выбрасывает ассерт.

видимо, чтото неправильно сделал или чегото недоделал в переключении...

Автор: Earnest 24.7.2008, 07:35
А зачем ты их удаляешь-то? Создай один раз и просто показывай\прячь...
Ну, понятно, что объекты самому как-то менеджить придется, но не велика беда - посмотри в код сплиттера, там не так много, разберешься. Определи свой класс-наследник.

Автор: voov 24.7.2008, 10:05
А стандартным классом никак нельзя обойтись? Может подругому создавать нужно?

Автор: voov 24.7.2008, 10:43
хорошо. буду наследоваться от сплиттера. в каком направлении двигаться?

насоздавать объектов видов нужных классов, прятать и показывать их не проблема.
мне непонятно как прицепить все эти виды в нужную ячейку сплиттера
(стандартный сплиттер не дает прицепить больше 1го вида)

может туда фрейм вставить, а в фрейм все виды?

Автор: Earnest 25.7.2008, 10:25
Конечно, придется поизвращаться. Там вся фишка в том, что виды в сплиттере - это просто его чайлды, а доступается он к ним по их ид-ру, который получается из row\col. Т.е., чтобы создать еще один вид, нужно у старого поменять ид-р - на любой другой. 
Но это жуть как криво. Лучше действительно создать промежуточное окно (только не фрейм, просто наследник CWnd), и создать там все эти виды.  Это окно будет нормальной панелью сплиттера, а переключение видов нужно повесить на него.
Представь, что в панели сплиттера у тебя tab-control. Кстати, может действительно tab сделать? Или тебе принципиально, что юзер сам не мог переключить вид, а они показывалиь автоматом?

Автор: voov 25.7.2008, 16:50
Цитата

Там вся фишка в том, что виды в сплиттере - это просто его чайлды, а доступается он к ним по их ид-ру, который получается из row\col. Т.е., чтобы создать еще один вид, нужно у старого поменять ид-р - на любой другой.

Была сразу мысль переопределить метод получения ид из row\col, токо ж он не виртуальный smile.

Ну вобщем сделал. Сплиттер не переопределял. Унаследовался от окна, засунул туда виды. И показываю нужный.
Вот код кому интересно.

Код

class CSwitchPane : public CWnd
{
....
protected:
    CMnemoView* mnemo;
    CPropertiesView* properties;
public:
    void createViews(CCreateContext* pContext);
    void showMnemo(void);
    void showProperties(void);
    afx_msg void OnSize(UINT nType, int cx, int cy);
}


Код

void CSwitchPane::createViews(CCreateContext* pContext) {
    DWORD dwStyle = AFX_WS_DEFAULT_VIEW & ~WS_BORDER;
    CRect rect;
    GetWindowRect(&rect);
    rect -= rect.TopLeft();

    mnemo = new CMnemoView();
    ((CWnd*)mnemo)->Create(NULL, NULL, dwStyle, rect, this, IDC_MNEMO_VIEW_, pContext);
    mnemo->ShowWindow(SW_HIDE);

    properties = new CPropertiesView();
    ((CWnd*)properties)->Create(NULL, NULL, dwStyle, rect, this, IDC_PROPERTIES_VIEW_, pContext);
    properties->ShowWindow(SW_HIDE);
}

void CSwitchPane::showMnemo(void) {
    mnemo->ShowWindow(SW_SHOW);
    properties->ShowWindow(SW_HIDE);
}

void CSwitchPane::showProperties(void) {
    mnemo->ShowWindow(SW_HIDE);
    properties->ShowWindow(SW_SHOW);
}

void CSwitchPane::OnSize(UINT nType, int cx, int cy) {
    CWnd::OnSize(nType, cx, cy);

    if (mnemo) mnemo->MoveWindow(0, 0, cx, cy, FALSE);
    if (properties) properties->MoveWindow(0, 0, cx, cy, FALSE);
}


Создаю в фрейме так

Код

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{
.........
    if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CSwitchPane), CSize(100, 100), pContext)) {
        m_wndSplitter.DestroyWindow();
        return FALSE;
    } else {
        m_pSwitchPane = ((CSwitchPane*)m_wndSplitter.GetPane(0, 1));
    }
    m_wndSplitter.SetColumnInfo(0, 250, 50);

    m_pSwitchPane->createViews(pContext); 
    m_pSwitchPane->showMnemo();

    return TRUE;
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)