Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT (часть 2)© Александр Фролов, Григорий ФроловТом 28, М.: Диалог-МИФИ, 1996, 288 стр. КомпонентыСреда Microsoft Visual C++ предусматривает дополнительные возможности для повторного использования программного кода при создании новых программ. Для этого предназначена так называемая галерея компонентов - Component Gallery. Component Gallery служит вместилищем для компонентов. В качестве компонентов выступают классы (возможно вместе с необходимыми ресурсами), органы управления ActiveX (OCX), а также сложные компоненты. Компоненты Component Gallery можно включать в ваше приложение и использовать по своему усмотрению. При добавлении к проекту некоторых компонент в проект добавляются не только новые классы, но также новые ресурсы. В ряде случаев даже выполняется изменение исходных текстов самого приложения. Добавление компонентов в проектПроцедура использования Component Gallery для добавления разрабатываемому приложению новых возможностей предельно проста. Выберите из меню Insert строку Component. На экране появится диалоговая панель Component Gallery (рис. 2.1). Она состоит из нескольких страниц, в которых отображаются различные пиктограммы. Именно эти пиктограммы и представляют компоненты, которые вы можете добавить к вашему приложению. Количество страниц Component Gallery и набор компонент зависит от версии Visual C++ и постоянно расширяется. В Component Gallery можно включить компоненты, разработанные другими фирмами, например Blue Sky Software, VideoSoft. Более того, вы можете включить в Component Gallery собственные компоненты, разработанные вами. В простейшем случае, в качестве таких компонент могут выступать классы приложений, которые вы создали. Рис. 2.1. Диалоговая панель Component Gallery Управление компонентамиСразу после установки среды Microsoft Visual C++ в диалоговой панели Component Gallery отображается две станицы, содержащие компоненты - Microsoft и OLE Controls. Каждая страница представляет разные категории компонентов. В диалоговой панели Component Gallery вы можете создавать и удалять страницы с компонентами, добавлять и удалять компоненты, перемещать их между категориями, переименовывать и выполнять над ними другие простые действия. Для управления страницами компонентов и отдельными компонентами достаточно нажать кнопку Customize. Вы сможете выполнить все настройки в открывшейся диалоговой панели Customize Component Gallery. Вся информация о компонентах и страницах Component Gallery записана в специальной базе данных. Эта база данных расположена в файле gallery.dat, в каталоге Msdev\Template. Если вы случайно удалили нужные компоненты с панели Component Gallery, вы можете восстановить их. Для этого надо удалить файл gallery.dat. Во время очередного запуска Microsoft Visual C++ заново создаст файл gallery.dat и восстановит все компоненты, поставляемые с Visual C++. Компоненты MicrosoftНа странице Microsoft диалоговой панели Component Gallery расположены компоненты, разработанные фирмой Microsoft. Среди них содержатся много интересных компонент, добавляющих к вашему приложению различные возможности практически без дополнительных затрат с вашей стороны. Среди них компонент, позволяющий приложениям использовать обменный буфер Windows Clipboard, компонент, выполняющий фоновые работы во время бездействия приложения, компонент, содержащий готовые диалоговые панели для ввода пароля и отображения хода различных процессов и многое многое другое. Чтобы получить полные описания каждого компонента, достаточно выбрать его в панели Component Gallery и нажать на кнопку с вопросительным знаком. Сейчас мы кратко опишем назначение компонент Microsoft, а затем рассмотрим использование одной из компонент на примере.
Как видите, некоторые компоненты, расположенные на странице Microsoft, дублируют возможности приложения, которыми можно управлять в ходе создания приложения средствами MFC AppWizard. Поэтому если во время начального создания проекта приложения вы не указали, что приложение будет работать с сокетами Windows то вместо кропотливого исправления проекта вручную можно просто добавить в него компонент Windows Sockets. Конечно, все возможности, которые предоставляют компоненты Microsoft, легко реализовать самому. Однако зачем тратить драгоценное время, когда уже есть готовое решение. Добавление компонент MicrosoftДля добавления к вашему проекту новой компоненты, выберите соответствующую пиктограмму и нажмите кнопку Insert. Дальнейший процесс вставки компонента зависит от него самого. Наиболее общий сценарий выглядит следующим образом. Когда вы нажмете кнопку Insert, у вас запрашивается различная дополнительная информация о том, что вы желаете получить. Это могут быть какие-либо характеристики компонента, названия классов, файлов и т. д. Когда вы введете всю необходимую информацию, начнется модификация проекта. На этом этапе в проект могут быть добавлены новые ресурсы и классы, а в исходные тексты приложения могут быть автоматически внесены исправления. Сейчас мы расскажем об использовании компонент Microsoft на примере компоненты Splash Screen. Далее, когда мы будем рассказывать о меню, панелях управления и панелях состояния мы также будем делать ссылки на Component Gallry. Заставка для приложенияМногие приложения Windows при запуске отображают на экране временную заставку. В ней, как правило, на фоне рисунка представлены название приложения, номер версии, другая справочная информация. Примером таких приложений могут служить Microsoft Word, Microsoft Excel и другие офисные приложения Microsoft. Microsoft Visual C++ также отображает заставку во время запуска. С помощью Component Gallry и компонента Splash Screen вы затратите всего нескольких минут, чтобы добавить к приложению заставку. Откройте проект приложения к которому надо добавить заставку. Выберите на панели Component Gallry из страницы Microsoft, пиктограмму Splash Screen. Затем нажмите кнопку Insert. На экране появится диалоговая панель Splash Screen (рис. 2.2). В ней вы должны указать ряд характеристик. В поле Class Name отображается имя класса CSplashWnd, который будет отвечать за отображение заставки. Вы можете изменить это имя по своему усмотрению или оставить его без изменения. Во втором поле диалоговой панели - Bitmap resource ID отображается идентификатор изображения bitmap, который будет служить заставкой для приложения. По умолчанию в качестве идентификатора предлагается использовать изображение bitmap с идентификатором IDB_SPLASH. Рис. 2.2. Диалоговая панель Splash Screen Компонент Splash Screen добавит к вашему приложению заготовку изображения bitmap с идентификатором IDB_SPLASH. Поэтому вам останется только отредактировать ее на свой вкус. Мы привели уже отредактированное нами изображение IDB_SPLASH на рисунке 2.3. Рис. 2.3. Изображение IDB_SPLASH Определение класса CSplashWnd, управляющего окном заставки, и его методы записываются в файлы с именами Splash.cpp и Splash.h. Эти файлы будут размещены в каталоге вместе с остальными исходными файлами приложения. Если вам надо изменить названия данных файлов, нажмите на кнопку Change. Когда вы заполните диалоговую панель Splash Screen, нажмите на кнопку OK. Начнется процесс встраивания компонента в проект. После его завершения закройте диалоговую панель Component Gallry, для чего нажмите на кнопку Close. Вы можете сразу встроить в проект несколько различных компонент. Однако, на наш взгляд, после встраивания очередного компонента стоит, как минимум, перестроить проект и убедиться в его работоспособности. Как устроен компонент Splash ScreenОткройте окно просмотра проекта Project Workspace и обратите внимание на произошедшие в нем изменения. На странице ClassView появился новый класс CSplashWnd, включающий несколько методов и элементов данных. В главном классе приложения появился новый метод PreTranslateMessage. На странице ResourceView к ресурсам приложения добавился ресурс Bitmap с идентификатором IDB_SPLASH. На странице FileView также произошли изменения. В ней добавился файл Splash.cpp, а в папке зависимых файлов Dependencies появились имена файлов Splash.h и Splash16.bmp. Число 16 на конце имени файла Splash16.bmp означает, что в изображении используется шестнадцать цветов. К сожалению, компонент Splash Screen не работает с изображениями, имеющими большее количество цветов. Кроме перечисленных изменений, хорошо заметных из окна просмотра проекта Project Workspace, имеют место и изменения в существующих методах главного класса приложения. Такие изменения обнаружить значительно труднее, особенно если программный код приложения слишком велик и данный компонент не имеет полной документации. Для облегчения поиска фрагментов измененного кода они обозначаются специальными комментариями следующего вида: // CG: Символы CG являются сокращением от Component Gallry. После символов CG: как правило следует словесное описание добавленного программного кода. Так как Microsoft Visual C++ не умеет вставлять в текст программы русскоязычные комментарии, мы полностью заменили текст комментариев и добавили собственное описание программного кода компоненты Splash Screen. Метод InitInstance класса CMultiAppЧтобы изучить измененный программный код, просмотрите метод InitInstance класса CMultiApp. Мы не стали приводить здесь первоначальный вид метода InitInstance класса CMultiApp, так как во первых, он уже был нами описан ранее в разделе “Приложение Multi”, а во вторых, изменения в методе InitInstance заключаются в добавлении единственного блока следующего за комментарием CG. В этом боле CG: сначала выполняется обработка командной строки приложения. Для этого используются метод ParseCommandLine, уже описанный ранее. Он записывает обработанную строку приложения в объект cmdInfo класса CCommandLineInfo. Для нас важно, если в командной строке приложения не указано имени файла, в элемент m_bShowSplash объекта cmdInfo записывается значение TRUE, а если указано - FALSE. Затем выполняется вызов метода EnableSplashScreen класса CSplashWnd. В качестве параметра ему передается элемент m_bShowSplash объекта cmdInfo. Он определяет, надо ли при запуске приложения показывать заставку. Если m_bShowSplash содержит значение TRUE, заставка показывается, если FALSE - нет. На этом блок CG:, добавленный компонентом Splash Screen, завершается. Далее идет уже знакомый вам текст метода InitInstance. Его описание вы найдете в разделе “Приложение Multi”: BOOL CMultiApp::InitInstance() { // CG: Следующий блок добавлен при вставке в проект // компонента Splash Screen { // Выполняем стандартную обработку командной строки // приложения CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash); } #ifdef _AFXDLL Enable3dControls(); #else Enable3dControlsStatic(); #endif // Загружаем файл конфигурации LoadStdProfileSettings(); // Создаем шаблон документа CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMultiDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMultiView)); // Регистрируем шаблон документа AddDocTemplate(pDocTemplate); // Выполняем стандартную обработку командной строки // приложения CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Обрабатываем командную строку приложения if (!ProcessShellCommand(cmdInfo)) return FALSE; return TRUE; } Метод PreTranslateMessage класса CMultiAppВиртуальный метод PreTranslateMessage, переопределенный в главном классе приложения CMultiApp, первоначально определен в базовом классе CWinApp. Метод PreTranslateMessage вызывается из цикла обработки сообщений перед тем как очередное сообщение будет распределено по назначению при помощи функций TranslateMessage и DispatchMessage. В качестве параметра pMsg, передается указатель на структуру типа MSG, которая представляет очередное сообщение, полученное в цикле обработки сообщений из очереди: virtual BOOL PreTranslateMessage(MSG* pMsg); Таким образом метод PreTranslateMessage позволяет выполнить дополнительную обработку сообщений или даже полностью изъять их из обработки (отфильтровать). Переопределив метод PreTranslateMessage вы должны возвращать нулевое значение, если данное сообщение должно быть обработано обычным образом или ненулевое значение, если метод PreTranslateMessage сам выполняет обработку сообщения и оно не должно передаваться приложению для дальнейшей обработки. Во время вставки в проект компонента Splash Screen в метод PreTranslateMessage главного класса приложения добавляется вызов метода PreTranslateAppMessage класса CSplashWnd. Если метод PreTranslateAppMessage класса CSplashWnd возвращает значение TRUE, тогда метод PreTranslateAppMessage класса CMultiApp также сразу завершается и возвращает значение TRUE. Сообщения, обработанные классом CSplashWnd более не передаются приложению для дальнейшей обработки. Если метод PreTranslateAppMessage класса CSplashWnd возвращает значение FALSE, тогда вызывается метод PreTranslateMessage базового класса CWinApp. Заметим, что по умолчанию метод PreTranslateMessage класса CWinApp выполняет некоторую дополнительную обработку сообщений, например выделяет сообщения от клавиатуры, соответствующие комбинациям клавиш, определенным в таблице акселераторов и преобразует их в командные сообщения. Более подробно о таблице акселераторов вы можете прочитать в разделе “Таблица акселераторов” главы “Меню, панели управления и панели состояния”, а также в 13 томе серии “Библиотека системного программиста”: BOOL CMultiApp::PreTranslateMessage(MSG* pMsg) { // CG: The following lines were added by the Splash Screen // component. if(CSplashWnd::PreTranslateAppMessage(pMsg)) return TRUE; return CWinApp::PreTranslateMessage(pMsg); } В случае, если сообщение передается для обработки методу PreTranslateMessage базового класса CWinApp - CWinApp::PreTranslateMessage, метод PreTranslateMessage класса CMultiApp возвращает результат работы этого метода. Метод OnCreate класса CMainFrameМетод OnCreate создает главное окно приложения и отображает в нем панели управления и состояния. Описание метода OnCreate класса CMainFrame вы можете посмотреть в разделе “Приложение Multi”. Во время добавления компонента Splash Screen метод OnCreate класса CMainFrame модифицируется. К нему добавляется вызов метода ShowSplashScreen класса CSplashWnd. Метод ShowSplashScreen класса CSplashWnd, который создает и отображает на экране окно заставки, будет описан нами позже: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Вызываем метод OnCreate базового класса if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // Создаем панель управления toolbar if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { // Ошибка при создании панели управления toolbar TRACE0("Failed to create toolbar\n"); return -1; } // Создаем панель состояния status bar if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { // Ошибка при создании панели состояния status bar TRACE0("Failed to create status bar\n"); return -1; } // TODO: вы можете изменить характеристики панели // управления, убрав некоторые флаги CBRS_ m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // TODO: вы можете запретить перемещение панели управления, // если удалите следующие три строки программы m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); // CG: The following line was added by the Splash Screen // component. CSplashWnd::ShowSplashScreen(this); return 0; } Класс CSplashWndПрактически весь программный код, отвечающий за отображение заставки Splash Screen, содержится в классе CSplashWnd. Этот класс включается в состав проекта и вы можете просмотреть его содержимое в окне проекта Project Workspace на странице ClassView (рис. 2.4). Рис. 2.4. Окно Project Workspace, класс CSplashWnd Определение класса CSplashWnd находится в файле Splash.h. Мы привели его полностью в листинге 2.1. Класс CSplashWnd создан на основе базового класса CWnd. Он включает в себя ряд методов и несколько элементов данных. Класс CSplashWnd может обрабатывать сообщения, поэтому для него в файле Splash.h определена макрокоманда DECLARE_MESSAGE_MAP, а в файле реализации - Splash.cpp - таблица сообщений класса. Листинг 2.1. Файл Splash.h // CG: This file was added by the Splash Screen component. #ifndef _SPLASH_SCRN_ #define _SPLASH_SCRN_ // Splash.h : header file // ////////////////////////////////////////////////////////////// // Splash Screen class class CSplashWnd : public CWnd { // Construction protected: CSplashWnd(); // Attributes: public: CBitmap m_bitmap; // Operations public: static void EnableSplashScreen(BOOL bEnable = TRUE); static void ShowSplashScreen(CWnd* pParentWnd = NULL); static void PreTranslateAppMessage(MSG* pMsg); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CSplashWnd) //}}AFX_VIRTUAL // Implementation public: ~CSplashWnd(); virtual void PostNcDestroy(); protected: BOOL Create(CWnd* pParentWnd = NULL); void HideSplashScreen(); static BOOL c_bShowSplashWnd; static CSplashWnd* c_pSplashWnd; // Generated message map functions protected: //{{AFX_MSG(CSplashWnd) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnPaint(); afx_msg void OnTimer(UINT nIDEvent); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif Методы класса CSplashWnd определены в файле реализации - Splash.cpp. Этот файл также добавляется к проекту Multi. Мы привели полный исходный текст этого файла в листинге 2.2. Листинг 2.2. Файл Splash.cpp // CG: Файл Splash.cpp добавляется в проект во время вставки // компонента Splash Screen и содержит реализацию класса // CSplashWnd #include "stdafx.h" #include "resource.h" #include "Splash.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////// // Splash Screen class BOOL CSplashWnd::c_bShowSplashWnd; CSplashWnd* CSplashWnd::c_pSplashWnd; CSplashWnd::CSplashWnd() { } CSplashWnd::~CSplashWnd() { // Clear the static window pointer. ASSERT(c_pSplashWnd == this); c_pSplashWnd = NULL; } BEGIN_MESSAGE_MAP(CSplashWnd, CWnd) //{{AFX_MSG_MAP(CSplashWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CSplashWnd::EnableSplashScreen(BOOL bEnable /*= TRUE*/) { c_bShowSplashWnd = bEnable; } void CSplashWnd::ShowSplashScreen(CWnd* pParentWnd /*= NULL*/) { if (!c_bShowSplashWnd || c_pSplashWnd != NULL) return; // Allocate a new splash screen, and create the window. c_pSplashWnd = new CSplashWnd; if (!c_pSplashWnd->Create(pParentWnd)) delete c_pSplashWnd; else c_pSplashWnd->UpdateWindow(); } BOOL CSplashWnd::PreTranslateAppMessage(MSG* pMsg) { if (c_pSplashWnd == NULL) return FALSE; // If we get a keyboard or mouse message, hide the splash // screen. if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN || pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN || pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCRBUTTONDOWN || pMsg->message == WM_NCMBUTTONDOWN) { c_pSplashWnd->HideSplashScreen(); return TRUE; // message handled here } return FALSE; // message not handled } BOOL CSplashWnd::Create(CWnd* pParentWnd /*= NULL*/) { if (!m_bitmap.LoadBitmap(IDB_SPLASH)) return FALSE; BITMAP bm; m_bitmap.GetBitmap(&bm); return CreateEx(0, AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, WS_POPUP | WS_VISIBLE, 0, 0, bm.bmWidth, bm.bmHeight, pParentWnd->GetSafeHwnd(), NULL); } void CSplashWnd::HideSplashScreen() { // Destroy the window, and update the mainframe. DestroyWindow(); AfxGetMainWnd()->UpdateWindow(); } void CSplashWnd::PostNcDestroy() { // Free the C++ class. delete this; } int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; // Center the window. CenterWindow(); // Set a timer to destroy the splash screen. SetTimer(1, 750, NULL); return 0; } void CSplashWnd::OnPaint() { CPaintDC dc(this); CDC dcImage; if (!dcImage.CreateCompatibleDC(&dc)) return; BITMAP bm; m_bitmap.GetBitmap(&bm); // Paint the image. CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap); dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY); dcImage.SelectObject(pOldBitmap); } void CSplashWnd::OnTimer(UINT nIDEvent) { // Destroy the splash screen window. HideSplashScreen(); } Вы всегда можете получить файл Splash.cpp следуя инструкциям в начале раздела “Заставка для приложения”. Теперь опишем отдельные методы класса. Конструктор и деструктор класса CSplashWndКонструктор класса CSplashWnd не содержит программного кода. Вы можете использовать его как заготовку, если решите расширить возможности компонента Splash Screen. Деструктор класса CSplashWnd также не содержит ничего сложного, он используется исключительно для записи в указатель c_pSplashWnd значения NULL: c_pSplashWnd = NULL; Таблица сообщений класса CSplashWndТаблица сообщений класса CSplashWnd содержит всего три макрокоманды, которые расположены внутри блока //{{AFX_MSG_MAP и поэтому управляются через ClassWizard: BEGIN_MESSAGE_MAP(CSplashWnd, CWnd) //{{AFX_MSG_MAP(CSplashWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() Две макрокоманды таблицы сообщений класса CSplashWnd уже давно вам знакомы. Это макрокоманда ON_WM_CREATE, которая вызывает метод OnCreate во время создания окна заставки (обработка сообщения WM_CREATE), и макрокоманда ON_WM_PAINT, которая вызывает метод OnPaint, когда надо перерисовать окно (обработка сообщения WM_PAINT). Таблицы сообщений класса CSplashWnd содержит также ранее не описанную нами макрокоманду ON_WM_TIMER. Эта макрокоманда предназначена для обработки сообщений WM_TIMER от таймера и вызывает метод OnTimer. Первоначально метод OnTimer определен в классе CWnd следующим образом. При вызове метода OnTimer для обработки сообщения WM_TIMER параметр nIDEvent содержит идентификатор таймера, вызвавшего это сообщение: afx_msg void OnTimer(UINT nIDEvent); Для установки (“запуска”) таймера используется метод SetTimer, также входящий в состав класса CWnd. Мы расскажем об этом методе более подробно, когда будем описывать метод OnCreate класса CSplashWnd, так как именно он устанавливает таймер для отображения заставки. Метод OnCreate класса CSplashWndМетод OnCreate класса вызывается при создании окна CSplashWnd, когда через таблицу сообщений проходит сообщение WM_CREATE. Реализация метода OnCreate класса CSplashWnd сначала вызывает метод OnCreate базового класса CWnd, который собственно и создает окно: if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; Далее вызывается метод CenterWindow, который выполняет центровку окна на экране: CenterWindow(); Метод CenterWindow определен в классе CWnd следующим образом: void CenterWindow(CWnd* pAlternateOwner = NULL); Если вызвать метод CenterWindow без указания параметров, или указать в качестве параметра значение NULL, то дочернее окно будет отцентровано относительно своего родительского окна, а всплывающее окно - относительно его владельца. Воспользовавшись параметром pAlternateOwner, вы можете указать другие окна относительно которых надо выполнить центровку. Затем метод OnCreate создает таймер, посылающий окну CSplashWnd сообщения с идентификатором 1 каждые 750 миллисекунд: SetTimer(1, 750, NULL); Метод SetTimer определен в классе CWnd и имеет три параметра. Параметр nIDEvent задает идентификатор, который будет выступать в качестве идентификатора сообщений WM_TIMER от таймера. Таймер будет вырабатывать сообщения с периодом, приведенным во втором параметре метода - nElapse: UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) ); Если третий параметр lpfnTimer равен NULL, то сообщения от таймера передаются окну для которого вызван метод SetTimer. Именно так используется метод SetTimer компонентом Splash Screen. Все сообщения таймера поступают окну CSplashWnd и обрабатываются в его таблице сообщений. В качестве параметра lpfnTimer можно указать имя функции обратного вызова, которая будет обрабатывать сообщения WM_TIMER вместо таблицы сообщений окна. Более подробно об использовании таймера и, в частности, о функции обратного вызова таймера читайте в 11 томе серии “Библиотека системного программиста”. Метод SetTimer возвращает в случае успешного создания таймера его идентификатор - ненулевое значение. Если таймер не создан, метод возвращает нулевое значение. Метод OnPaint класса CSplashWndМетод OnPaint класса CSplashWnd вызывается для обработки сообщений WM_PAINT, когда надо перерисовать изображение в окне. Компонент Splash Screen использует этот метод, чтобы вывести изображение bitmap в окне заставки: void CSplashWnd::OnPaint() { CPaintDC dc(this); CDC dcImage; if (!dcImage.CreateCompatibleDC(&dc)) return; BITMAP bm; m_bitmap.GetBitmap(&bm); // Paint the image. CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap); dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY); dcImage.SelectObject(pOldBitmap); } Метод OnTimer класса CSplashWndМетод OnTimer класса CSplashWnd вызывается для обработки сообщений от таймера, созданного в методе OnCreate. Этот метод вызывается всего один раз. При обработке первого сообщения от таймера он закрывает окно CSplashWnd и вместе с ним прекращает работу таймер. Для того чтобы закрыть окно заставки, используется метод HideSplashScreen, определенный в классе CSplashWnd: HideSplashScreen(); Метод EnableSplashScreen класса CSplashWndМетод EnableSplashScreen класса CSplashWnd устанавливает флаг c_bShowSplashWnd, записывая в него значение, переданное через единственный параметр метода - bEnable: c_bShowSplashWnd = bEnable; Метод ShowSplashScreen класса CSplashWndМетод ShowSplashScreen класса CSplashWnd создает и отображает на экране окно заставки. Перед этим он проверяет состояние флага c_bShowSplashWnd и переменной c_pSplashWnd: if (!c_bShowSplashWnd || c_pSplashWnd != NULL) return; Если флаг c_bShowSplashWnd содержит значение FALSE или объект c_pSplashWnd, представляющий окно заставки уже создан, метод ShowSplashScreen немедленно завершает свою работу. Если эти условия не выполняются, метод ShowSplashScreen создает новый объект класса CSplashWnd, который будет представлять окно заставки: c_pSplashWnd = new CSplashWnd; Затем вызывается метод Create для объекта c_pSplashWnd (он, кстати, переопределен в классе CSplashWnd), который и выполняет фактическое создание окна заставки: if (!c_pSplashWnd->Create(pParentWnd)) delete c_pSplashWnd; else c_pSplashWnd->UpdateWindow(); Если окно заставки не создано, метод Create возвращает нулевое значение и объект c_pSplashWnd удаляется. Если создание окна прошло успешно, для c_pSplashWnd вызывается метод UpdateWindow, вызывающий перерисовку окна. Такая перерисовка выполняется с помощью метода OnPaint класса CSplashWnd. Метод PreTranslateAppMessage класса CSplashWndКласс CSplashWnd имеет свою таблицу сообщений. Так как в классе CSplashWnd переопределен метод PreTranslateAppMessage, то он вызывается для каждого сообщения, поступающего в это окно перед его обработкой. В самом начале метод PreTranslateAppMessage проверяет, существует ли окно заставки. Если нет, то дополнительная обработка сообщений не выполняется: if (c_pSplashWnd == NULL) return FALSE; Когда окно заставки уже создано, метод PreTranslateAppMessage определяет тип сообщения. Если сообщение поступило от мыши или клавиатуры, то для окна заставки, представленного объектом c_pSplashWnd, вызывается метод HideSplashScreen, который его закрывает не дожидаясь первого сообщения от таймера. Метод PreTranslateAppMessage в этом случае возвращает значение TRUE и обработка сообщения завершается: if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN || pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN || pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCRBUTTONDOWN || pMsg->message == WM_NCMBUTTONDOWN) { c_pSplashWnd->HideSplashScreen(); return TRUE; // message handled here } Если поступило какое-либо другое сообщение, метод PreTranslateAppMessage возвращает значение FALSE и оно передается далее для дальнейшей обработки: return FALSE; Метод Create класса CSplashWndВ классе CSplashWnd компонент Splash Screen переопределяет виртуальный метод Create базового класса CWnd: BOOL CSplashWnd::Create(CWnd* pParentWnd /*= NULL*/) { /// .. } Класс CSplashWnd добаляет к этому методу программный код, который загружает ресурс изображения IDB_SPLASH. Для этого используется метод LoadBitmap: if (!m_bitmap.LoadBitmap(IDB_SPLASH)) return FALSE; При помощи метода GetBitmap для объекта, представляющего изображения bitmap, определяются различные характеристики этого изображения, которые записываются в объект bm структуры BITMAP: BITMAP bm; m_bitmap.GetBitmap(&bm); Последний оператор, завершающий метод Create, вызывает метод CreateEx, который и создает окно заставки: return CreateEx( 0, AfxRegisterWndClass( 0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, WS_POPUP | WS_VISIBLE, 0, 0, bm.bmWidth, bm.bmHeight, pParentWnd->GetSafeHwnd(), NULL ); Метод CreateEx определен в классе CWnd. Первый параметр метода задает дополнительные стили создаваемого окна заставки. Этот параметр содержит нулевое значение. Описание дополнительных стилей вы можете найти в документации Microsoft Visual C++. Второй параметр метода CreateEx должен содержать имя класса Windows, на основе которого создается окно. Для этого параметра используется класс, зарегистрированный функцией AfxRegisterWndClass. Третий параметр метода CreateEx определяет текст заголовка создаваемого окна. Так как для окна заставки заголовок не нужен, то в качестве этого параметра передается значение NULL. В четвертом параметре должны быть указаны основные стили создаваемого окна. Мы используем в качестве этого параметра комбинацию флагов WS_POPUP и WS_VISIBLE. Эти флаги означают, что создается временное окно, которое сразу отображается на экране. Дополнительную информацию об основных и дополнительных стилях окон вы можете получить из 11 тома “Библиотеки системного программиста”. Пятый, шестой, седьмой и восьмой параметры метода CreateEx определяют начальное положение, а также ширину и высоту окна. Начальное положение окна заставки выбирается по умолчанию - пятый и шестой параметры содержат нулевые значения, а ширина и высота берутся исходя из размеров изображения bitmap. Предпоследний, девятый параметр метода определяет родительское окно для окна заставки. В качестве этого параметра используется идентификатор окна (полученный методом CWnd::GetSafeHwnd), указанного параметром pParentWnd метода CSplashWnd::Create. Метод GetSafeHwnd класса CWnd возвращает идентификатор окна, связанного с объектом класса CWnd. Если объект класса CWnd не связан с окном, то метод GetSafeHwnd возвращает значение NULL, и, в этом случае, окно заставки не имеет родительского окна. Последний - десятый параметр метода CreateEx, может содержать указатель на дополнительные параметры. В данном вызове метода CreateEx этот параметр не используется. Рассмотрим процедуру регистрации класса Windows для окна заставки более подробно. Для выполнения регистрации используется функция AfxRegisterWndClass, которая возвращает текстовую строку с именем зарегистрированного класса: LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 ); Параметр nClassStyle указывает комбинацию стилей, используемых для создаваемого окна. Список стилей вы можете просмотреть в 11 томе “Библиотеки системного программиста” или в документации Microsoft Visual C++. Окна, созданные на основе зарегистрированного класса, будут использовать курсор с идентификатором hCursor, кисть с идентификатором hbrBackground и пиктограмму с идентификатором hIcon. В нашем примере для окна заставки регистрируется класс окна, который будет использовать стандартный кусор IDC_ARROW в форме стрелки. Метод HideSplashScreen класса CSplashWndМетод HideSplashScreen класса CSplashWnd закрывает окно заставки, вызывая метод DestroyWindow, а затем устанавливает флаг обновления для всех окон приложения с помощью метода UpdateWindow: DestroyWindow(); AfxGetMainWnd()->UpdateWindow(); Метод PostNcDestroy класса CSplashWndМетод PostNcDestroy класса CSplashWnd вызывается уже после того как окно заставки закрыто и используется дл того, чтобы удалить объект класса CSplashWnd, представляющий это окно в нашем приложении: delete this; |