Применение Windows API - [25]

Шрифт
Интервал

Без дальнейшей суеты приведем код WinMain, который осуществляет начальные установки.

>// Create top window class

>TopWinClassMaker topWinClass(WndProcMain, ID_MAIN, hInst, ID_MAIN);

>topWinClass.Register();


>// Create child pane classes

>WinClassMaker paneClass(WndProcPane, IDC_PANE, hInst);

>paneClass.SetSysCursor(IDC_IBEAM);

>paneClass.SetDblClicks();

>paneClass.Register();


>Splitter::RegisterClass(hInst);


>// Create top window

>ResString caption(hInst, ID_CAPTION);

>TopWinMaker topWin(caption, ID_MAIN, hInst);

>topWin.Create();

>topWin.Show(cmdShow);

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

Приведем оконную процедуру верхнего окна.

>LRESULT CALLBACK WndProcMain(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

> Controller* pCtrl = GetWinLong(hwnd);

> switch (message) {

> case WM_CREATE:

>  try {

>   pCtrl = new Controller(hwnd, reinterpret_cast(lParam));

>   SetWinLong(hwnd, pCtrl);

>  } catch (char const* msg) {

>   MessageBox(hwnd, msg, "Initialization", MB_ICONEXCLAMATION | MB_OK);

>   return -1;

>  } catch (...) {

>   MessageBox(hwnd, "Unknown Error", "Initialization", MB_ICONEXCLAMATION | MB_OK);

>   return -1;

>  }

>  return 0;

> case WM_SIZE:

>  pCtrl->Size(LOWORD(lParam), HIWORD(lParam));

>  return 0;

> case MSG_MOVESPLITTER:

>  pCtrl->MoveSplitter(wParam);

>  return 0;

> case WM_DESTROY:

>  SetWinLong(hwnd, 0);

>  delete pCtrl;

>  return 0;

> }

> return ::DefWindowProc(hwnd, message, wParam, lParam);

>}

Имеем обычную оконную процедуру за исключением одного сообщения: MSG_MOVESPLITTER. Это — наше собственное, определяемое пользователем сообщение, которое послано сплиттером его родительскому окну. Но сначала давайте взглянем на контроллер главного окна.

>class Controller {

>public:

> Controller(HWND hwnd, CREATESTRUCT* pCreat);

> ~Controller();

> void Size(int cx, int cy);

> void MoveSplitter(int x);

>private:

> enum { splitWidth = 8 }; // width of splitter

> // User Interface

> HWnd _hwnd;

> //Main controller window

> HWnd _leftWin;

> HWnd _rightWin;

> HWnd _splitter;

> int _splitRatio; // in per cent

> int _cx;

> int _cy;

>};

Контроллер содержит дескриптор своего окна, двух дочерних подокон, и окна сплиттера. Он также сохраняет текущий коэффициент разбиения, в процентах.

Конструктор контроллера отвечает за создание дочерних окон.

>Controller::Controller(HWND hwnd, CREATESTRUCT * pCreat) : _hwnd (hwnd), _leftWin (0), _rightWin (0), _splitter (0), _splitRatio (50) {

> // Create child windows

> {

>  ChildWinMaker leftWinMaker(IDC_PANE, _hwnd, ID_LEFT_WINDOW);

>  leftWinMaker.Create();

>  _leftWin.Init(leftWinMaker);

>  leftWinMaker.Show();

> }

> {

>  ChildWinMaker rightWinMaker(IDC_PANE, _hwnd, ID_RIGHT_WINDOW);

>  rightWinMaker.Create();

>  _rightWin.Init(rightWinMaker);

>  rightWinMaker.Show();

> }

> Splitter::MakeWindow(_splitter, _hwnd, ID_SPLITTER);

>}

Когда пользователь перемещает полоску расщепителя, родитель получает сообщение MSG_MOVESPLITTER . Параметр wParam содержит новое расстояние полосы расщепителя от левого края родительского окна. В ответ на такое сообщение, родитель должен также изменить размеры дочерних подокон и переместить расщепитель. Он делает это, вызывая метод Size.

>void Controller::MoveSplitter(int x) {

> _splitRatio = x * 100 / _cx;

> if (_splitRatio < 0) _splitRatio = 0;

> else if (_splitRatio > 100) _splitRatio = 100;

> Size(_cx, _cy);

>}

Вообще же, Size вызывается всякий раз, когда пользователь изменяет размеры основного окна, но тот код который вытолько что видели, мы вызываем также тогда, когда сплиттер перемещается.

>void Controller::Size(int cx, int cy) {

> _cx = cx;

> _cy = cy;

> int xSplit = (_cx * _splitRatio) / 100;

> if (xSplit < 0) xSplit = 0;

> if (xSplit + splitWidth >= _cx) xSplit = _cx - splitWidth;

> _splitter.MoveDelayPaint(xSplit, 0, splitWidth, cy);

> _leftWin.Move(0, 0, xSplit, cy);

> _rightWin.Move(xSplit+splitWidth, 0, cx-xSplit-splitWidth, cy);

> _splitter.ForceRepaint ();

>}

Обратите внимание на используемый здесь важный прием. Мы перемещаем расщепитель, но задерживаем его перерисовку до изменения его обоих подокон, расположенных слева и справа. Эта методика устраняет некоторое неприятное смазывание изображения.

Выше была представлена реализация клиентского кода. Теперь, я надеюсь, Вам будет интересно увидеть реализацию сплиттера.

Прежде всего нам приятно объединить зависимые функции в пространство имен. Вам видны вызовы Splitter::RegisterClass и Splitter::MakeWindow. Splitter в этих именах — это namespace.

>namespace Splitter {

> void RegisterClass(HINSTANCE hInst);

> void MakeWindow(HWnd& hwndSplitter /* out */, HWnd hwndParent, int childId);

>};

Ниже приводится реализация этих функций.

>LRESULT CALLBACK WndProcSplitter(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.