Шаг 73.
Библиотека OWL.
Еще один текстовый редактор

    На этом шаге мы рассмотрим еще один текстовый редактор.

    Перед Анастасией Цокол, студенткой 4 курса факультета математики и информационных технологий Курганского государственного университета (декабрь 2005 г.) была поставлена следующая задача: разработать приложение, содержащее любой текст (предусмотреть загрузку текста из файла). Текст должен иметь возможность редактирования с помощью стандартных диалоговых панелей "Поиск" и "Замена" (реализовать все возможности: "Найти", "Найти далее", "Заменить", "Заменить всё").

    Задача решена с использованием MDI-приложения.

    Так как необходимо предусмотреть загрузку текста из файла и его редактирование, следовательно, было создано меню с пунктами File (Open, Exit) и Edit (Find, Find Next, Replace).

    Так же, для удобства пользователя, была создана панель инструментов с соответствующими кнопками Open, Exit, Find, FindReplace, Replace (любую кнопку можно создать, используя Resource Workshop, размеры и изображения определяются по желанию).

    При запуске программы открывается окно, на котором "активны" только две кнопки Open и Exit, так как текст для редактирования ещё не открыт.

    При выборе подпункта Open или при нажатии на соответствующую кнопку, с помощью функции cmFileOpen() создается новое окно, являющееся дочерним по отношению к окну-клиенту, созданному в функции InitMainWindow() (более подробное описание можно посмотреть на 45 шаге).

    После того, как какой-либо текст был загружен из файла, становятся "активными" кнопки Find и Replace и, следовательно, можно приступать к редактированию текста.

    При выборе команды "Find" появляется диалоговое окно. В строку редактирования данного окна вводится искомое слово или искомый символ. При нажатии на кнопку "Найти", в документе будет выделен данный фрагмент в соответствии с текущим положением курсора. Если запрашиваемый текст не найден, выдаётся сообщение "Фрагмент … не найден". Нажатие на кнопку диалогового окна "Найти далее" соответствует нажатию кнопки "Найти далее" главного окна (положение курсора в тексте можно менять и при открытом диалоговом окне).

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

    Find и Replace - это стандартные диалоговые окна Windows (см. шаг 28).

    Так же была создана строка сообщения для отображения подсказки при подведении (режим EnterHints) курсора к определенной кнопке на панели инструментов или к соответствующему подпункту меню.

    Текст приложения:

#include <owl\applicat.h>
#include <owl\decmdifr.h>
#include <owl\editfile.h>
#include <owl\mdi.h>
#include <owl\controlb.h>
#include <owl\statusba.h>
#include <owl\buttonga.h>
#include "pr73_1.rc"

//Класс приложения.
class TMDIApp: public TApplication
{
  public:
	 TMDIApp():TApplication(){}
	 void InitMainWindow();
  protected:
	  TMDIClient *clienTWndw;
	  TControlBar *controlBar;
	  TMDIChild *childWnd;
	  void CmFileOpen();

	  DECLARE_RESPONSE_TABLE (TMDIApp);
};

DEFINE_RESPONSE_TABLE1(TMDIApp, TApplication)
EV_COMMAND (CM_FILEOPEN, CmFileOpen),
END_RESPONSE_TABLE;

// TMDIApp::InitMainWindow()
// Эта функция создает главное окно приложения,
// окно-клиент, панель инструментов и
// строку сообщения.
void TMDIApp::InitMainWindow()
{  // Создать окно-клиент.
  clienTWndw = new TMDIClient;
  // Создать окно обрамления.
  TDecoratedMDIFrame *frameWnd = new TDecoratedMDIFrame 
       ("Пример текстового редактора", MENU_1, *clienTWndw, TRUE);
  // Определить размеры и расположение окна обрамления.
  frameWnd->Attr.X = 50;
  frameWnd->Attr.Y = 50;
  frameWnd->Attr.W=GetSystemMetrics(SM_CXSCREEN)/3;
  frameWnd->Attr.H=GetSystemMetrics(SM_CXSCREEN)/3;
  // Создать инструментальную линейку.
  controlBar = new TControlBar (frameWnd,TControlBar::Vertical);
  controlBar->Insert(*new TButtonGadget(ID_OPEN, CM_FILEOPEN));
  controlBar->Insert(*new TSeparatorGadget (10));
  controlBar->Insert(*new TButtonGadget(ID_EXIT, CM_EXIT));
  controlBar->Insert(*new TSeparatorGadget (30));
  controlBar->Insert(*new TButtonGadget(ID_FIND, CM_EDITFIND));
  controlBar->Insert(*new TSeparatorGadget (10));
  controlBar->Insert(*new TButtonGadget(ID_FINDREPLACE, CM_EDITFINDNEXT));
  controlBar->Insert(*new TSeparatorGadget (10));
  controlBar->Insert(*new TButtonGadget(ID_REPLACE, CM_EDITREPLACE));
	// Вставить панель инструментов в окно обрамления.
  frameWnd->Insert(*controlBar, TDecoratedFrame::Right);
  // Установить режим подсказки, чтобы сразу
  // показывать подсказку.
  controlBar->SetHintMode(TGadgetWindow::EnterHints);
  // Создать строку сообщения.
  TMessageBar *msgbar=new TMessageBar(0);
  //Вставить строку сообщения в окно обрамления.
  frameWnd->Insert(*msgbar, TDecoratedFrame::Bottom);
  EnableCtl3d (TRUE);
  // Установить значение указателя MainWindow приложения.
  SetMainWindow(frameWnd);
};

void TMDIApp::CmFileOpen()
{  // Создать объект TData диалогового окна.
  TOpenSaveDialog::TData fileData (OFN_FILEMUSTEXIST |
	 OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
	 "Все файлы (*.*) | *.* |Текстовые файлы (*.txt) | *.txt |", 0, 0, " * ");
  // Задать имя файла как пустую строку.
  strcpy(fileData.FileName, "");
  // Создать диалоговое окно Open.
  TFileOpenDialog *dialog = new TFileOpenDialog (MainWindow, fileData);
  // Выполнить диалоговое окно Open.
  int result = dialog->Execute();
  // Если пользователь выходит по кнопке ОК...
  if (result == IDOK)
	 // Создать новый управляющий элемент редактирования файла.
	{TEditFile *editFile =new TEditFile (0, 0, 0, 0, 0, 0, 0, fileData.FileName);
	 // Создать новое дочернее окно для файла.
	 childWnd = new TMDIChild (*clienTWndw, "", editFile);
	 // Отобразить новое дочернее окно.
	 childWnd->Create();
	 }
};

int OwlMain(int,char *[])
{
  return TMDIApp().Run();
}

    Файл ресурсов:

#ifndef WORKSHOP_INVOKED
#include "windows.h"
#endif

#include <owl\mdi.rh>
#include <owl\editfile.rh>

#define MENU_1          100
#define ID_MDIEDIT      101
#define ID_DOCUMENT     102
#define ID_OPEN         CM_FILEOPEN
#define ID_EXIT         CM_EXIT
#define ID_FIND         CM_EDITFIND
#define ID_FINDREPLACE  CM_EDITFINDNEXT
#define ID_REPLACE      CM_EDITREPLACE

#ifdef RC_INVOKED

#include <owl\except.rc>
#include <owl\statusba.rc>

MENU_1 MENU
{
	POPUP "&File"
	{
		 MENUITEM "&Open",       CM_FILEOPEN
		 MENUITEM SEPARATOR
		 MENUITEM "E&xit",       CM_EXIT
	}
	POPUP "&Edit"
	{
		 MENUITEM "&Find...", CM_EDITFIND
		 MENUITEM "Find &Next", CM_EDITFINDNEXT
		 MENUITEM "&Replace...", CM_EDITREPLACE
	}
}

STRINGTABLE
{  CM_FILEOPEN,      "Открыть"
   CM_EXIT,          "Выход"
   CM_EDITFIND,      "Найти"
   CM_EDITFINDNEXT,  "Найти далее"
   CM_EDITREPLACE,   "Заменить"
   IDS_FILECHANGED,  "Файл был изменён. \n\nСохранить изменения?"
   IDS_CANNOTFIND,   "Фрагмент не найден \042%s\042"
}

ID_OPEN        BITMAP "open1.bmp"
ID_EXIT        BITMAP "exit1.bmp"
ID_FIND        BITMAP "find1.bmp"
ID_FINDREPLACE BITMAP "findnx1.bmp"
ID_REPLACE     BITMAP "replace1.bmp"

#endif
Текст этого приложения можно взять здесь.

    Результат работы приложения изображен на рисунке 1:


Рис.1. Результат работы приложения

    На следующем шаге мы рассмотрим простейший калькулятор.




Предыдущий шаг Содержание Следующий шаг