Visual c - розширене програмування пишемо файловий менеджер


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

nbspnbspКак завжди, Ви можете відправити свої побажання, клікнувши по цьому посиланню.

Щиро Ваш. З повагою, Вахтуров Віктор.

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

nbspnbspКак я писав в минулому розсилці, сьогодні ми почнемо розглядати нову тему.

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

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

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

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

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

nbspnbspЕще раз поглянемо на призначений для користувача інтерфейс програми Total Commander.
Дві панелі, розділені. Чим. Ось про це сьогодні і піде мова.
Про поділюваних вікнах. Про спліттер.

Сплітери.

nbspnbspПрежде ніж почати створювати наш проект, дозвольте викласти трохи теорії (бо, куди ж без неї, рідної).

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

nbspnbspКак не дивно, сплітери відносяться саме до групи "нестандартних" елементів управління. Це означає, що не існує класу вікна спліттера, що визначається операційною системою, і в разі необхідності його (спліттер) доведеться реалізовувати самому. На щастя, фірми - виробники подбали про потреби програмістів і до складу бібліотек класів для побудови призначеного для користувача інтерфейсу зазвичай входять класи, инкапсулирующие функціональність поділюваних вікон.

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

Зупинимося на кожному типі більш докладно.

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

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

nbspnbspІменно такий спліттер реалізований в MFC. Принцип роботи такого спліттера полягає в тому, що спліттер є батьківським вікном для всіх "поділюваних" вікон. Тобто зазвичай при використанні такого спліттера його позиціонують в межах вікна - рамки таким чином, щоб він займав всю її клієнтську область, а вікна, які повинні бути розділені сплиттером створюють як дочірні вікна самого спліттера. При "перетягуванні" області поділу такої спліттер зазвичай блокує висновок на екран в прямокутної області, яку він обіймав функцією LockWindowUpdate і виробляє отрисовку "області перетягування". Мінус такого підходу в тому, що на час "перетягування" блокується весь графічний висновок в усі "колективні" вікна.
Але до переваг такого спліттера можна віднести можливість "розділяти" більше ніж два вікна відразу і по горизонталі і по вертикалі. Іншими словами, можна сформувати цілу "матрицю" вікон, які будуть позиціонуватися в межах вікна спліттера.

nbspnbspНа цьому закінчимо ліричний відступ в область теорії і приступимо до практичної роботи.

nbspnbspДля початку створимо проект.

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

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

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

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

nbsp2. Видалимо з функції CMainFrame :: OnCreate створення вікна m_wndView. Тобто видалимо рядки:

nbspif (! m_wndView.Create (NULL, NULL, AFX_WS_DEFAULT_VIEW,
nbspnbspCRect (0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
nbsp nbspnbspTRACE0 ( "Failed to create view window \ n");
nbspnbspreturn -1;
nbsp>

nbsp3. У функціях CMainFrame :: OnSetFocus і CMainFrame :: OnCmdMsg змінну m_wndView замінимо на m_wndSplitter.

nbsp4. Додамо до класу CMainFrame ще дві зашіщенние (protected) змінні:

nbspnbspето поки будуть вікна - заглушки для того, щоб їх вставити в спліттер і добитися правильного його поведінки.

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

nbspBOOL CMainFrame :: OnCreateClient (LPCREATESTRUCT lpcs, CCreateContext * pContext)
nbsp nbspnbspif (! m_wndSplitter.CreateStatic (this, 1, 2))
nbspnbspnbspnbspreturn FALSE;

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

nbspnbspif (! m_wndLeftPane.Create (WS_CHILD | WS_VISIBLE,
nbspnbspnbspnbspCRect (0, 0, 0, 0), m_wndSplitter,
nbspnbspnbspnbspm_wndSplitter.IdFromRowCol (0, 0)))
nbspnbspnbspnbspreturn FALSE;

nbspnbspif (! m_wndRightPane.Create (WS_CHILD | WS_VISIBLE,
nbspnbspnbspnbspCRect (0, 0, 0, 0), m_wndSplitter,
nbspnbspnbspnbspm_wndSplitter.IdFromRowCol (0, 1)))
nbspnbspnbspnbspreturn FALSE;

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

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

nbspnbspreturn CFrameWnd :: OnCreateClient (lpcs, pContext);
nbsp>

nbspНу ось, ми бачимо радісну картину. вікно-рамка, панель інструментів (в своєму первозданному стані), спліттер, роздільник якого "приліплений" до одного краю вікна.

nbspnbspНе дуже красиво. Чи не правда ?

nbspnbspМожно перемістити роздільник спліттера як треба, але при зміні розмірів головного вікна-рамки роздільник спліттера НЕ буде переміщатися. Тобто він (роздільник) має фіксовану позицію.
Сумно. Адже в Total Commander - е спліттер зберігає відносну позицію (процентне відношення ширини правого вікна, що знаходиться в сплітері до ширини лівого вікна незмінно). Але стандартний спліттер MFC не підтримує такої функціональності. Але на то проблеми і існують, щоб їх вирішувати.

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

nbspnbspnbspnbspА поки Все.

Вихідний код проекту, розглянутого в статті ви можете знайти на сайті розсилки SoftMaker.fatal.ru на головній сторінці проекту.