Мастерская творца. Создание текстового редактора
Многие говорят, что программировать сложно. На самом деле программировать не сложнее, чем нарезать колбасу или написать письмо. Не сложнее, чем водить машину или пилотировать самолет. Главное — научиться. Мы постоянно получаем письма от вас с просьбами научить программированию. Почти полгода мы думали, как сделать это наиболее просто. Как научить создавать свои игры и программы, но так, чтобы не пришлось писать огромных руководств по языкам программирования и постоянно ссылаться на специализированную литературу. Результатом раздумий стал уникальный цикл статей — " Кладовая программиста ". Любому делу можно учиться двумя способами. Либо сначала долго штудировать теорию, а потом плавно переходить к практике — это эффективно, но очень долго. Второй способ — учиться сразу на практике. В этом случае не все получается сразу, но вы приобретаете бесценный опыт. Мы научим вас программировать на Delphi (статью " Игровая нирвана: Delphi и программирование компьютерных игр " с обзором Delphi читайте в седьмом номере “Мании” за 2002 год или на нашем компакте ) за несколько уроков. Каждый урок будет представлять собой независимую статью, руководство по созданию программы или игры. То есть можно будет взять, скажем, третью статью из серии и понять все, что в ней написано. Но! Чем более “поздний” урок вы возьмете, тем сложнее будет разобраться. Последовательность уроков мы подобрали так, чтобы в каждом следующем создаваемая утилита или игра была бы чуть сложнее, чем в предыдущем. Тем самым вы на наглядных примерах и в кратчайший срок выучите основные функции Delphi и сможете пользоваться ими уже для воплощения своих собственных идей. Итак, через тридцать минут вы сами создадите полноценный текстовый редактор, безглючный, красивый и удобный, который сможет по функциональности поспорить с творениями Microsoft (например, с “Блокнотом”). Вы поймете, что программирование — крайне увлекательный процесс. И снова в бой Запустите “Дельфи”. Мы не будем создавать редактор с нуля. Зачем, если кто-то уже сделал часть работы за нас? В любой приличной IDE (Интегрированная Среда Разработки) есть мастер приложений. С его помощью мы быстро создадим каркас будущей программы. После запуска “Дельфи” откроет новый проект. Нам он ни к чему, поэтому выполните File/Close All. После этого кликайте File/New. Откроется громадное окно с кучей пресетов. На вкладке Projects дважды кликните на иконке Application Wizard. Откроется мастер приложений. Первое его окно предложит указать, какие меню нам нужны. Помечайте галочкой File и Edit и кликайте Next. Следующее окно предложит выбрать расширения файлов, с которыми будет работать наша программа. Мы будем делать простой текстовый редактор, значит нам понадобится расширение “txt”. Кликайте на Add. В поле Description введите что-то вроде “Текстовый документ”, а в поле Extension — “txt”. Щелкайте Ok , а потом Next. В следующем окне у вас поинтересуются, какие стандартные кнопки вы хотите добавить на панель инструментов будущего приложения. Думаю, в интерфейсе этого окна вы разберетесь сами, ничего сложного там нет. Добавьте на панель инструментов все доступные кнопки из меню File и Edit. Перед тем как добавлять кнопки из меню Edit, один раз нажмите кнопку Space. Так вы поставите между группами кнопок File и Edit узкую вертикальную полоску, чтобы логически отделить их друг от друга. В следующем окне введите название программы. Я назвал ее Super. Данное окно — единственное, где нельзя использовать русский язык. Не беспокойтесь — позже вы сможете сменить заголовок программы и имя ее исполняемого файла на русские. Но сейчас — нельзя. С помощью кнопки Browse определите для своего проекта место на жестком диске и пометьте галочками пункты Create a status line и Enable hints. Нажмите на Finish , и “Дельфи” создаст новый проект. Перед вами четыре окна. Вверху — меню и палитра компонентов самого “Дельфи”, слева — инспектор объектов , он же объектный инспектор (чрезвычайно важная и полезная в работе штука), а прямо перед вами окажется заготовка программы. Выглядит она не совсем так, как будет выглядеть конечное приложение. Под заготовкой — окно редактора кода, где вы будете программировать. Там уже есть добрых пять-шесть страниц. Это вспомогательный код, который создал мастер приложений. На его основе мы и будем разрабатывать текстовый редактор. Каркас готов, пора обшивать его подробностями. Интереса ради можете запустить заготовку. Для этого нажмите кнопку Run на главной панели Delphi. Вы увидите, что программа уже сейчас работоспособна, но ничего полезного не делает. Разве что в меню File можно выбрать Exit, и тогда программа закроется. Ну ничего — сейчас мы добавим ей функциональности. Камера… Мотор! Нам надо перевести
Наш текстовый редактор на стапелях…
весь каркас на русский язык: заголовок окна программы, все пункты меню и подсказки к кнопкам (сами кнопки уже готовы). Пора познакомиться с другом всех программистов — объектным инспектором (ОИ). Щелкните на каком-нибудь элементе заготовки, например на кнопке. Она выделится. И тотчас ОИ преобразится. У него две вкладки — Properties и Events. На первой можно отредактировать свойства этого компонента. Свойства на языке программистов — это разнообразные параметры. На вкладке Events можно назначить разным событиям обработчики. Предвижу ваше недоумение и спешу объяснить. У каждого компонента (или объекта — в более общем случае) есть свои события. Например, если пользователь кликнул по кнопке — это целое событие. Или если пользователь ввел какой-то текст в поле ввода — тоже событие. Даже если пользователь просто провел курсором над какой-то панелькой — это событие. На вкладке Events разные события обозначены интуитивно понятными названиями. Вы же поймете, что событие OnClick происходит, когда пользователь кликает по компоненту. События у нас есть, и их надо обрабатывать. И для этого пригодятся обработчики. Обработчик — это кусочек программного кода, который запустится, если сработает то или иное событие. Именно так мы и будем реагировать на действия пользователя. Для примера рассмотрим одно из уже назначенных событий. На панели инструментов заготовки выберите кнопку, которая закрывает программу. Она выглядит как две разноцветные вертикальные полоски с крышечкой. Переключитесь на вкладку Events. Оказывается, этой кнопке уже назначено событие OnClick. Обработчик этого события называется FileExit. Но это не аксиома — вы сами можете назвать его как угодно. Дважды щелкните по названию обработчика. Вы окажетесь в том куске программного кода, который отвечает за закрытие программы. Все, что между begin и end — это обработчик. В нашем случае здесь всего лишь одна-единственная команда — Close , которая закрывает программу. Надеюсь, теперь вы поняли, как работать с событиями. Чтобы создать новый обработчик события для выделенного объекта, просто дважды щелкните по пустой строчке напротив соответствующего события. Но мы несколько отвлеклись. Если помните, была поставлена задача русифицировать приложение. Приступим. Сперва по очереди выделяйте каждую кнопку на панели инструментов нашего редактора, и в ОИ на первой вкладке найдите свойство Hint. Это свойство как раз и отвечает за всплывающую подсказку к кнопке. Переведите на великий и могучий значение этого свойства. Например, первую кнопку переведем так: “Новый документ|Нажмите эту кнопку для создания нового документа”. Перед чертой пишется краткое описание, а после — полное. После того как вы русифицировали кнопки, пора приниматься за пункты меню. Напрямую работать с ними не получится даже при большом желании. Дважды щелкните по кнопке Main Menu , которая находится между панелью инструментов и статусной линией заготовки. На самом деле это вовсе не кнопка, а невизуальный компонент. Она символизирует меню программы. После запуска программы эта “кнопка” просто не будет видна. Откроется редактор меню. Вот тут уже можно выделять разные пункты меню как отдельные объекты и изменять их свойства. Здесь надо перевести не только подсказки, но и сами названия пунктов меню. За названия любых объектов отвечает свойство Caption. Добавлять новые или удалять старые пункты можно через контекстное меню. Обратите внимание, что перед некоторыми буквами в названиях пунктов меню стоит знак амперсанд — &. Это значит, что во время работы программы следующая за ним буква будет подчеркнута, а активировать этот пункт меню можно будет нажатием соответствующей кнопки на клавиатуре. Для полной русификации не хватает только одного — русского названия программы. Щелкните на свободном месте заготовки (она называется формой) и в ОИ напишите что-нибудь в свойстве Caption. Я, например, написал вот что: “Текстовый редактор “Супер””. Покой нам только снится Программу мы русифицировали. Пора создавать сам текстовый редактор. Его основа — поле, куда пользователь
…и в первом плавании.
может вводить текст. На палитре “Дельфи” есть компонент, который отвечает за подобное поле ввода, — RichEdit. Найдите этот компонент (а размещается он на вкладке Win32 ), кликните на него, а потом кликните на свободном месте на форме. Невзрачная кнопочка развернется в целое поле ввода. Однако расположено оно абы как. Надо с этим что-то делать. Выделите RichEdit и в ОИ установите свойство Align в alClient. Поле ввода заняло всю свободную площадь на форме. А нам как раз это и надо. Однако в самом поле уже написана какая-то несуразность. А нам надо, чтобы перед пользователем предстал девственно чистый и готовый к работе лист. За содержимое поля ввода отвечает свойство Lines. В объектном инспекторе щелкните на маленькую кнопку с тремя точками напротив этого свойства и в открывшемся окне удалите все содержимое поля ввода. Теперь запустите программу. Оказывается, в поле ввода уже можно писать, и при этом работают многие стандартные комбинации клавиш Windows. Теперь нам остается прописать функции сохранения и загрузки текстовых файлов. Внимательно посмотрите на нашу форму. Видите невизуальные компоненты OpenDialog и SaveDialog? Они отвечают за стандартные окна сохранения и загрузки файлов Windows. Благодаря этому нет необходимости создавать соответствующие диалоги. Но кое-что придется сделать ручками. Ведь окна сохранения и загрузки “не знают” о поле ввода. Надо их как-то связать. А также надо связать все это с кнопками и пунктами меню, которые будут запускать процедуры сохранения и загрузки файлов. Вот этим мы сейчас и займемся. Дважды щелкните по кнопке сохранения документа нашей заготовки. Откроется новый обработчик события — мышиного клика. И аккурат между begin и end (вторыми по счету, после надписи, выделенной синим цветом) пропишите одну-единственную строку: RichEdit1.Lines.SaveToFile(SaveDialog.FileName); Разберем эту строку по звеньям. Мы вызываем у свойства Lines объекта RichEdit1 метод SaveToFile, а в качестве параметра передаем ему значение свойства FileName объекта SaveDialog. Вместе эта конструкция сохраняет все строки из RichEdit в текстовый файл. А имя файла мы получаем из свойства FileName. После того как пользователь выбрал или ввел название какого-то файла в диалоге сохранения файла, этот диалог (который по совместительству объект SaveDialog) передает в свойство FileName путь и название этого самого файла. Чтобы вы лучше усвоили все вышесказанное, приведу своеобразную русскую транскрипцию всего содержимого обработчика события FileSaveAs: Если Диалог_сохранения запустился, тогда begin Поле_ввода1.Строки.Сохранить_в_файл(Диалог_Сохранения.Имя_файла); end; Теперь даже человек, не знающий английского языка, поймет, что к чему. Поэтому строчку для открытия текстового файла я приведу без всяких комментариев (вы сами легко разберетесь, что она означает): RichEdit1.Lines.LoadFromFile(OpenDialog.FileName); Ее надо прописать в обработчик клика для кнопки открытия файла. Сама кнопка расположена рядом с кнопкой сохранения. Можете запустить программу. Теперь вы получили полноценный текстовый редактор — можно и писать, и сохранять написанное для потомков, и даже открывать ранее сохраненное. Но останавливаться только на этом было бы странно. Давайте сделаем текстовый редактор еще более функциональным. Смотрите, сколько еще неработающих кнопок осталось на панели инструментов! Значит, есть над чем поработать. Капитальный ремонт Кнопка Новый документ все еще не работает. Но это легко поправить. В обработчике события этой кнопки напишите такую строку: RichEdit1.Clear; Как понятно из названия, эта команда очищает содержимое поля ввода. Теперь кнопка работает. Вы, наверное заметили, что мы назначаем обработчики только кнопкам. А как быть с одноименными пунктами меню? Оказывается, для них обработчики создавать не надо, так как кнопки и пункты меню связаны особой внутренней логикой “Дельфи”.
Кроме нашего кода, в тексте программы еще много разных примочек от “Дельфи”.
Обработчик для кнопки Настройка печати уже готов, значит, нам остается назначить обработчик самой кнопке Печать. Создавайте его и между вторыми begin и end пишите: RichEdit1.Print(‘Текст редактора “Супер”’); Эта строчка отправляет на печать все содержимое RichEdit1, а в качестве параметра процедуре Print мы передаем заголовок распечатки. Далее по списку у нас идет кнопка Отмена. Создавайте для нее обработчик и пишите в нем буквально следующее: with RichEdit1 do if HandleAllocated then SendMessage(Handle, EM_UNDO, 0, 0); Я сейчас не буду объяснять, как действует эта строчка — пока это будет непонятно. Дело в том, что эта строка затрагивает глубинные механизмы Windows, и ее нельзя вот так просто “разложить по полочкам”, как мы лихо поступали с предыдущими командами. Но через несколько номеров мы обязательно вернемся к ней, когда будем копаться в системе. Обработчики для кнопок Вырезать , Копировать и Вставить выглядят следующим образом: RichEdit1.CutToClipboard; RichEdit1.CopyToClipboard; RichEdit1.PasteFromClipboard; Все! Вы только что создали самый настоящий текстовый редактор. Теперь можете называть его своим именем, показывать друзьям и гордиться — вполне заслуженно. Пока редактор, прямо скажем, не перегружен функциями. Но это же только начало. В следующий раз мы вместе проапгрейдим редактор до версии 2.0 и добавим в него такие полезные функции, как поиск и замену, полноценное форматирование стилем, шрифтом, кеглем, гарнитурой, цветом шрифта и фона. Мы причешем и приукрасим его и даже научим понимать файлы популярного текстового формата rtf, который так любят журналисты и верстальщики всего мира. А если у вас что-то не получилось сейчас — не беда. На нашем диске __ вы найдете готовые исходники текстового редактора. *** В ближайших номерах ваша коллекция программ со значком “Сделал сам” пополнится. В наших планах создать вместе с вами графический просмотрщик наподобие ACDSee , медиаплеер, несколько простеньких числовых игр, графический редактор довольно высокого уровня, космическую аркаду, почтовый клиент и даже интернет-браузер. Если все пойдет по плану, то в завершении цикла мы с вами, что называется, выйдем в третье измерение и сделаем настоящую трехмерную игру.
Тонкости текстовки Люди, которые привыкли все делать дотошно, наверняка переведут все строчки программного кода буква к букве. Все верно, но вот на регистр букв внимание можете не обращать. И RichEdit1.CutToClipboard , и richedit1.cuttoclipboard , и даже rIcHeDiT1.cUttOcliPBoArD будут работать одинаково. Количество пробелов до и после строки также безразлично. Команды, отделенные точкой с запятой, можно писать и в столбик, и в строчку, да хоть по диагонали. Главное, чтобы очередность соблюдалась. В “Дельфи” все сделано так, чтобы программист мог получить удовольствие (читай: результат) минимальными усилиями. Порой даже названия свойств или методов вводить не надо. Как только вы поставите разделительную точку, появится небольшой списочек свойств и методов данного объекта. Просто наберите пару-тройку первых букв нужной строки и нажмите Enter — строка автоматически “дополнится”. __
Файлы проекта Наверное, вы уже поняли, что любая программа, которая разрабатывается в “Дельфи”, наделяется громким наименованием Проект. Но проект состоит не из одного файла. Самый главный файл проекта имеет расширение .DPR. Если вы дважды кликнете по такому файлу, весь проект корректно откроется в “Дельфи”. Про другие файлы такого сказать нельзя. Программа может состоять из нескольких модулей (обычно число модулей равно числу смысловых окон, но бывают и исключения). Каждый модуль — это отдельный файл с расширением .PAS (пишем-то на Паскале), в котором находится программный код этого модуля. Если модуль описывает форму, то для него создается еще один файл — с расширением .DFM. Он описывает положения разных компонентов на форме и их свойства. Кроме того, для проекта создается файл с расширением .RES. В нем хранятся прочие ресурсы проекта вроде иконок или курсоров. Но этот файл часто не нужен. После компиляции в папке проекта появляются сам экзешник и несколько вспомогательных файлов. Каждый модуль компилируется отдельно и помещается в файл с расширением .DCU. Вот такая вот арифметика. Тем не менее, если вы захотите перенести свой проект с одного компьютера на другой, вам незачем тащить всю эту файловую братию. Достаточно главного файла проекта (DPR) и файлов всех модулей (PAS и DCU).
Библиотечка начинающего программиста Код — исходный текст программы. Исходник — то же самое, что и код. Компиляция — процесс, в течение которого исходный код преобразуется в конечный exe -файл. Библиотека , Модуль — “кирпичик” будущей программы. Представляет собой отдельный файл, в котором хранится участок исходного кода, выполняющий какую-то конкретную функцию. Существует очень много стандартных библиотек, из которых программисты собирают программы. Таким образом, вся рутина при разработке приложения сводится к минимуму. IDE (Integrated Development Interface) — Интегрированный Интерфейс Разработки. Под этими страшными словами скрывается всего лишь несколько главных окошек Дельфи, с помощью которых ведется разработка программы. Приложение — вот таким неказистым словом назвали разработчики Windows все программы, предназначенные для платформы Wintel (Windows+Intel). Компонент — визуальный “кирпичик”, который ставится на заготовку будущего окна и представляет собой какой-нибудь простой или сложный элемент управления (список, надпись, кнопка — это простые; окно рисования, браузер, окно просмотра анимаций — сложные). Форма — заготовка будущего окна. __
Информация по циклу Мы планируем публиковать в каждом номере по статье из “Кладовой программиста”. Но мы не исключаем, что возможны небольшие перерывы. Например, в случае, если появится материал другой тематики, более актуальный, чем урок из “Кладовой”. Тогда мы поставим эту, более важную статью, а материал с уроком по Delphi опубликуем в следующем номере. Не забывайте, что любой урок из цикла — это самодостаточная статья, которую можно изучать и без знания материала предыдущего урока. Но мы все равно будем выкладывать все предыдущие статьи цикла на компакт, чтобы те, кто начал изучать с нами Delphi не с первого урока, ничего не упустили.