Стандартные элементы интерфейса Используйте стандартные для данного элемента интерфейса компоненты. Встретив Вашу программу, пользователь не будет терять время на знакомство, а сразу приступит к работе - это один из признаков профессионально сделанной программы. Небольшая палитра инструментов Старайтесь использовать не слишком большое количество разнообразных компонентов. И естественно, использовав где-то в одном месте один стандартный компонент, в аналогичном случае также применяйте именно его. Одинаковое расстояние между элементами управления Располагайте элементы интерфейса на одинаковом расстоянии между собой. Разбросанные как попало компоненты создают ощущение непрофессионально сделанного продукта. И наоборот, тщательно выверенное размещение на Форме кнопок, переключателей, флажков и других компонентов, составляющих интерфейс — признак качественной работы. TabOrder. "Правильный" порядок TabOrder - это порядок перемещения экранного курсора по элементам управления при нажатии клавиши Tab. В правильно написанной программе курсор перемещается, следуя логике работы пользователя с программой. При создании же программы программист часто меняет компоненты, одни удаляет, другие добавляет по мере необходимости. В результате в готовой программе курсор хаотично скачет по Форме. Завершив программу, не забывайте настроить TabOrder. Выбор шрифтов Шрифты просто оставьте в покое. Заданные по умолчанию самой Delphi шрифты подойдут для любой системы, на которой может работать Ваша программа. Полужирный шрифт используйте только для выделения важных элементов. Применение же курсива и особенно подчёркивания, которое пользователь может принять за гиперссылку - дурной тон. Выбор цветов Что касается цветов элементов интерфейса, то также, как и в случае со шрифтами, лучше оставьте их стандартными, по умолчанию. Delphi использует системную палитру Windows, и пользователь, изменив её, легко настроит цвета под себя. Альтернативное управление Профессионально сделанная программа должна иметь возможность управляться не только мышкой, но и с клавиатуры. Не должно быть функций, доступных выполнению только мышью (рисование в графических редакторах не в счёт!). Для наиболее используемых функций следует предусмотреть "горячие клавиши" для их быстрого вызова. Кирпичики интерфейса Что касается конкретных элементов интефейса пользователя, то качество взаимодействия пользователя с программой зависит от: - соответствия элемента управления выполняемой им задаче;
- правил, по которым функционирует элемент управления.
На этой страничке рассматриваются правила создания некоторых элементов интерфейса. А сейчас хочу показать, какие инструменты предлагает Delphi для управления компонентами на Форме, их взаимным расположением и поведением курсора при нажатии клавиши Tab. Для того, чтобы расположить относительно друг друга компоненты в правильном порядке, сначала необходимо их выделить. Можно просто обвести мышкой область на Форме, в которой содержатся выбранные компоненты. Или, удерживая "Shift", указать той же мышкой каждый подлежащий выделению компонент. Повторный щелчок мышкой по выделенному компоненту (при нажатом "Shift") снимает с него выделение. Выделенными компонентами можно управлять как единым целым - передвигать по Форме, присвоить значение одинаковым свойствам, скопировать (для установки, например, на другую Форму), даже удалить. Выделение мышкой области с компонентами | Группа выделенных компонентов |  |  | Теперь щёлкните правой кнопкой по одному из компонентов, и из "всплывающего" меню выберите Position -> Align... Появится диалоговое окошко, позволяющее настроить положение компонентов в группе по горизонтали и вертикали. Например, нам нужно выровнять наши четыре кнопки по левому краю и сделать так, чтобы между ними было одинаковое расстояние по вертикали. Для этого выделим радиокнопки Horizontal: Left sides и Vertikal: Space equally. Доступ к меню выравнивания | Диалог выравнивания компонентов | Результат выравнивания группы компонентов |  |  |  | Выбрав пункт Center, мы расположим компоненты так, что их центры будут располагаться на одной линии по горизонтали или вертикали, а пункт Center in window перемещает компоненты в центр окна, также по горизонтали или вертикали. В этом же меню строка Tab Order... вызывает появление диалогового окна, управляющего перемещением курсора по элементам интерфейса при нажатии клавиши Tab. В момент появления Формы на экране курсор будет находиться, естественно, на компоненте, располагающемся на первой строчке диалогового окна. И далее будет перемещаться вниз по списку. На диалоговом окне две синие стрелочки "вверх" и "вниз" управляют положением выделенного компонента. Выделяйте нужный компонент, стрелками перемещайте на нужную строчку в списке, и так далее. При выборе пункта меню Control -> появляется подменю, состоящее из двех пунктов: - Bring to Front
- Send to Back
Это методы компонента, доступные также программно. Button1.SendToBack перемещает кнопку на "задний план", а Button1.BringToFront - на "передний план". То есть, если один компонент располагается над другим, эти методы меняют их местами. Случаи, в которых это может применяться, довольно очевидны. Урок 15 Многопоточность Потоки в Delphi выполняют функцию имитации псевдопараллельной работы приложения. Как известно, для организации многозадачности операционная система выделяет каждому приложению, выполняющемуся в настоящий момент, определённые кванты времени, длина и количество которых определяется его приоритетом. Поэтому объём работы, который приложение может выполнить, определяется тем, сколько таких квантов оно сможет получить в единицу времени. Для операционной системы каждый поток является самостоятельной задачей, которой выделяются кванты времени на общих основаниях. Поэтому приложение Delphi, умеющее создать несколько потоков, получит больше времени операционной системы, и соответственно сможет выполнить больший объём работы. Создать дополнительный поток в Delphi поможет объект TThread. Ввести объект TThread в программу можно двумя способами: 1. с помощью Мастера; 2. вручную. 1. Мастер создания дополнительного потока в Delphi создаёт отдельный модуль, в рамках которого выполняется поток. Выполним: File -> New -> Other... В появившейся табличке выбора найдём TThread Object. Появится окошко, в верхнюю строку которого (Class Name) введём имя нашего будущего потока: MyThread. В результате будет создан модуль, содержащий заготовку кода, реализующего дополнительный поток Delphi: unit Unit2; // Имя модуля, содержащего поток. При сохранении его можно изменить. Interface uses Classes; type MyThread = class(TThread) //MyThread - заданное нами имя потока. private { Private declarations } protected procedure Execute; override; end; Implementation { Important: Methods and properties of objects in visual components can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure MyThread.UpdateCaption; begin Form1.Caption := 'Updated in a thread'; end; } { MyThread } procedure MyThread.Execute; begin { Place thread code here } end; end. 2. В первом способе класс MyThread был создан мастером в дополнительном модуле. Второй способ состоит в том, что мы сами создаём такой класс в рамках одного из уже существующих модулей программы, например, в модуле Unit1: unit Unit1; //Обычный модуль в котором описывается основная программа Interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; //Здесь необходимо описать класс TMyThread: TMyThread = class(TThread) private { Private declarations } protected procedure Execute; override; end; var Form1: TForm1; //Нужно ввести переменную класса TMyThread MyThread: TMyThread; Implementation {$R *.dfm} //Нужно создать процедуру Execute, уже описанную в классе TMyThread procedure TMyThread.Execute; begin //Здесь описывается код, который будет выполняться в потоке end; Если поток создаётся мастером, т.е. в другом модуле, то не забудьте в основном модуле описать переменную - экземпляр потока, как указано выше. Также, поскольку класс потока описан в другом модуле, имя этого модуля необходимо добавить в секцию uses. Теперь можно запускать поток, даже если в его процедуре Execute нет ни единого оператора. //Запускать поток будем нажатием на кнопку: procedure TForm1.Button1Click(Sender: TObject); begin //Вначале нужно создать экземпляр потока: MyThread:=TMyThread.Create(False); //Параметр False запускает поток сразу после создания, True - запуск впоследствии , методом Resume //Далее можно указать параметры потока, например приоритет: MyThread.Priority:=tpNormal; //Можно указать что после завершения кода поток завершится автоматически: MyThread.FreeOnTerminate:=true; end; end. Ну вот, даже этот минимальный код позволяет поэкспериментировать с потоками и посмотреть, что они создаются в системе, работают, уничтожаются. Например, измените условие завершения потока: MyThread.FreeOnTerminate:=false; //Поток не будет уничтожен после завершения работы Теперь в Диспетчере Задач Windows можно наблюдать, что при каждом нажатии на кнопку Button1 в нашем приложении количество потоков в проекте Project1 увеличивается. А теперь поместите в процедуру Execute такой оператор: MyThread.Terminate; Метод Terminate уничтожает данный экземпляр потока. Теперь при нажати кнопки в приложении количество потоков всё равно остаётся равным 1 (это главный поток приложения), так как сразу после создания новый поток уничтожается методом Terminate, и мы просто не успеваем заметить краткий миг его существания. Тем не менее, это означает, что код потока в процедуре Execute выполняется! Ещё пример. Если в основной программе попробовать выполнить такой цикл: while True do; то приложение зависнет. А теперь поместите его в процедуру Execute. При нажатии на кнопку наш бесконечный цикл будет непрерывно выполняться в потоке, однако и приложение как целое не зависнет. При работе с потоками необходимо учитывать приоритет создаваемых потоков. Так, если в предыдущем примере запустить не один поток, а два или больше, то компьютер станет очень заметно "тормозить". Это происходит потому что приоритет по умолчанию новых потоков - нормальный. Можно уменьшить его, задав MyThread.Priority:=tpLower; Этого достаточно, чтобы компьютер чувствовал себя более свободно. Вот таблица приоритетов: Приоритет | Описание | tpIdle | Низший приоритет. Поток получает время только тогда, когда операционая система находится в состоянии простоя. | tpLowest | Приоритет на два пункта ниже нормального | tpLower | Приоритет на один пункт ниже нормального | tpNormal | Нормальный приоритет | tpHigher | Приоритет на один пункт выше нормального | tpHighest | Приоритет на два пункта выше нормального | tpTimeCritical | Максимальный приоритет. Приоритет на уровне функций ядра операционной системы. | Вот вам готовый проект работы c потоками, для экспериментов. В продолжение темы нужно рассмотреть |