Иллюстрированный самоучитель по Visual Studio .NET

Настройка стартового кода

Просмотрите плоды работы мастера в окне Class View. С помощью контекстного меню задайте в этом окне режим просмотра Sort By Type, так как он компактнее, а классов у нас будет достаточно много. Приятным моментом является то, что класс CRightView теперь действительно потомок CScrollView, как мы это определили в окне мастера. В сходной ситуации Visual Studio 6 отказывалась менять родителя, и это приходилось делать вручную. Отметьте также, что во всех отношениях стартовые заготовки Studio .NET 7.0 более компактны, чем их прототипы Visual Studio 6. Тем не менее в них есть лишние детали, которые я с неизменным упорством убираю.

Так, каждое из двух представлений имеет по две версии метода GetDocument. Один работает в отладочной (debug) версии проекта, а другой – в окончательной (release). Класс CLeftview, который будет демонстрировать файловое дерево, не нуждается в поддержке вывода на принтер, как и представление CRightView, которое предполагается использовать для предварительного просмотра содержимого файлов документов. Виртуальную функцию preCreateWindow мы также не будем использовать в некоторых классах. То же следует сказать о наследии класса CObject: функциях Assertvalid и Dump. Об особой культуре их использования я говорил в предыдущей книге (Visual C++6 и MFC, "Питер", 2000), а здесь просто рекомендую молча убрать их из всех классов. Если возникнет необходимость вывести в окно Debug отладочную информацию, то можно обойтись без этих функций и в любом методе класса с успехом пользоваться глобально определенным объектом afxDump.

Обычно, перед тем как приступить к разработке приложения, я провожу генеральную чистку стартовой заготовки. При выбрасывании лишнего кода, как и при прополке, важно не забывать о корнях. Удалять функцию следует как в срр-файле (реализации класса), так и в h-файле (интерфейса класса). При этом удобной оказывается команда, а точнее ее аналог в виде кнопки на инструментальной панели Edit › Find and Replace › Find in Files. Попробуйте использовать ее для того, что бы найти и удалить с корнем все версии функции GetDocument. Убирайте объявления и тела этой функции, но не ее вызовы. Затем в h-файлы классов CLeftview и CRightview и только в них вставьте такую достаточно надежную версию этой функции:

CTreeDoc* GetDocument()
{
return dynamic_cast<CTreeDoc*>(m_pDocument);
}

Замены такого рода, когда в h-файл вставляется код, а не только декларации, сопряжены с некоторыми неожиданными сообщениями со стороны компилятора. Здесь важно проявить терпение и не опускать руки раньше времени. Если вы правильно сделали замены, то после компиляции проекта получите предупреждение и сообщение об ошибке. С предупреждением справиться просто, если посмотреть справку по его коду (С4541). Выяснится, что для использования информации о типе указателей на этапе выполнения (run-time type information, которой пользуется выражение dynamic_cast<type-id>(expression)), необходимо предварительно сделать установку специального режима компиляции. В Studio .NET это делается так:

  1. Поставьте фокус в узел Tree окна Class View или окна Solution Explorer и дайте команду View › Property Pages (ALT + Enter).
  2. В появившемся диалоге Property Pages раскройте узел дерева C/C++ и выберите элемент Language.
  3. В таблице окна справа найдите свойство Enable Runtime Type Info и задайте для него значение Yes (/GR).

Аббревиатура /GR соответствует опции, задаваемой в командной строке компилятора. После повторной компиляции предупреждения исчезнут, однако ошибка останется. В такие моменты важно обратить внимание на имя файла, при компиляции которого была обнаружена ошибка. В нашем случае – это TreeFrm.cpp. Раскройте этот файл и просмотрите его начало, где стоят директивы #include. Сбой произошел в месте включения файла #include "Lef tview.h". Именно в него мы вставили новое тело функции GetDocument. Компилятор сообщает, что при анализе строки:

return dynamic_cast<CTreeDoc* <strong>></strong> (m_pDocument);

Он обнаружил неверный тип для преобразования (invalid target type for dynamic_ cast). Но тип CTreeDoc* (указатель на класс документа) задан верно. Проблема всего лишь в том, что компилятор пока не знает о том, что CTreeDoc происходит от известного ему класса CDocument. Решение этой проблемы – вставить директиву #include "TreeDoc.h" перед директивой #include "Lef tview.h". В сложных проектах, состоящих из множества файлов, неверная последовательность включения файлов заголовков может привести к дополнительной головной боли. Для выявления причины отказа в таких случаях нужен серьезный анализ этой последовательности.

Теперь, запустив приложение, вы должны увидеть заготовку приложения, которое соответствует выбору (флажку) Windows Explorer, сделанному нами в окне мастера AppWizard. Мы имеем два окна, разделенных перегородкой (split bar). Левое окно (рапе) предстоит наполнить ветвями файлового дерева, а в правом – показывать в виде "картинок" файлы документов приложения, обнаруженные в текущей папке – той папке, которая выбрана в левом окне, – дереве файлов. Возвращаясь к сокращениям кода стартовой заготовки, отметим, что многие файлы, будучи уменьшенными в объеме, значительно выигрывают в читабельности и выглядят не так страшно для новичков. В качестве примера приведем текст файла TreeFrm.h после указанной операции:

class CTreeFrame: public CMDIChildWnd
{
DECLARE_DYNCREATE (CTreeFrame)
public:
CTreeFrame();
virtual ~CTreeFrame();
//====== Создание панелей расщепленного (split) окна
virtual BOOL OnCreateClient(LPCREATESTRUCT Ipcs,
CCreateContext* pContext);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
//====== Объект для управления расщепленным окном
CSplitterWnd m_wndSplitter;
DECLARE_MESSAGE_MAP() };
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.