Главная страница ЕЖИдневника


Уроки по Delphi

Урок 6
Внеурочье
Урок 5 Графические часы
Урок 4
Внекласс-1
Урок 3
Урок 2
Урок 1
Урок 0
Уроки по Dephi

Урок 4. Динамическое изменение внешнего вида программы

Исходные тексты программы в ближайшее время будут здесь. ;о)


Оператор if. Понятие переменной. Локальные переменные. Тип integer. Целочисленное деление. «Привязка» компонентов к краям формы. Событие OnResize формы.

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

Давай сделаем так, чтобы внешний вид надписей изменялся при изменении размера окна программы. У метки Label4, в которой ты выводишь дату и время, будем изменять размер шрифта так, что бы надпись всегда занимала всю ширину окна. Все остальные надписи должны выравниваться по центру. Кроме того, мы запретим форме становиться меньше некоторого наперёд заданного размера. Для этого нам потребуется оператор

if (условие)
then (команда1)
else (команда2);


Смысл этого оператора очень прост: если выполняется (условие), то выполняй команду1, иначе — выполняй команду2. Если нужно выполнить несколько команд, то их нужно заключить в операторные скобки begin – end. Я советую всегда использовать операторные скобки, даже если в них будет находиться всего одна команда. Конечно, текст программы немного увеличится, но, на мой взгляд, повысится её читабельность. Вот так:

if (условие)
then begin
  (команда1);
  (команда2);
end
else begin
  (команда3);
end;


Обрати внимание на пунктуацию. Да, чуть не забыл, ветку else этого оператора можно опустить. Ещё нам потребуются переменные. Переменная — это специально выделенный участок памяти компьютера для временного хранения информации. Переменная доступна по своему имени. Например, нам нужно использовать в каком-то участке программы некоторое число, которое рассчитывается в другом участке программы. Тогда мы должны создать переменную, присвоить ей нужное значение, после чего мы можем использовать имя этой переменной в выражениях, а программа вместо имени будет подставлять значение переменной. До сих пор мы обходились без переменных, но активно использовали свойства компонентов, которые можно рассматривать как переменные. (Свойства компонентов устроены немного сложнее, чем переменные, но используются они точно так же). Переменная характеризуется своим типом. Тип переменной определяет какого рода данные могут быть записаны в переменную. Скажем, если переменная целочисленная, то ей можно присвоить только целые числа, переменной вещественного типа можно присвоить дробные числа, строковой переменной — текстовые строки и т.д. В Delphi существует огромное количество различных типов. Кроме того, программист может на основе имеющихся определить новые типы.

Итак, план действий:

1. В обработчик события OnTimer нашего таймера между заголовком процедуры и словом begin добавь код:

var w : integer;

Слово var говорит, что мы собираемся описать новые переменные. То, что это слово находится внутри процедуры, означает, что эти переменные будут локальными, то есть доступными только в этой процедуре. w — это имя нашей переменной, а integer означает, что переменная w будет целого типа. В тело процедуры поместим код:

  w := Label4.Width+2*Label4.Left;
  if w <= Form1.ClientWidth
  then begin
    Label4.Font.Size := Label4.Font.Size+1;
  end;
  if w > Form1.ClientWidth
  then begin
    Label4.Font.Size := Label4.Font.Size-1;
  end;

Свойство ClientWidth формы возвращает ширину «клиентской» области окна программы, то есть той области, где могут размещаться компоненты. В первом условии мы проверяем что больше ширина «клиентской» области или ширина метки плюс ширина пустого пространства слева и справа от метки (мы просто умножаем свойство Left на 2, что гарантирует нам, что справа останется столько же места, как и слева) — именно это мы присвоили переменной w. Если ширина метки и пустого пространства меньше либо равно ширине формы, то увеличиваем размер шрифта метки на 1. Во втором условии проверяем тоже, только знак стоит больше, и в результате уменьшаем размер шрифта на 1.

Почему нельзя воспользоваться веткой else, и обойтись одним условием, а не двумя? Ха! А это тебе будет домашнее задание.

2. Добавим в тот же обработчик код:

  Label1.Left := (Form1.ClientWidth-Label1.Width) div 2;
  Label2.Left := (Form1.ClientWidth-Label2.Width) div 2;
  Label3.Left := (Form1.ClientWidth-Label3.Width) div 2;
  Label5.Left := (Form1.ClientWidth-Label5.Width) div 2;

То есть выравнивание по центру происходит в результате расчёта на какое расстояние от левого края нужно переместить каждую метку. Операция div — это целочисленное деление. Вспоминай арифметику на уровне 1 класса. Деление целых чисел, деление с остатком... Никаких дробей при использовании div ты не получишь.

3. Уменьшим ширину Memo1 так, что бы оно полностью умещалось на форме (исчезла бы горизонтальная полоса прокрутки). И увеличим высоту так, что бы могли уместиться две строчки. Изменим свойство Alignment на taCenter (теперь текст в Memo1 будет выравниваться по центру). Изменим свойства Anchors: akTop выставим в false, а akRight и akBottom — в true. Это означает, что теперь компонент Memo1 будет «привязан» к левому, правому и нижнему краям формы. То есть при изменении ширины окна Memo1 будет деформироваться, а при изменении высоты — смещаться вслед за нижним краем.

4. Аналогично п.3 можно привязать метку Label5 к нижнему краю и отвязать её от верхнего края, а вот привязка её к левому и правому краям ничего не даст — размер метки подстраивается автоматически под её содержимое.

5. Создадим у формы разработчик события OnResize (возникает при изменении размера формы) и введём в него следующий код:

  if Form1.Width < 350
  then begin
    Form1.Width := 350;
  end;
  if Form1.Height < 370
  then begin
    Form1.Height := 370;
  end;

Тем самым как только ширина станет меньше 350 пикселей, мы будем возвращать её к этому размеру. Аналогично высота формы будет ограничена 370 пикселами.

Домашнее задание. Переделать пункт 1, используя оператор if с двумя ветками. Разобраться почему два оператора if с одной веткой работают корректно, а один оператор с двумя ветками (казалось бы - полный аналог) работает плохо. Изменить условие в операторе так, что бы работало хорошо.

На следующем уроке мы сделаем графические часы.

Alёna: Крокодил не ловится, не растёт кокос... :о( Чёт не ладится у меня программа, много у меня к ней вопросов. Причём сплошь нецензурных... :о((

AЛександр:Ну дык это... Может как-нибудь упрОстим и ускОрим процесс? Народ ведь ждёт! Вопросы-то озвучь.

Alёna: 1. Метки при изменении размеров формы в ту или иную сторону начинают двигаться куды им заблагорассудится, перекрывая друг друга... Я их неправильно привязала? Может, половину стОит привязать к верху, а другую к низу? И изменять размер шрифта в них всех - соответственно изменению размера формы, по образу и подобию изменения в таймере? А какой обработчик использовать?

Aлександр: Угу. Совсем неправильно! Все, которые выше метки с датой и временем - к верхнему и левому краям. Те, которые ниже - к нижнему и левому. А Memo1 к нижнему, левому и правому краям. Разве я не так с самого начала говорил?

Aлександр:
A> И изменять размер шрифта в них всех - соответственно
A> изменению размера формы, по образу и подобию изменения в таймере?
Можно и так. Хотя я говорил о центрировании меток.
A> А какой обработчик использовать?
??? Если ты хочешь добиться эффекта плавного изменения размера используй TForm1.Timer1Timer, если сразу при изменении формы - TForm1.FormResize.

Alёna: 2. Собсно метка со временем/датой тоже отплясывает чечётку. Я тебе на это уже жаловалась. Подрагивание, о котором ты мне говорил, я видела в программе Ценителя. А у меня всё совсем не так. Напомни, плиз, что ты мне предлагал сделать?

Aлександр: Упс. Кажется я слегка перестарался.

Сравни варианты:

w := Label4.Width+2*Label4.Left;
   if w <= Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size+1;
   end;
   if w > Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size-1;
   end;

и:

if Label4.Width+2*Label4.Left <= Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size+1;
   end;
   if Label4.Width+2*Label4.Left > Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size-1;
   end;

В первом случае метка должна дёргаться. Во втором - нет. Точнее во втором случае она тоже будет дёргаться, только *очень* быстро. Именно это соображение заставляет написать код с одним условием if. Но тогда в обоих случаях метка будет дёргаться:

w := Label4.Width+2*Label4.Left;
   if w <= Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size+1;
   end
   else begin
     Label4.Font.Size := Label4.Font.Size-1;
   end;

Или:

if Label4.Width+2*Label4.Left <= Form1.ClientWidth
   then begin
     Label4.Font.Size := Label4.Font.Size+1;
   end;
   else begin
     Label4.Font.Size := Label4.Font.Size-1;
   end;

A> Напомни, плиз, что ты мне предлагал сделать?
Чтобы она не дёргалась нужно исправить условие. Вместо "Label4.Width+2*Label4.Left <= Form1.ClientWidth" написать что-то другое. Более сложное. Причём чуть-чуть за рамками того, что я уже объяснял. Ещё раз "Упс". Я в задании указал, что это "за рамками", и будет хорошо, если ты опишешь условие хотя бы словами (если в литературе не найдёшь нужного слова)? Или забыл? Впрочем, можно решить так как это сделал <забыл как зовут, ты его ещё поругала, что, дескать, всю малину тебе испортил, прислав программу на следующий же день>. Тогда всё будет в рамках. Но это не самое эффективное решение. Итого: два раза "упс"... Хреновенький из меня преподаватель. :-( Всё-таки задание оказалось слишком сложным и это моя вина. Исправляться надо.


Все комментарии (цензурные и по возможности грамотные) рассматриваются в порядке живой очереди, принимаются к сведению и даже публикуются на сайте. Так что если тебе есть что сказать по поводу вышепрочитанного - мыль сюда!!! ;)

пользовательское соглашение, политика конфиденциальности