Выпуск 05: Условия...

 
     

Архив рассылки

Доброго времени суток!

Этот выпуск я начну с продолжения предыдущего :)

В прошлом выпуске мы создали программу, которая ищет площадь прямоугольника, где нужные значения вводит пользователь. Теперь всё тоже самое зделаем в консольном приложении:

var
  a, b, s: Real;
begin
 Write('Vvedite storony priamougolnika -> ');
 ReadLn(a, b);
 s:= a*b;
 Write('Plosiad'' priamougolnika ravna ' + FloatToStr(s));
 ReadLn;
end.

Программа вроде правильная :) Она делает всё тоже, что и её сестра с Windows'овским интерфейсом. Но запустите программу. И что видим? Умница Дельфи нашла ошибку: [Error] Project1.dpr(11): Undeclared identifier: 'FloatToStr'. Это значит, что Дельфи не знает что это за функция FloatToStr. Дело в том, что все функции должны быть где-то описанны. Эта функция описанна, но это описание находится в другом файле. Эти файлы называются модулями и их надо подключать к проектам. А подключаются они при помощи слова Uses (использует), после которого надо указать имя модуля, т.е. название файла, в котором эта функция описанна. Для функций, которые конвертируют цифры и числа он называется SysUtils. Приведите программу в такой вид:

{$APPTYPE CONSOLE}

uses
  SysUtils;
var
  a, b, s: Real;
begin  Write('Vvedite storony priamougolnika -> ');
 ReadLn(a, b);
 s:= a*b;
 Write('Plosiad'' priamougolnika ravna ' + FloatToStr(s));
 ReadLn;
end.

...и её запустите. Сейчас всё работает. Если посмотрите на проект Windows Application (который по умолчанию бывает при включении Дельфи), то там вверху среди кучи других тоже можно найти SysUtils.

Но почему работают функции Write и Read? В косольном приложении (хоть и не видно) автоматически к проекту бывает подключён модуль System. Чтобы открыть модуль, в котором описанна функция, нажмите клавишу Ctrl и наведите курсор на нужную функцию или модуль. Эта функчия/модуль должны быть подчёркнутыми:

http://spider3d.narod.ru/img/05/01.gif

Кликните на эту подчёркнутую область и откроется модуль. Курсор сразу перейдёт на место описания функции (если вы кликали по ней). Подключите к проекту модуль Math и его откройте.

uses
  SysUtils,
  Math;

Просмотрите этот модуль, там можно найти много полезных функций, например:

 Sin(X) - синус
 Cos(X) - косинус
 Tan(X) - тангенс
 Cotan(X) - котангенс
 LogN(Base, X) - логарифм -> Base - основание, X - число
 Power(Base, Exponent) - возведение в степень -> Base - число, Exponent - степень

В Дельфи таких модулей тьма! :)

Поскольку вы уже знаете, что такое модули, можно по чуть-чуть переходить на WinAPI ;)

Первые шаги

Итак, создайте новое консольное приложение и сразу его сохраните. Сотрите все строчки, кроме begin..end.. Теперь добавим модули, которые нужны для создания Windows приложения. Эти модули называются Windows и Messages.

uses
  Windows,
  Messages;

begin

end.

В модуле Windows находятся функции, которые нужны для создания окна, а также для его управления. В модуле Messages описанны все сообщения (о которых поговорим чуть-чуть по позже :).

Вот и всё пока :) Этот проект будет шаблоном для нашых OpenGL программ, но мы его ещё не скоро завершим.

Комментарии

Комментарии - одно из самых замечательных вещей в программировании, которое облегчает работу (конечно, облегчение зависит от программиста :). Комментарии это часть кода, которая игнорируется компилятором, так что там можно писать что угодно. "Что угодно" - вещь условная :) Вам совсем незачем в середину кода пихать стихи или слова песен :) Комментарии обычно используются для объяснения кода. В дальнейшем я везде буду использовать комментарии, и вам советую, чтобы потом не путаться в коде (если забудете, что делает кокая-либо строчка).

Существуют два варианта комментариев:

 1. Комментарий - строчка. Таким способом записываются короткие заметки
 2. Комментарий - текст. Такие комментарии используются, когда нужны длинные объяснения, занимающие несколько строк.

Чтобы создать комментарий первого типа, надо перед ним поставить два слэша. Пример:

WriteLn('Hello, World!'); // Это комментарий первого типа

Всё, что находится за двумя слэшами является комментарием. Такой комментарий не может занимать больше одной строки. Если его надо продолжить (в новой строке), нужно опять ставить слэши:

WriteLn('Hello, World!'); // Это комментарий первого типа
// Функция "WriteLn()" отображает текст 'Hello, World!' на экране. Она описанна в модуле System.pas (модули имеют расширение *.pas)

Комментарии второго типа выглядят по другому. Они имеют свои "командные скобки", между которыми всё и записывается. Этими скобками являются фигурные скобки ({ и }), а также скобки со звёздочками ( (* и *) ). Пример:

{ Это
  типа
  очень
  длинный
  комментарий }

WriteLn('Hello, World!');

(* Этот
  комментарий абсолютно
  бессмысленный! *)

Думаю, вы поняли (тут и нечего понимать :)

Условный оператор и логические выражения

Это очень важная тема в программировании, потому что эти операторы помогают делать разные выборы, без которых в программировании не выжить :)

Логические выражения в программировании такие же, как и в математике:

 = - равно
 > - больше
 < - меньше
 >= - не меньше
 <= - не больше
 <> - не равно
 - - отрицание

С этим всё ясно. Результат сравнения является типа Boolean, так что такая программа будет правильная:

var
  i: Boolean;
begin
 i:= 50>10;
 WriteLn(i);
 ReadLn;
end.

Результат будет слово "True" (правда), поскольку 50 действительно больше, чем 10. Эта программа тоже выведет результат "True":

i:= -50<10;
WriteLn(i);

-50 меньше, чем 10, но если убрать минус - результатом будет слово "False" (не правда).

Логические выражения используются в условных операторах. Условный оператор звучит так: ЕСЛИ то_да_это ТО делать_одно ИНАЧЕ делать_другое :) (только без смайлика в конце :) Вот пример:

begin
 If (50>10)
  Then
   WriteLn('50 bol''se, cem 10!')
  Else
   WriteLn('Nu, drugovo varianta tocno ne budet! :)');
 ReadLn;
end.

Если результат сравнения (50>10) будет равен True, то выполнится код, находящийся после слова Then, иначе выполнится код, который находится после слова Else. Запомните: перед Else нельзя ставить точку с запятой!!! Но можно вообще не использовать Else. Тогда, конечно, не будет запасного варианта, но он не всегда и нужен. Ещё один пример:

{$APPTYPE CONSOLE}

uses SysUtils;

var
  a, b: Integer;
begin
 ReadLn(a, b);
 If (a > b)
  Then
   begin
    WriteLn('"a" bol''se, cem "b"!');
    WriteLn('Plosiad'' kvadrata so storonami "a" ravna ' + IntToStr(a*a));
   end
  Else
   begin
    WriteLn('"b" bol''se, cem "a"!');
    WriteLn('Plosiad'' priamougolnika so storonami "a" i "b" ravna ' + IntToStr(a*b));
   end;
 ReadLn;
end.

Если "a" больше, чем "b", то программа ищет площадь квадрата, в противном случае - прямоугольника со сторонами a и b.

Как видно в примере, можно использовать и несколько функций в условном операторе для каждого варианта. Надо просто открыть новые "логические скобки". Когда их закрываете, после "end" надо ставить точку с запятой, а не точку, потому что эти скобки не завершают проект. Самый последний end - завершающий, по этому там и стоит точка. Можно также использовать условные операторы в условных операторах. Это легко и очень удобно. Это зделать уже сможет каждый. Только не забывайте закрывать все скобки:

begin
 If (50 > 10)
  Then
   If (-30 < -1500)
    Then
     WriteLn('True')
    Else
     WriteLn('False')
  Else
   If (50 = 50)
    Then
     WriteLn('True')
    Else
     WriteLn('False');
 ReadLn;
end.

Пример, конечно бессмысленный, но главное, чтобы вы поняли как всё работает.

Теперь Задание #5: напишите программу, которая находит самое большое и самое маленькое значение из трёх, которые вводит пользователь. Если вы поняли как действует условный оператор, то вам это будет легко.

Сообщение, ссылка

Событие указывает, когда программа должна выполнять нужные действия, например событие OnCreate (для формы) говорит, что программа начнёт выполнять все действия сразу, когда будет включена, а всё, что находится в событие OnMouseMove будет выполняться, когда пользователь подвигает мышку. Мы уже работали с событием OnClick (для кнопки).

Для каждого события операционная система программе посылает нужное сообщение, которое говорит приложению, что пора выполнять какие либо действия. Можно и ничего не делать :) Когда вы работаете в Delphi используя VCL (библиотеку визуальных компонентов), вы работаете с событиями, а в невизуальном программировании мы будем "ловить" сообщения.

Все сообщения начинаются с префикса WM_ (windows message), а аналогичные события начинаются с префикса On("при", OnClick = при нажатии). Всё остальное совпадает, например для события OnCreate посылается сообщение WM_Create.

Т.е.: Windows посылает программе сообщение о том, что произошло какое то событие и программа начинает исполнять действия, которые должны исполняться при нужном событии. Даже окно, не имеющее фокуса, может получать сообщения о произошедших событиях.

Каждое окно имеет свою ссылку (дескриптор, описатель), по которой к нему обращается операционная система. Тип этой величины в Delphi – HWND (window handle – ссылка на окно). Ссылку на окно может использовать не только операционная система, но и любое другое приложение, желающее поработать с другими окнами.

Сейчас я приведу пример использования ссылок в Delphi. Этот пример будет искать окно обычного блокнота :)

Откройте Delphi и на появившейся форме поставьте обычную кнопку (TButton). Работать будем в событии OnClick для этой кнопки. Два раза щёлкните на кнопке и создайте переменную – ссылку на окно (типа hwnd).

procedure TForm1.Button1Click(Sender: TObject);
var
  NotePad: hwnd; // ссылка на окно
begin

end;

С помощью этого дескриптора (ссылки) мы будем искать окно блокнота. Важно: нельзя найти окно, если не знаете класса и/или заголовка окна.

По умолчанию, заголовок окна у блокнота – "Безымянный – Блокнот" (в русской версии Windows). Имя класса – "Notepad". Для поиска окна существует функция FindWindow (искать окно). У неё есть 2 параметра:

1. Класс окна
2. Заголовок окна

Если одного элемента не знаем, нужно писать nil. Для наилучшего поиска надо указать оба параметра. Поскольку я знаю оба из них, можно начать поиск.

procedure TForm1.Button1Click(Sender: TObject);
var
  NotePad: hwnd; // ссылка на окно
begin
// в переменную записывается результат поиска окна
 NotePad:= FindWindow('Notepad', 'Безымянный - Блокнот');
// если окно будет найдено, то результатом будет единица,
// в противном случае - 0
 If NotePad <> 0
  Then
   ShowMessage('Notepad found') // окно найденно
  Else
   ShowMessage('Notepad not found'); // окно не найденно
end;

Если вы включите блокнот, то программа его найдёт, но если там будет открыт документ, программа его не сможет найти, потому что заголовок окна не совпадёт. В таком случае, вместо заголовка можно поставить nil.

Многие из вас могут спросить "как это связанно с OpenGL?". Именно эти функции никак не связанны, просто я хочу объяснить для чего нужна ссылка на окно и как её можно использовать в своей программе (она будет нужна в OpenGL). Чтобы ваша программа работала, вам нужно будет создать ссылку на окно вашего приложения, чтобы операционная система знала по какому адресу посылать сообщения.

Примечание: в проектах OpenGL мы не будем использовать функцию ShowMessage (как в примере), потому что она требует подключения модуля Dialogs, который не мало "весит". Вместо неё будем использовать функцию MessageBox, как пользоваться которой я вам расскажу позже.

Имея ссылку на другое окно ваша программа может с им делать почти всё, что хочет, например послать окну сообщение, что ему пора закрыться. Для этого используется функция SendMessage. В первом параметре указывается ссылка на окно (класс и/или заголовок), во втором указывается тип сообщения. 3 и 4 параметры, которые называются wParam и lParam, определяются в каждом конкретном сообщение по-своему. Например, чтобы минимизировать окно, нужно написать следующее:

SendMessage(NotePad, WM_SYSCOMMAND, SC_MINIMIZE, 0);

Окну сначала сообщается, что нажата кнопка в системном меню, а потом, что эта кнопка минимизации окна, поскольку их там не меньше 3-х.

В сообщении о закрытии окна они не используются, по этому вместо них можно поставить нули. Пример:

SendMessage(NotePad, WM_CLOSE, 0, 0);

Тут тому-же самому блокноту посылается сообщение, что ему надо закрыться и он выполняет действия, которые должны исполниться при событии OnClose, т.е. тупо закрывается (выводя табличку с вопросом о сохранении файла, если там были изменения).

Чтобы узнать класс окна, можно пользоваться утилитой WinSight32, которая предоставляется вместе с Delphi.

Ссылка, в зависимости от версии Delphi, соответствуют типам Integer или LongWord, но это вам знать не обязательно :)

Возвращаемся к Windows API

Откройте проект с будущем OpenGL приложением, т.е. шаблон, который мы не давно начали. Приведите его в такой вид:

uses
  Windows, // Модуль для работы с окном
  Messages; // Модуль для работы с сообщкниями

var
  Wc: TWndClassEx; // Переменная для определения класса окна
  Wnd: HWND; // Ссылка на окно
  Msg: TMsg; // Переменная для хранения сообщений

begin

end.

Переменная Msg нам нужна для обработки сообщений, а Wc - для описания нами создаваемого окна.

К сожалению продолжать нельзя :) Для этого надо выучить ещё две темы.

Вам на помощь! :)

Не знаю заметили вы или нет, но после нажатия точки (например Edit1.Text) появляется список разных команд. Это список возможных функций и пр. Для чего этот список нужен? Чтобы не пришлось печатать всё название функции. Поставьте на форму компонент Edit и Button. Два раза щёлкните на кнопке. В редакторе напечатайте Edit1 и поставьте точку. Подождите пока появится этот список. Теперь начните печатать слово Text, только не спешите. Когда нажмёте букву "T", в списке останутся только те функции, которые начинаются с этой буквы. Продолжайте печатать, пока в списке не выделится "Text" и нажмите ENTER. Может пример и не впечатляет, но есть функции с очень длинными названиями и этот список помогает экономить время, а также избегать ошибок.

На сегодня хватит. Длинный выпуск получился :) Хорошо выучите этот материал (особенно условный оператор), потому что это будет использоваться почти в каждой программе.
 

2005-10-08

Автор, ведущий и дизайнер рассылки: Евгений Нарышкин (spider3d@yandex.ru)

OpenGL для начинающих (under construction): http://spider3d.narod.ru/

Хостинг от uCoz