Создание своего диалога выбора цвета

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

В общем приступим! Сначала создаём форму и помещаем туда всё необходимое:

7 компонентов типа TImage и назовём их так:

• MainViewer – экран вывода градиента;

• ScalKontr – определяет присутствие изменяемого компонента RGB цвета в градиенте (если выбран R _ GB - то красного, если G _ RB – то зелёного, если B _ RG – то синего) от 0 до 255, путем нажатия курсора на нужную область.

• Yarcost – шкала яркости выбранного оттенка.

• Proba 1 – для выода цвета, находящегося под курсором при выборе насыщенности компонентом ScalKontr.

• Proba 2 – для вывода оттенка, находящегося под курсором при выборе результата и яркости с помощью MainViewer или Yarcost.

• ImageZahvat – для вывода выбранной в ScalKontr насыщенности.

• Itog – для вывода выбранного оттенка.

12 Edit-ов , 3 RadioButton и 2 кнопки . Их оставим в покое (в смысле не переименовываем).

Теперь нам необходимо определиться с необходимыми процедурами.

Во-первых – это процедура генерирования шкалы контраста.
Во-вторых – это процедура генерирования градиента в MainViewer (в соответствии с выбранным типом градиента и выбранной насыщенностью).
В-третьих – процедура генерирования шкалы яркости, в соответствии с выбранным оттенком.

Начнём с первого. Сам нижеприведённый код я поместил в обработчик OnCreate формы.

Пояснения смотрите в комментариях к коду:

var
LineColor, ViewColor: TColor;
ColR, ColG, ColB, i, j:integer;
begin
{Если выбран баланс Красного с Синим и Зелёным (R_GB)}
if RadioButton1.Checked then
begin
ColR:=255;
ColG:=0;
ColB:=0;
for j:=0 to 255 do
begin
LineColor:=RGB(255-j, 0, 0); //Изменяем значение красного цвета
for i:=0 to 17 do
begin
ScalKontr.Canvas.Pixels[i, j]:=LineColor; //рисуем точку
end;
end;
end;
{Если выбран баланс Зелёного с Красным и Синим (G_RB)}
if RadioButton2.Checked then
begin
ColR:=0;
ColG:=255;
ColB:=0;
for j:=0 to 255 do
begin
LineColor:=RGB(0, 255-j, 0); //Изменяем значение зелёного цвета
for i:=0 to 17 do
begin
ScalKontr.Canvas.Pixels[i,j]:=LineColor; //рисуем точку
end;
end;
end;

{Если выбран баланс Синего с Красным и Зелёным (B_RG)}
if RadioButton3.Checked then
begin
ColR:=0;
ColG:=0;
ColB:=255;
for j:=0 to 255 do
begin
LineColor:=RGB(0, 0, 255-j); //Изменяем значение синего цвета
for i:=0 to 17 do
begin
ScalKontr.Canvas.Pixels[i,j]:=LineColor; //рисуем точку
end;
end;
end;

Думаю здесь всё понятно. Далее приступим к основной процедуре рисования градиента в MainViewer. Вот код:

{========================================================== Процедура генерации RGB-градиента}
procedure GenerateRGBInOutGrad(ClrOutR, ClrOutG, ClrOutB: Integer);
var
i, j: Integer; //счётчики
PixelColor: TColor; //цвет пиксела
Holst: TBitMap; //Объект для записи пикселей
begin
Holst:=TBitMap.Create; //создаём объект типа TBitMap
Holst.Width:=256; //указываем ширины
Holst.Height:=256; //указываем высоту

if ClrDialog.RadioButton1.Checked then //если выбрана RadioButton1
begin
{Палитра красного с зелёным и синим}
for j:=0 to 255 do //цикл по оси Y
begin
for i:=0 to 255 do //цикл по оси X
begin
PixelColor:=RGB(ClrOutR, j, i); {привязываем значения зелёного и синего к
изменениям координат и переводим из RGB в
TColor}
Holst.Canvas.Pixels[i, j]:=PixelColor; //Рисуем точку
end;
end;
end;

if ClrDialog.RadioButton2.Checked=true then //если выбрана RadioButton2
begin
{Палитра зелёного с красным и синим}
for j:=0 to 255 do //цикл по оси Y
begin
for i:=0 to 255 do //цикл по оси X
begin
PixelColor:=RGB(j, ClrOutG, i); {привязываем значения красного и синего к
изменениям координат и переводим из RGB в
TColor}
Holst.Canvas.Pixels[i, j]:=PixelColor; //Рисуем точку
end;
end;
end;

if ClrDialog.RadioButton3.Checked=true then //если выбрана RadioButton3
begin
{Палитра синего с красным и зелёным}
for j:=0 to 255 do //цикл по оси Y
begin
for i:=0 to 255 do //цикл по оси X
begin
PixelColor:=RGB(j, i, ClrOutB); {привязываем значения красного и зелёного к
изменениям координат и переводим из RGB в
TColor}
Holst.Canvas.Pixels[i, j]:=PixelColor; //Рисуем точку
end;
end;
end;
ClrDialog.MainViewer.Canvas.Draw(0,0,Holst); //рисуем всю картину на компонент TImage
Holst.Free; //освобождаем память, занимаемую объёктом Holst
end;

Вот!

Ну и, наконец, код вывода шкалы яркости:

{========================================================== Процедура генерации полосы яркости выбранного оттенка}
procedure GenerYarkost(ColR, ColG, ColB: Real);
var
i, j: integer; //счётчики
LineColor: TColor; //цвет TColor
StepR, StepG, StepB: Real; {шаг изменения для каждого цвета,
необходимы для равномерного смешивания
цветов по всей длине линии яркости . }
begin
ClrDialog.Edit4.Text:=IntToStr(round(ColR)); {Эти строки}
ClrDialog.Edit5.Text:=IntToStr(round(ColG)); {нужны лишь в моём}
ClrDialog.Edit6.Text:=IntToStr(round(ColB)); {примере. В Вашем
может и не понадобятся.}

{+++++++++++++++++++++++++++++++++++++++}

{Генерация шкалы яркости для выбранного оттенка}
StepR:=(256-ColR)/256; //определение шага для красного
StepG:=(256-ColG)/256; //определение шага для зелёного
StepB:=(256-ColB)/256; //определение шага для синего

j:=256; //здесь счётчику по Y-ку присваивается начальное значение
repeat j:=j-1; {Цикл по Y-ку организован с помощью repeat until чтобы
организовать обратный отсчёт от 256 до 1. Это сделано
для того, чтобы заполнять шкалу не с верху вниз, а снизу
вверх (т.к. начальная точка экранных координат
расположена в верхнем правом углу.)}

ColR:=ColR+StepR; {В каждом переходе цикла по Y}
ColG:=ColG+StepG; {увеличиваем значение соответствующего цвета}
ColB:=ColB+StepB; {на соответствующий ему шаг.}
for i:=0 to 17 do
begin
{На всякий случай проверим значения цветов на вхождение
в пределы 255}
if ColR>255 then ColR:=255;
if ColG>255 then ColG:=255;
if ColB>255 then ColB:=255;

LineColor:=RGB(round(ColR), round(ColG), round(ColB)); //Записываем оттенок
ClrDialog.Yarcost.Canvas.Pixels[i, j]:=LineColor; //Рисуем точку в компонент TImage
end;
until j=1;
end;

Вот в принципе все необходимые процедуры для написания такого диалога. Всё остальное – дело техники и это вы найдёте в примере к статье. Правда есть ещё один момент, который необходимо описать – это перевод из TColor в RGB формат. Чисто для примера сделаем 3 переменные типа integer (пусть это будут ColR , ColG и ColB ) и одну переменную типа TColor (Например, ColTColor). Далее присвоим значение переменной ColTColor. Пусть это будет зелёный (clGreen). Ну и, наконец, выделим из этой переменной значения RGB компонентов в соответствующие переменные типа integer. Весь код :

procedure TestTColorToRGB;
var
ColR, ColG, ColB: integer;
ColTColor: TColor;
begin
ColTColor:=clGreen; //присваиваем зелёный цвет

ColR:= ColTColor mod $100; //выделяем красный
ColG:=( ColTColor div $100) mod $100; //выделяем зелёный
ColB:= ColTColor div $10000; //выделяем синий
end;

У переменных должны получиться следующие значения:

ColR = 0;
ColG = 255;
ColB = 0.

Вот и всё. Конечно, для крутого графического редактора этого мало, но ведь можно и дополнить чем-нибудь ещё!

Июль 4, 2008 — Рубрика: Delphi
Метки: , ,

Дополнительные функции обработки строк:

В модуле StrUtils.pas содержатся полезные функции для обработки строковых переменных. Чтобы подключить этот модуль к программе, нужно добавить его имя (StrUtils) в раздел Uses.

1) PosEx(SubStr, Str: String; Offset: Integer) - функция аналогична функции Pos(), но позволяет задать отступ от начала строки для поиска. Если значение Offset задано (оно не является обязательным), то поиск начинается с символа Offset в строке. Если Offset больше длины строки Str, то функция возратит 0. Также 0 возвращается, если подстрока не найдена в строке. Пример:

uses StrUtils;
{ … }
var Str1, Str2: String; P1, P2: Integer;
{ … }
Str1:=’Hello! How do you do?’;
Str2:=’do’;
P1:=PosEx(Str2, Str1, 1); { P1 = 12 }
P2:=PosEx(Str2, Str1, 15); { P2 = 19 }

2) Функция AnsiReplaceStr(Str, FromText, ToText: String) - производит замену выражения FromText на выражение ToText в строке Str. Поиск осуществляется с учётом регистра символов. Следует учитывать, что функция НЕ изменяет самой строки Str, а только возвращает строку с произведёнными заменами. Пример:

uses StrUtils;
{ … }
var Str1, Str2, Str3, Str4: String;
{ … }
Str1:=’ABCabcAaBbCc’;
Str2:=’abc’;
Str3:=’123′;
Str4:=AnsiReplaceStr(Str1, Str2, Str3); { Str4 = “ABC123AaBbCc” }

3) Функция AnsiReplaceText(Str, FromText, ToText: String) - выполняет то же самое действие, что и AnsiReplaceStr(), но с одним исключением - замена производится без учёта регистра. Пример:

uses StrUtils;
{ … }
var Str1, Str2, Str3, Str4: String;
{ … }
Str1:=’ABCabcAaBbCc’;
Str2:=’abc’;
Str3:=’123′;
Str4:=AnsiReplaceText(Str1, Str2, Str3); { Str4 = “123123AaBbCc” }

4) Функция DupeString(Str: String; Count: Integer) - возвращает строку, образовавшуюся из строки Str её копированием Count раз. Пример:

uses StrUtils;
{ … }
var Str1, Str2: String;
{ … }
Str1:=’123′;
Str2:=DupeString(Str1, 5); { Str2 = “123123123123123″ }

5) Функции ReverseString(Str: String) и AnsiReverseString(Str: AnsiString) - инвертируют строку, т.е. располагают её символы в обратном порядке. Пример:

uses StrUtils;
{ … }
var Str1: String;
{ … }
Str1:=’0123456789′;
Str1:=ReverseString(Str1); { Str1 = “9876543210″ }

6) Функция IfThen(Value: Boolean; ATrue, AFalse: String) - возвращает строку ATrue, если Value = True и строку AFalse если Value = False. Параметр AFalse является необязательным - в случае его отсутствия возвращается пустая строка.

uses StrUtils;
{ … }
var Str1, Str2: String;
{ … }
Str1:=IfThen(True, ‘Yes’); { Str1 = “Yes” }
Str2:=IfThen(False, ‘Yes’, ‘No’); { Str2 = “No” }

Мы рассмотрели функции, позволяющие выполнять со строками практически любые манипуляции. Как правило, вместо строки с указанным типом данных, можно использовать и другой тип - всё воспринимается одинаково. Но иногда требуются преобразования. Например, многие методы компонент требуют параметр типа PChar, получить который можно из обычного типа String функцией PChar(Str: String):

uses ShellAPI;
{ … }
var FileName: String;
{ … }
FileName:=’C:\WINDOWS\notepad.exe’;
ShellExecute(0, ‘open’, PChar(FileName), ”, ”, SW_SHOWNORMAL);

Тип Char представляет собой один-единственный символ. Работать с ним можно как и со строковым типом. Для работы с символами также существует несколько функций:

Chr(Code: Byte) - возвращает символ с указанным кодом (по стандарту ASCII):

var A: Char;
{ … }
A:=Chr(69); { A = “E” }

Ord(X: Ordinal) - возвращает код указанного символа, т.е. выполняет противоположное действие функции Chr():

var X: Integer;
{ … }
X:=Ord(’F'); { X = 70 }

Из строки можно получить любой её символ - следует рассматривать строку как массив. Например:

var Str, S: String; P: Char;
{ … }
Str:=’Hello!’;
S:=Str[2]; { S = “e” }
P:=Str[5]; { P = “o” }

В этой статье описаны основные приёмы работы со строковыми типами данных. Как правило, этих данных достаточно для написания любого алгоритма.

Июль 1, 2008 — Рубрика: Delphi
Метки: , ,

Стандартные функции обработки строк:

1) Функция Length(Str: String) - возвращает длину строки (количество символов). Пример:

var
Str: String; L: Integer;
{ … }
Str:=’Hello!’;
L:=Length(Str); { L = 6 }

2) Функция SetLength(Str: String; NewLength: Integer) позволяет изменить длину строки. Если строка содержала большее количество символов, чем задано в функции, то “лишние” символы обрезаются. Пример:

var Str: String;
{ … }
Str:=’Hello, world!’;
SetLength(Str, 5); { Str = “Hello” }

3) Функция Pos(SubStr, Str: String) - возвращает позицию подстроки в строке. Нумерация символов начинается с единицы (1). В случае отсутствия подстроки в строке возращается 0. Пример:

var Str1, Str2: String; P: Integer;
{ … }
Str1:=’Hi! How do you do?’;
Str2:=’do’;
P:=Pos(Str2, Str1); { P = 9 }

4) Функция Copy(Str: String; Start, Length: Integer) - возвращает часть строки Str, начиная с символа Start длиной Length. Ограничений на Length нет - если оно превышает количество символов от Start до конца строки, то строка будет скопирована до конца. Пример:

var Str1, Str2: String;
{ … }
Str1:=’This is a test for Copy() function.’;
Str2:=Copy(Str1, 11, 4); { Str2 = “test” }

5) Функция Delete(Str: String; Start, Length: Integer) - удаляет из строки Str символы, начиная с позиции Start длиной Length. Пример:

var Str1: String;
{ … }
Str1:=’Hello, world!’;
Delete(Str1, 6, 7); { Str1 = “Hello!” }

6) Функции UpperCase(Str: String) и LowerCase(Str: String) преобразуют строку соответственно в верхний и нижний регистры:

var Str1, Str2, Str3: String;
{ … }
Str1:=’hELLo’;
Str2:=UpperCase(Str1); { Str2 = “HELLO” }
Str3:=LowerCase(Str1); { Str3 = “hello” }

Строки можно сравнивать друг с другом стандартным способом:

var Str1, Str2, Str3: String; B1, B2: Boolean;
{ … }
Str1:=’123′;
Str2:=’456′;
Str3:=’123′;
B1:=(Str1 = Str2); { B1 = False }
B2:=(Str1 = Str3); { B2 = True }

Если строки полностью идентичны, логическое выражение станет равным True.

Июнь 30, 2008 — Рубрика: Delphi
Метки: , ,

Работа со строковыми типами данных

Строковый тип данных - один из самых часто используемых в программах тип. Действительно, без него не обходится практически ни один алгоритм. Даже программы, выполняющие исключительно математические операции, порой, написаны с использованием строковых типов данных.

Строка - это последовательность символов. В Object Pascal существует несколько строковых типов. Вот основные из них:Тип данных Максимальная длина Используемая память Используется для…
ShortString 255 символов от 2 до 256 байт Минимальная совместимость, хранение небольших строк
AnsiString около 2^31 символов от 4 байт до 2 Гб 8-битные символы (ANSI), DBCS ANSI, MBCS ANSI и т.д.
WideString около 2^30 символов от 4 байт до 2 Гб Юникод-символы - многопользовательские сервера, мультиязыковые приложения

Для большинства целей подходит тип AnsiString (иногда называется Long String).

Июнь 28, 2008 — Рубрика: Delphi
Метки: ,

Копирование методами Windows.

uses ShellApi;

function WindowsCopyFile(FromFile, ToDir : string) : boolean;
var F : TShFileOpStruct;
begin
F.Wnd := 0; F.wFunc := FO_COPY;
FromFile:=FromFile+#0; F.pFrom:=pchar(FromFile);
ToDir:=ToDir+#0; F.pTo:=pchar(ToDir);
F.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
result:=ShFileOperation(F) = 0;
end;

// Пример копирования:
procedure TForm1.Button1Click(Sender: TObject);
begin
if not WindowsCopyFile(’C:\UTIL\ARJ.EXE’, GetCurrentDir) then
ShowMessage(’Copy Failed’);
end;

Июнь 19, 2008 — Рубрика: Delphi
Метки: , ,

Копирование методом LZExpand.

uses LZExpand;

procedure CopyFile(FromFileName, ToFileName : string);
var
FromFile, ToFile: File;
begin
AssignFile(FromFile, FromFileName);
AssignFile(ToFile, ToFileName);
Reset(FromFile);
try
Rewrite(ToFile);
try
if LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle)<0 then
raise Exception.Create(’Error using LZCopy’)
finally
CloseFile(ToFile);
end;
finally
CloseFile(FromFile);
end;
end;

Июнь 5, 2008 — Рубрика: Delphi
Метки: ,

Копирование методом Pascal.

type
TCallBack=procedure (Position,Size:Longint); {Для индикации процесса копирования}

procedure FastFileCopy(Const InfileName, OutFileName: String; CallBack: TCallBack);
Const BufSize = 3*4*4096; { 48Kbytes дает прекрасный результат }
type
PBuffer = ^TBuffer;
TBuffer = array [1..BufSize] of Byte;
var
Size : integer;
Buffer : PBuffer;
infile, outfile : File;
SizeDone,SizeFile: Longint;
begin
if (InFileName <> OutFileName) then
begin
buffer := Nil;
AssignFile(infile, InFileName);
System.Reset(infile, 1);
try
SizeFile := FileSize(infile);
AssignFile(outfile, OutFileName);
System.Rewrite(outfile, 1);
try
SizeDone := 0; New(Buffer);
repeat
BlockRead(infile, Buffer^, BufSize, Size);
Inc(SizeDone, Size);
CallBack(SizeDone, SizeFile);
BlockWrite(outfile,Buffer^, Size)
until Size < BufSize;
FileSetDate(TFileRec(outfile).Handle,
FileGetDate(TFileRec(infile).Handle));
finally
if Buffer <> Nil then Dispose(Buffer);
System.close(outfile)
end;
finally
System.close(infile);
end;
end else
Raise EInOutError.Create(’File cannot be copied into itself’);
end;

Июнь 1, 2008 — Рубрика: Delphi
Метки: ,

Написание простого медиа-проигрывателя (часть 2)

Продолжим нашу работу над медиа-проигрывателем, основанным на Windows Media Player. Хочется подчеркнуть, что кардинально изменить что-либо не удастся, поэтому в этой статье я просто расскажу о небольших усовершенствованиях и на этом мы остановимся.

Обычно во время воспроизведения мы должны видеть название файла, который проигрывается в данное время. Давайте снабдим проигрыватель этой функцией. Для этого изменим обработчик пункта меню “Открыть” на следующее:

if OpenDialog.Execute then
begin
MediaPlayer.URL:=OpenDialog.FileName;
Form1.Caption:=’SMP - ‘+ExtractFileName(OpenDialog.FileName);
end;

Как работает добавленная строка? Функция ExtractFileName() возвращает имя файла из указанного пути - то, что нам нужно. “SMP” - это сокращённо “Simple Media Player” :-) Наконец, значение присваивается заголовку формы.

Что ещё можно добавить? Да, действительно странный проигрыватель… Можно сделать окошко “О программе”. Для этого в меню добавьте соответствующий пункт и назовите его “О программе…” По правилам Windows любая надпись, приводящая к открытию диалогового окна, должна заканчиваться многоточием - “…” Рекомендую запомнить это правило и всегда и везде его использовать. Окно можно создать “с нуля”: File - New - Form (в разных версиях Delphi названия пунктов меню могут отличаться). А ещё можно воспользоваться окном, подготовленным разработчиками - открываем File - New - Other, переходим на вкладку Forms, выбираем “About box” и нажимаем “ОК”. В результате создаётся форма. В ней напишите название программы, своё имя, версию… Далее создаём обработчик для созданного пункта меню

AboutBox.ShowModal;

Пытаемся запустить программу, но Delphi выдаёт предупреждение, что второй модуль не связан с первым и предлагает это сделать. Соглашаемся, и приложение запускается.

Вот и всё. Конечно, такому проигрывателю далеко до Winamp, Light Alloy и даже до стандартного Windows Media Player, но основы, я думаю, понятны. Если вы повнимательнее изучите список ActiveX-компонент, то найдёте там много интересного.

Май 28, 2008 — Рубрика: Delphi
Метки: , ,

Написание простого медиа-проигрывателя (часть 1)

ростейший медиа-проигрыватель можно создать стандартными средствами Windows. Существуют модули, которые доступны из любого языка программирования - это ActiveX. Delphi в этом плане не исключение. Встроенный в систему Windows Media Player имеет собственный ActiveX-модуль, который мы легко можем использовать в своей программе. Правда, кардинально изменить в нём что-либо не получится. В данной статье я покажу пример, как использовать этот компонент.

Для начала ActiveX-компонент (сокращённо AX) нужно интегрировать в оболочку Delphi. Делается это легко: открываем диалоговое окно Component - Import ActiveX Control. В разных версиях Delphi этот пункт меню может называться по-разному, но ключевым остаётся слово ActiveX. В открывшемся окне в списке компонент найдите строку Windows Media Player. Нажмите кнопку Install. В появившемся окне можно указать, в какой пакет следует установить компонент. Можно оставить всё по умолчанию и нажать ОК. После этого на вкладке ActiveX палитры компонент появится кнопка WindowsMediaPlayer. Теперь можно приступить к созданию проигрывателя.

Для начала поместите компонент на форму - щёлкните по его значку и затем по форме. Вы увидите знакомое изображение - изображение проигрывателя. Его внешний вид зависит от версии установленного в системе компонента. Примерный вид того, что вы увидите, изображён на рисунке 1.
рис. 1
рис. 2

Для начала давайте сделаем возможность открытия нужного файла. За путь к файлу, который нужно воспроизводить, отвечает свойство URL типа WideString (строка). Давайте сделаем для программы меню, куда и добавим нужный нам пункт. Поместите на форму TMainMenu (страница Standard). Дважды щёлкните по значку TMainMenu, лежащему на форме. Откроется дизайнер меню. Выделите единственный пункт в заголовке меню и в его свойстве Caption напишите “Файл”. Затем щёлкните по созданному пункту и снизу появистя ещё одна пустая строка. Там и введите название нашего пункта - “Открыть”. Следующей строкой давайте создадим разделитель для меню - в свойстве Caption поставьте один-единственный символ - минус (”-”). Следующей строкой сделайте пункт “Выход”. Ну вот, программа уже имеет меню, хотя и небольшое. Теперь нужно связать пункт меню с диалогом открытия файла. Найдите компонент TOpenDialog на странице Dialogs и поместите его на форму. Активируйте свойство Filter и нажмите на кнопку с тремя точками (”…”). В появившемся окне введите желаемые типы файлов. В поле Filter Name нужно ввести описание типов файлов, а в поле Filter - сам фильтр. Пример на рисунке 2.

Чтобы с компонентом было удобно работать, измените его свойство Name на MediaPlayer.

Выделите компонент и перейдите в окно Object Inspector. Свойств (Properties) у компонента не очень много, а вот событий (Events) гораздо больше. Но мы используем лишь некоторые из них.

Для удобства, компонент MainMenu1 переименуем в MainMenu, а OpenDialog1 - в OpenDialog.

Пришло время запрограммировать пункт меню “Открыть”. Откройте дизайнер меню и дважды щёлкните по нужному пункту - откроется редактор кода. В этом месте следует написать:

if OpenDialog.Execute then
MediaPlayer.URL:=OpenDialog.FileName;

Метод Execute открывает диалог и, если пользователь не нажал “Отмена”, то функция возвращает значение True, а в FileName записывается путь к выбранному файлу. Затем мы присваиваем свойству URL проигрывателя выбранный файл. Запустите программу и попробуйте открыть файл. Всё должно работать, файл должен воспроизводиться.

Теперь давайте приведём окно проигрывателя к нормальному виду. Сам проигрыватель нужно растянуть на всю ширину окна - измените его свойство Align на alClient. Саму форму стоит сделать поменьше, т.к. наш проигрыватель пока что воспроизводит только аудио-файлы. На мой взгляд, для формы можно установить ширину (Width) равной 300, а высоту (Height) - 200. Наконец, можно изменить вид окна и установить BorderStyle в значение bsSizeToolWin, а заголовок (Caption) - “Simple Media Player”.

Теперь запрограммируем пункт “Выход” - для этого следует написать в его обработчике всего одну строку:

Self.Close;

Этот метод закрывает текущую форму (Self - объект, выбранный по умолчанию, форма) и завершает приложение.

Теперь нужно сделать в меню элементарные команды управления воспроизведением - Start, Stop, Pause. Конечно, в проигрывателе и без того есть существующие кнопки, но они должны иметь своё отражение и в меню.

Для начала добавьте в заглавную строку меню (туда, где “Файл”) пункт “Управление”. Затем добавьте два пункта - “Старт / Стоп” и “Пауза”. Запрограммировать эти команды легко. Для управление воспроизведением служит набор методов Controls, а узнать текущее состояние проигрывателя можно из свойства PlayState. Вот как выглядит обработчик пункта “Старт / Стоп”:

if MediaPlayer.PlayState =wmppsPlaying then
MediaPlayer.Controls.Stop
else
MediaPlayer.Controls.Play;

А вот обработчик “Паузы”:

if MediaPlayer.PlayState =wmppsPlaying then
MediaPlayer.Controls.Pause;

Запустите программу и проверьте её работоспособность.
рис. 3

Как видите, мы создали сравнительно простой, но рабочий проигрыватель. В следующий раз мы продолжим его разработку. Примерное изображение окна программы после выполнения всех действий, описанных в статье, показано на рисунке 3.

Май 20, 2008 — Рубрика: Delphi
Метки:

Пирамидальная сортировка

Алгоритм пирамидальной сортировки (heapsort) - один из самых быстрых алгоритмов сортировки.

Program heapsort;

{$APPTYPE CONSOLE}

type
tkey = integer;
int = integer;

const N = 10;

var a,b : array [0..N+1] of tkey;

function parent(x : int) : int;
begin
result:=x shr 1;
end;

function left(x : int) : int;
begin
result := x shl 1;
if result > a[0] then result := N+1;
end;

function right(x:int):int;
begin
result := x shl 1 + 1;
if result > a[0] then result := N+1;
end;

procedure swap(i,j : int);
var temp : tkey;
begin
temp := a[i];
a[i] := a[j];
a[j] := temp;
end;

procedure moveup(x : int);
begin
while (a[x] > a[parent(x)]) and (parent(x) > 0) do begin
swap(x, parent(x));
x := parent(x);
end;
end;

procedure movedown(x : int);
var max : integer;
begin
if a[left(x)] > a[right(x)] then max := left(x)
else max := right(x);
while (a[max] > a[x]) and (max <= a[0]) do begin
swap(max, x);
x := max;
if a[left(x)] > a[right(x)] then max := left(x)
else max := right(x);
end;
end;

procedure update(x : int; k : tkey);
begin
a[x] := k;
moveup(x);
movedown(x);
end;

procedure add(k : tkey);
begin
inc(a[0]);
update(a[0], k);
end;

procedure delete(x : int);
begin
swap(x, a[0]);
dec(a[0]);
update(x, a[x]);
end;

procedure hsort;
var i:int;
begin
a[0] := 1;
a[1] := b[1];
for i := 2 to N do
add(b[i]);
for i := 1 to N do
delete(1);
end;

var i : int;
begin
randomize;
fillchar(a, sizeof(a), 0);
fillchar(b, sizeof(b), 0);

for i := 1 to N do
b[i] := random(10);

writeln(’Non-sorted elements’);
for i := 1 to N do
write(b[i], ‘ ‘);
writeln;

hsort;

writeln(’Sorted elements’);
for i := 1 to N do
write(a[i], ‘ ‘);
readln;
end.

Май 19, 2008 — Рубрика: Delphi
Метки: