Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Visual C++ - расширенное программирование Пишем файловый менеджер. Часть 1.


Информационный Канал Subscribe.Ru


Visual C++ - расширенное программирование

Выпуск № 6
Cайт : SoftMaker.fatal.ru
Архив рассылки : SoftMaker.fatal.ru
Количество подписчиков : 36

В этом выпуске

От ведущего
MFC - простое и сложное
 Создание файлового менеджера (часть 1)

  Пролог
  Сплиттеры
Подписчикам
Вопросы
Ответы

От ведущего


  Здравствуйте, уважаемые подписчики.
  Рад сообщить вам, что в разделе "MFC - простое и сложное" начат новый цикл статей "Создание файлового менеджера", в которых будет подробно рассмотрен процесс разработки программы-аналога широко известного Windows Commander - а. Надеюсь, вам будет интересно.

  Как всегда, Вы можете отправить свои пожелания, кликнув по этой ссылке.

Искренне Ваш. С уважением, Вахтуров Виктор.

MFC - простое и сложное [Создание файлового менеджера (часть 1)].

Пролог.

  Как я писал в прошлой рассылке, сегодня мы начнем рассматривать новую тему.

  Хочу предложить вам интересное занятие - мы напишем файловый менеджер. Писать будем, конечно же, используя среду разработки Microsoft Visual C++ и библиотеку MFC.

  Сначала мы создадим интерфейс - "лицо" нашего программного продукта, а потом "наполним" его "мозгами".

  Не будем долго думать в отношении того, какой же интерфейс у нас будет. Классический образ пользовательского интерфейса файлового менеджера существует уже давно (со времен первых версий Norton Commander). Потом он был воспроизведен во многих программах-оболочках, работающих под DOS и унаследован программами-файловыми менеджерами, работающими под Windows. Итак, "центром" всего интерфейса будут, как обычно, две панели, имеющие одинаковый внешний вид (содержащие списки файлов и директорий, а также некоторые элементы управления) и несущие одинаковую функциональную нагрузку.

  Как я сказал выше, не будем далеко ходить за примером. К тому же учиться лучше воспроизводя некоторые классические вещи. Поэтому выберем в качестве образца именно такой классический пример - в своем роде образец среди программ данного класса - Windows Commander (сейчас он, правда, называется Total Commander, ибо дядя Билли очень заботится о чистоте восприятия логотипа своих форточек).
Так вот. Мы просто попытаемся в некоторой степени воспроизвести интерфейс Total Commander - а. На самом деле это совсем не трудно. На это у меня ушла всего пара часов. Но это если четко представлять себе что надо делать.
Обещаю вам, что после прочтения данного цикла статей вы сможете разрабатывать с помощью MFC пользовательские интерфейсы, гораздо более сложные чем у Total Commander.

  Итак, начнем.

  За основное правило в нашей работе мы примем принцип : "разделяй и властвуй". Мы будем делить задачу на части, а каждую часть - еще на части. И реализовывать последовательно то, что необходимо на данном этапе. Мы будем строить программу из модулей, которые с успехом могут быть использованы потом в других приложениях.

  Как я уже сказал, первое что должно быть у современного файлового менеджера - это две панели, отображающие содержимое каталогов дисков компьютера. Почему две (не одна, не три, а именно две) ? Как говорится, исторический опыт. Это самое удачное построение пользовательского интерфейса программ данной категории. Вспомните проводник Windows. Большинство людей пользуются им только тогда, когда под рукой нет ни одной, даже самой захудалой, но более удобной программы-оболочки или файлового менеджера.

  Еще раз взглянем на пользовательский интерфейс программы Total Commander.
Две панели, разделенные... Чем ? Вот об этом сегодня и пойдет речь.
О разделяемых окнах. О сплиттерах.


Сплиттеры.

  Прежде чем начать создавать наш проект, позвольте изложить немного теории (ибо, куда же без нее, родной).

  Наблюдая за развитием пользовательского интерфейса прикладных программ, работающих под управлением Windows, можно отметить явный прогресс в этой области за последние годы. Интерфейс действительно становится все более удобным и приятным, все более "дружественным". Все большую роль в этом процессе играют "неродные" Windows элементы управления, обладающие функциональностью, не реализованной в стандартных элементах и созданные разработчиками для решения специфических задач.

  Как ни странно, сплиттеры относятся именно к группе "нестандартных" элементов управления. Это значит, что не существует класса окна сплиттера, определяемого операционной системой, и в случае необходимости его (сплиттер) придется реализовывать самому. К счастью, фирмы - производители позаботились о нуждах программистов и в состав библиотек классов для построения пользовательского интерфейса обычно входят классы, инкапсулирующие функциональность разделяемых окон.

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

Остановимся на каждом типе более подробно.

  Дружественный сплиттер.

  Вы можете увидеть такой вид сплиттера довольно часто. Ярким примером приложения, использующего именно дружественный сплиттер является приложение справочной системы Windows hh.exe.
До появления Visual Studio NET и его справоцной системы, все файлы справки MSDN просматривались именно с помощью этого приложения. Запустите справку Windows, и вы поймете о чем я говорю.

  Обычно дружественный сплиттер - это окно, позиционирующееся между разделяемыми им окнами и имеющее одно с этими окнами родительское окно. При "захвате" мышкой этого окна, оно перемещается горизонтально или вертикально (в зависимости от того, какой - горизонтальный или вертикальный сплиттер), следуя за указателем мыши и, либо одновременно со своим движением (что приводит к частой перерисовке разделяемых окон), либо после "отпускания" изменяет размеры этих самых разделяемых окон. Недостатками использования такого сплиттера можно назвать возможные проблемы с перерисовкой как разделяемых окон, так и самого окна сплиттера, а также то, что обычно таким сплиттером можно "разделить" всего два окна. Попробуйте снова запустить справку Windows и подвинуть сплиттер сначала достаточно намного влево, а затем вправо - правее его первоначальной позиции. Я много раз наблюдал неперерисовавшиеся "следы" на полосе окна сплиттера.

  Иерархический сплиттер.

  Именно такой сплиттер реализован в MFC. Принцип работы такого сплиттера заключается в том, что сплиттер является родительским окном для всех "разделяемых" окон. То есть обычно при использовании такого сплиттера его позиционируют в пределах окна - рамки таким образом, чтобы он занимал всю ее клиентскую область, а окна, которые должны быть разделены сплиттером создают как дочерние окна самого сплиттера. При "перетаскивании" области разделения такой сплиттер обычно блокирует вывод на экран в прямоугольной области, занимаемой им функцией LockWindowUpdate и производит отрисовку "области перетаскивания". Минус такого подхода в том, что на время "перетаскивания" блокируется весь графический вывод во все "разделяемые" окна.
Но к преимуществам такого сплиттера можно отнести возможность "разделять" больше чем два окна сразу и по горизонтали и по вертикали. Иными словами, можно сформировать целую "матрицу" окон, которые будут позиционироваться в пределах окна сплиттера.

  На этом закончим лирическое отступление в область теории и приступим к практической работе.

  Для начала создадим проект.

  Создадим его при помощи обычного визарда ( MFC AppWizard (exe) ) Visual C++ для создания MFC - приложений.
Я назвал проект VCmd. Коротко и просто.
На первом шаге визарда выберем однодокументный тип приложения и отключим поддержку архитектуры Документ/Облик, сняв соответствующий флажок. Далее - все по умолчанию до шага №4 визарда. Здесь просто снимем флажок "Initial Status Bar". Так мы заранее избавились от строки состояния (в Total Commander её нет). Все. Можно нажать кнопку "готово". Проект создан. Откомпилировав его, увидим просто окно-рамку с панелью инструментов и меню. Панелью инструментов мы займемся позже, а сейчас хотелось бы видеть не что иное, как два окна, разделенные сплиттером.

  При создании проекта с поддержкой архитектуры Документ/Облик можно сразу создать окно, разделенное сплиттером. Можно даже создать нечто вроде "заготовки" проводника Windows, но во-первых, мы не хотим проводник. Во вторых, нам не нужны классы документов в нашем проекте - нам не нужна их сериализация и прочие возможности. Нам нужен легкий и элегантный каркас приложения. Вот этим и займемся.

  Прежде всего заметим, что добрые разработчики из Microsoft и тут оставили небольшой "след" архитектуры Документ/Облик. В проекте есть класс CChildView, понаследованный от класса CWnd. Это класс окна, создающегося в клиентской области окна - рамки и занимающего почти всю клиентскую область (за исключением области, занимаемой панелью инструментов).
Объект класса CChildView m_wndView является переменной-компонентой класса CMainFrame - класса главного окна рамки.

  Теперь избавимся от этого окна, заменив его сплиттером.

  Для этого :

 1. Удалим строку объявления переменной m_wndView из декларации класса CMainFrame в header-файле MainFrm.h и добавим вместо нее переменную m_wndSplitter, объект класса CSplitterWnd.

 2. Удалим из функции CMainFrame::OnCreate создание окна m_wndView. То есть удалим строки :

 if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
  CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
 {
  TRACE0("Failed to create view window\n");
  return -1;
 }

 3. В функциях CMainFrame::OnSetFocus и CMainFrame::OnCmdMsg переменную m_wndView заменим на m_wndSplitter.

 4. Добавим в класс CMainFrame еще две зашищенные (protected) переменные :

  CListCtrl  m_wndLeftPane;
  CListCtrl  m_wndRightPane;

  это пока будут окна - заглушки для того, чтобы их вставить в сплиттер и добиться правильного его поведения.

 5. Добавим при помощи инструмента ClassWizard функцию OnCreateClient в класс CMainFrame, в которой добавим следующий код для создания сплиттера и дочерних окон :

 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
 {
  if(!m_wndSplitter.CreateStatic(this, 1, 2))
    return FALSE;

  // Код создания списков, добавления в них колонок и установки расширенных
  // стилей потом, конечно же, будет заменен на код инициализации компонентов
  // файлового менеджера для отображения содержимого
  // каталогов, которые мы напишем впоследствии.

  if(!m_wndLeftPane.Create(WS_CHILD | WS_VISIBLE,
    CRect(0, 0, 0, 0), &m_wndSplitter,
    m_wndSplitter.IdFromRowCol(0, 0)))
    return FALSE;

  if(!m_wndRightPane.Create(WS_CHILD | WS_VISIBLE,
    CRect(0, 0, 0, 0), &m_wndSplitter,
    m_wndSplitter.IdFromRowCol(0, 1)))
    return FALSE;

  m_wndLeftPane.InsertColumn(0, "Name", LVCFMT_LEFT, 60, 0);
  m_wndLeftPane.InsertColumn(1, "Ext", LVCFMT_LEFT, 28, 1);
  m_wndLeftPane.InsertColumn(2, "Size", LVCFMT_LEFT, 32, 2);

  m_wndLeftPane.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

  m_wndRightPane.InsertColumn(0, "Name", LVCFMT_LEFT, 60, 0);
  m_wndRightPane.InsertColumn(1, "Ext", LVCFMT_LEFT, 28, 1);
  m_wndRightPane.InsertColumn(2, "Size", LVCFMT_LEFT, 32, 2);

  m_wndRightPane.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

  return CFrameWnd::OnCreateClient(lpcs, pContext);
 }

 Ну вот, мы видим радостную картину : окно-рамка, панель инструментов (в своем первозданном состоянии), сплиттер, разделитель которого "прилеплен" к одному краю окна...

  Не очень красиво. Не правда ли ?

  Можно переместить разделитель сплиттера как надо, но при изменении размеров главного окна-рамки разделитель сплиттера не будет перемещаться. То есть он (разделитель) имеет фиксированную позицию.
Печально. Ведь в Total Commander - е сплиттер сохраняет относительную позицию (процентное отношение ширины правого окна, находящегося в сплиттере к ширине левого окна неизменно). Но стандартный сплиттер MFC не поддерживает такой функциональности. Но на то проблемы и существуют, чтобы их решать.

  В следующей статье я расскажу о том, как доработать сплиттер MFC, добавив ему полезную функциональность.

    А пока Все.

Автор статьи : Вахтуров Виктор.  

Исходный код проекта, рассматриваемого в статье вы можете найти на сайте рассылки SoftMaker.fatal.ru на главной странице проекта.

Подписчикам

  Дабы заранее разрешить возможные недоразумения, прошу Вас помнить, что Вопросы публикуются в рассылке только один раз. Поэтому, если Вам не ответили в этой рассылке, или ваш вопрос не был опубликован, пришлите его еще раз. Не стоит отвечать на вопрос, который был задан в предыдущей рассылке (за исключением случая, когда он снова опубликован в этой).
Для того, чтобы задать свой вопрос, пришлите письмо по этой ссылке.
Для того, чтобы ответить на вопрос, надо кликнуть по ссылке "ответить", расположенной под текстом вопроса.
Обо всех ошибках, замеченных в данной рассылке, а также своих предложениях и пожеланиях пишите сюда.

Вопросы

  Для того, чтобы задать свой вопрос, кликните этой ссылке.
Вы можете задавать любые вопросы, касающиеся программирования на языке C и C++. Это могут быть вопросы касающиеся как конструкций языка, применения библиотек классов, шаблонов (таких как MFC или STL), использования компиляторов, так и самой философии программирования на C или C++. Здесь нет ограничений - спрашивайте и получайте ответы.

  К сожалению, вопросов сегодня нет.

Ответы

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

Всего доброго. До встречи в следующей рассылке.

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


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное