вторник, 11 февраля 2014 г.

Что-то вроде боли или сплиттер в диалоге

Сколько раз собирался, но это уже край) Хочу передать сердешный привет компании Microsoft с ее замечательным фреймворком для программирования на C++ под Windows - MFC (Microsoft Foundation Classes). Я не считаю себя гуру или даже профессионалом C++/Windows. Много раз сталкивался с этим тулом на мелких задачах и каждый раз он меня удивлял своей неоднозначностью. Иногда на нем задача решается элегантно, в 3 строки, которые, если лень, можно еще и обернуть в необходимые классы, нагенерив их Wizard'ом. А порой начинается ад: не понятно что, как и куда пихать, классы путаются с POD-струкрурами, StackOverflow радует примерами на чистом С. Ну так вот. Потом я познакомился с WindowForms в .Net Framework (что казалось полным трапом, ибо совсем все просто О_о ), затем Java с ее AWT/Swing, далее вовсе QtGui. Сердце подсказывало опасаться MFC и тратить время с пользой - собственно на winAPI.

Проект со злосчастным сплиттером - внутри




К ужасу или счастью, выпало мне снова взять в руки поделку MS. Ну теперь-то я уже не студентота копипастная, сейчас со всем разберусь! Первое, что удивляет - низкий полет над API, практически тонкие обертки над POD-структурами, которые, при некоторой доле фантазии отлично гоняются туда-сюда. Суть меняется от того слабо, ибо объекты ядра быть таковыми не перестали, а вот этот ООП-цирк - это лишь смена парадигм и использование перегрузок функций во все поля.

"Инструменты"


Вообще, общая организация - пародия на "как у людей": отдельный класс-приложение (да-да, WinMain скрыт в недрах MFC), минимум один класс окна, общий предок - класс CObject, возможность использовать архитектуру документ-вид (почти MV), метаинформация и даже (!!!) графический редактор форм (правда, только для диалогов). А вот дальше начинается ужас: единый файл с уникальными идентификаторами ресурсов (помимо ресурсов, контролы тоже помечаются ID), адовая кодогенерация с макросами той-самой метаинформации, обработчиков сообщений и черт знает чего еще. Еще и разделение на "диалоговые приложения" (dialog-based), одно- и многодокументные интерфейсы (SDI и MDI соответственно). Есть тонкие моменты, которые могут вам неожиданно кинуться в колеса. Например, моему маленькому мозгу так и не удалось ни найти, не придумать реально работающий вариант диалога с разделителем (Splitter). Пришлось идти по стопам вопиющих на 5-8 странице выдачи гугла, где советуют в диалоге уместить (!) фрейм (по сути, обычное окно), в котором сделать сплиттер, в части которого добавить вид (!!!). Ну, конечно, при этом нужно пробрасывать события (системые сообщения). Говорят, это самый простой способ. Еще и учитывая, что вид создается динамически где-то внутри.
// Мы в OnCreate диалога
// Создаем фрейм внутри диалога
frameWnd_ = new CFrameWnd;
frameWnd_->Create(strMyClass, L"", WS_CHILD, CRect(0,0,1,1), this, NULL, 0, NULL);
frameWnd_->ShowWindow(SW_SHOW);
frameWnd_->MoveWindow(0,0,600,600);

// Создаем сплиттер внутри фрейма внутри диалога
splitter_->CreateStatic(frameWnd_, 1, 2); // We need to go deeper...)

// Создаем одну из двух вьюх в сплиттере
// Обратите внимание на третий аргумент: в макрос мы передаем тип вьюхи, а ее экземпляр
// где-то там создается. Чтобы ей как-то управлять из диалога, нужно извернуться =)

splitter_->CreateView(0,0,RUNTIME_CLASS(CMyView), CSize(200,200), &cCreateContext);
//...

[caption id="attachment_618" align="center" width="478"]В MFC-диалоге сплиттер такой В MFC-диалоге сплиттер такой[/caption]

ЗЫ



В общем, было весело =) Для сравнения, как это реализовано в Qt, любопытные могут заглянуть в референс. Но печаль в том, что это делается в две строки - создание и добавление дочерних элементов методом QSplitter::AddWidget(QWidget*).



QSplitter *splitter = new QSplitter(parent);
QListView *listview = new QListView;
QTreeView *treeview = new QTreeView;
QTextEdit *textedit = new QTextEdit;
splitter->addWidget(listview);
splitter->addWidget(treeview);
splitter->addWidget(textedit);

Складывается крайне устойчивое впечатление, что MFC писался под какую-то конкретную задачу, если приходится отступать от парадигмы, которую диктует фреймворк, то решить задачу иногда становится проще на голом API системы. Ко всему прочему MFC скудно документирован (даже справочник в MSDN уступает референсу Qt, что уж говорить о адекватных семплах).


Линк к проекту сплиттера в диалоге MFC для внимательных =)


[caption id="attachment_598" align="aligncenter" width="300"]CSplitterWnd Плод стараний - CSplitterWnd с CView-потомками, внутри CFrameWnd, внутри потомка CDialog.[/caption]

Комментариев нет:

Отправить комментарий