VR-Online для программистов #6

Page 1

VR-online JOURNAL Фленов Михаил and VR-Team VR-online для программистов №6 Delphi (Базы данных): Создание псевдонимов ...........................................................................3 Delphi (OpenGL): Работа с текстурами........................................................................................7 Delphi (DirectX): DirectX без VCL .............................................................................................13 VRML............................................................................................................................................18 Форматы файлов: Potoshop PSD.................................................................................................22 Delphi: Docking – перемещение компонентов ..........................................................................26 Delphi: Прозрачные окна ............................................................................................................29 Delphi (ActiveX): Программы для Internet.................................................................................31 SQL: Запросы с подзапросами ...................................................................................................36 OpenGL: Освещение....................................................................................................................39 Java: Компоненты часть вторая..................................................................................................42

Copyright: VR-online Journal http://www.vr-online.ru


VR-online Journal (Horrific and VR-Team)

Как же не хватает времени. Столько всего надо сделать, и ещё больше хочется сделать. Каждый день приходится выбирать, что сегодня делать. Самый сложный выбор – выполнять работу, за которую можно получить деньги или просто сделать что-то для себя и не получить за это ни гроша, но сделать это для души. Работать для души – это хорошо, но желудок хочет кушать и ему надо что-то, поэтому душа пока отдыхает. Хорошо, когда ты делаешь то, что тебе нравиться и получаешь за это приличные деньги. В моём случае пока что это не получается. То, что мне нравиться приносит мало денег, да и вообще в моём городе заработать «достаточно» невозможно. Как ты думаешь, можно работать программером на 300 баксов, когда в той же Москве получают $800 и даже более $1000? Сложно. Каждый день думаешь о том, как кому-то повезло и пускаешь слюни. Я уже много раз хотел уехать и уже много раз говорил об этом. У меня просто есть такое человеческое чувство – зависть. Пока что с этой завистью удаётся бороться, но желудок требует еды. Когда я был один, не женат и не было детей, то я без проблем работал для души и получал на предприятии $100. Сейчас мне даже $300 не хватает, потому что прожить на них с маленьким ребёнком нереально. Один раз я говорил о том, что проект VR-online может закрыться. Сейчас я уверен, что этого не произойдёт. У нас набралась хорошая команда, которая мне помогает по мере своих возможностей и по мере борьбы души и желудка. Журнал не коммерческий и не приносит денег, но энтузиазм и душа не дадут ему умереть. Даже если когда-нибудь я отойду от дел, журнал будет жить!!! И всё это благодаря команде Vr-team, которая работает абсолютно бесплатно для тебя.

Для программистов №6

VR-online JOURNAL Horrific aka Фленов Михаил

INFO: ИДЕЯ И РЕАЛИЗАЦИЯ: Флёнов Михаил (Horrific) ГРАФИКА: Фленов Михаил, tr4sh

VR-Team: Crazy_Script, Del, Demogorgon, Fighter, Mish!, Negus, Spider NET, tr4sh INTERNET: WWW: http://www.vr-online.ru E-MAIL: horrific@vr-online.com ДИЗАЙН САЙТА: tr4sh КОДИНГ САЙТА: Mish!

Данный журнал распространяется в виде PDF файлов. Вы можете выкладывать номера на любые носители без изменения внешнего вида журнала, без перевода в другие форматы, без изменения самого файла. В журнал запрещается вносить изменения. Перепечатка материалов запрещена. Журнал распространяется бесплатно, и ты можешь скачать его с нашего сайта, поэтому мы не видим смысла в перепечатывании материалов. Если ты хочешь стать автором журнала, то присылай свою статью на наш e-mail и мы обязательно включим её в очередной номер.

Фленов Михаил aka Horrific

http://www.vr-online.ru

2


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi (Базы данных): Создание псевдонимов Сегодня мы научимся создавать псевдонимы. Точнее сказать, я уже расказывал как это сделать, с помощью SQL Explorer, а сегодня мы это сделаем из собственной проги. Брось на форму компонент TSession. Если ты работаешь с базой данных, то этот объект создаёться автоматически без твоего ведома. В нём хранится низкоуровневая информация о BDE, драйверах и многом другом. Если ты хочешь изменить какие-то значения указанные в этом объекте по умолчанию, то тебе необходимо: Поставить этот компонент на форму. Указать любое имя в его свойстве SessionName . Всем компонентам TTable и TQuery , для которых будут действовать установленные тобой значения, вполе SessionName нужно указать имя объекта TSession. Для нашего примера достаточно первых двух действий, потому что у нас не будет компонентов TTable или TQuery. Посмотри на рисунок 1 и сконструируй форму, подобную этой. Как только закончишь, продолжай читать. Рассмотрим процедуру FormShow - которая вызывается на событие OnShow: procedure TForm1.FormShow(Sender: TObject); var str:TStrings; begin Str:=TStringList.Create; Session1.GetAliasNames(Str); ListBox1.Items.Assign(Str); Str.Free; end;

Рис 1. Пример формы

Здесь я получаю список всех доступных в системе псевдонимов и вставляю этот список в TListBox. Рассмотрим по строчно. Сначала я объявляю переменную Str типа TStrings. Str:=TStringList.Create - эта строка инициаизирует переменную Str, как список строк (TStringList). Функция GetAliasNames компонента ТSession возвращает все доступные системе псевдонимы. В качестве параметра передаёться указатель на объект типа TStrings, куда запишутся весь список. ListBox1.Items.Assign(Str) - копирую список в элементы ListBox1.

http://www.vr-online.ru

3


VR-online Journal (Horrific and VR-Team)

Для программистов №6

И последняя строка освобождает переменную Str. Теперь создадим новый псевдоним стандартного типа. К этому типу относятся таблицы Paradox и DBF. Я создаю псевдоним по нажатию первой кнопки. Вот соответствующая процедура: procedure TForm1.Button1Click(Sender: TObject); var str:TStrings; begin Session1.AddStandardAlias('VROnline','c:\','Paradox'); Str:=TStringList.Create; Session1.GetAliasNames(Str); ListBox1.Items.Assign(Str); Str.Free; end; Создание происходит с помощью функции AddStandardAlias компонента ТSession. В качестве первого параметра, ты должен указать имя нового псевдонима. Второй - путь к базам данных, которые будут связаны с псевдонимом. Третий - драйвер, который будет использоватся по умолчанию. После добавления, я снова получаю спсок доступных псевдонима и копирую его в TListBox. Теперь создадим псевдоним нестандартого типа. Для примера будет использоваться Interbase. Он будет создаваться по нажатию второй кнопки: procedure TForm1.Button2Click(Sender: TObject); var L: TStringList; begin L := TStringList.Create; try with L do begin Add('SERVER NAME=IB_SERVER:/PATH/DATABASE.GDB'); Add('USER NAME=MYNAME'); end; Session1.AddAlias('NewIB', 'InterBase 4.x Driver by Visigen',L); finally L.Free; end; end; Процедура AddAlias компонента ТSession создаёт псевдоним нестандартного типа. Первый параметр - имя псевдонима. Второй - имя драйвера. Третий параметр указатель на TStringList, в котором хранятся дополнительные настройки. Дополнительные параметры хранятся в виде строк (например 'SERVER NAME= IB_SERVER: /PATH/DATABASE.GDB'). В строке указывается имя параметра и после знака равно его значение. Параметры могу тотличаться, в зависимости от драйвера. Чтобы узнать, какие параметры доступны, можно создать пробный псевдоним в SQL Explorer и посмотреть, какие там присутствуют параметры. Внимание!!! - имя драйвера у тебя может отличаться. Чтобы увидеть все доступные драйверы, нужно войти в BDE Administrator . Здесь, на закладе Configuration на дереве выбираешь Drivers , и здес в разделах Native и ODBC есть все имена драйверов.

http://www.vr-online.ru

4


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Исходники примера находятся в файле delphi1.zip Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

5


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Тебя мучает одна проблема, которую ты не можешь решить? Заходи на форум на нашем сайте, подумаем вместе!!! На нашем форуме ты можешь задать любой вопрос и получить ответ по следующим темам: • Программирование (Delphi, JBuilder, C++ Builder, Kylix, Visual C++Visual Basic и другие); • Технологии программирования (сети, мультимедиа, DirectX, OpenGL); • Администрирование; • Операционные системы; • Базы данных (SQL Server, язык SQL и другие); • Железо; • Internet технологии (Perl, PHP, Flash, XML); • Софт; • Сети; Адрес сайта http://www.vr-online.ru

http://www.vr-online.ru

6


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi (OpenGL): Работа с текстурами Сегодня нам предстоит изучить достаточно сложный материал - текстуры. Мы научимся их загружать и натягивать на объекты. Работать с текстурами, это тебе не шубу в трусы запихивать. Приготовься к достаточно сложной работе. Посмотри на рисунок 1. Здесь ты можешь увидеть результат сегодняшней работы. Я не смог подобрать более удачную позицию, но если ты запустишь пример, то сможешь увидеть все прелести текстуры. Для этого я сделал сферу вращающейся. Как ты видишь, для примера используется сфера обтянутая текстурой. В качестве текстуры я использую системную иконку, так что ты сегодня научишься ещё и превращать иконы в bmp формат. Я не буду объяснять всю прогу, а остановлюсь только на том, что относится к текстуре. Теперь бросим свой зоркий взгляд на функцию рисования:

Рис 1. Результат

procedure TForm1.FormPaint(Sender: TObject); var ps:TPaintStruct; begin BeginPaint(Handle,ps); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glPushMatrix; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); glTexImage2d(GL_TEXTURE_2D,0,3,TextureW,TextureH,0,GL_RGB, GL_UNSIGNED_BYTE,Texture^); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_2D); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); gluQuadricTexture(quadObj,GL_TRUE);

http://www.vr-online.ru

7


VR-online Journal (Horrific and VR-Team)

Для программистов №6

glTranslatef(TX,TY,0); glRotatef(RX,1,0,0); glRotatef(RY,0,1,0); glRotatef(RZ,0,0,1); gluSphere(quadObj,2.7, 15, 10); TX:=TX+SX; TY:=TY+SY; if (TX<-10) or (TX>10) then SX:=-SX; if (TY<-10) or (TY>10) then SY:=-SY; glDisable(GL_TEXTURE_2D); glPopMatrix; glDisable(GL_DEPTH_TEST); glFlush(); swapBuffers(dc); EndPaint(Handle,ps); end; Посмотри внимательно на эту процедуру. Большинство тебе должно быть уже понятно. glTexParameteri - устанавливает параметры текстуры. Первый параметр - тип, который может быть GL_TEXTURE_1D или GL_TEXTURE_2D. Второй параметр - символическое имя параметры, который нужно установить. Мы можем изменять: GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T и GL_TEXTURE_BORDER_COLOR . Третий параметр - значение, которое мы хотим установить, указанному в предыдущем параметре. Может не совсем понятно, но сейчас всё будет ясно. Давай рассмотрим каждый параметр в отдельности: GL_TEXTURE_MIN_FILTER - устанавливает тип функции, которая будет использоваться при уменьшении текстуры. Если ты решил изменить этот параметр, то ты должен указать GL_TEXTURE_MIN_FILTER вторым в функции glTexParameteri. В этом случае, третий параметр сможет принимать значения: GL_NEAREST - возвращает значение элемента текстуры, который является самым близким. GL_LINEAR - возвращает среднее значение из четырёх ближайших к центру тестируемого пиксела. GL_NEAREST_MIPMAP_NEAREST - выбирает ближайший MIPMAP и дальше использует тип NEAREST. GL_LINEAR_MIPMAP_NEAREST - выбирает ближайший MIPMAP и дальше использует тип LINEAR. GL_NEAREST_MIPMAP_LINEAR - выбирает два MIPMAP и дальше использует тип NEAREST. GL_LINEAR_MIPMAP_LINEAR - выбирает два MIPMAP и дальше использует тип LINEAR. GL_TEXTURE_MAG_FILTER - устанавливает функцию используемую при увеличении текстуры. Если ты решил её изменить, то ты должен установить GL_TEXTURE_MAG_FILTER вторым параметром в glTexParameteri, а третий сможет принимать значения: GL_NEAREST GL_LINEAR

http://www.vr-online.ru

8


VR-online Journal (Horrific and VR-Team)

Для программистов №6

GL_TEXTURE_WRAP_S - устанавливает повторения текстуры по координате S. Может принимать значения: GL_CLAMP - запрещает повторение текстуры. Одна её копия будет натянута на весь объект. GL_REPEAT - разрешает повторение текстуры. GL_TEXTURE_WRAP_Т - то же самое, что и GL_TEXTURE_WRAP_S, только для координаты Т. Возможные значения третьего параметра те же. GL_TEXTURE_BORDER_COLOR - устанавливает цвет обрамления текстуры. При этом параметре, третий сможет принимать значение массива из четырёх значений, которые интерпретируются как цвет (RGBA). Пор умолчанию (0,0,0,0). Теперь перейдём к функции glTexEnvf. Она устанавливает параметры среды текстуры. Первый параметр должен быть GL_TEXTURE_ENV. Второй должен быть GL_TEXTURE_ENV_MODE. Третий может принимать значения GL_MODULATE, GL_DECAL или GL_BLEND. Я использую второй параметр, а ты можешь попробовать другие и посмотреть на результат. Функция glTexImage2d устанавливает 2D текстуру. Первый параметр должен быть GL_TEXTURE_2D. Второй параметр - уровень детализации текстуры (0 - основной). Третий - количество цветовых компонент в текстуре (может быть 1,2,3 или 4). Дальше идёт ширина и высота. Дальше идёт обрамление (может быть 0 или 1). Я использую 0, чтобы не было никаких обрамлений. Далее - формат, в котором хранятся цветовые данные в массиве. Здесь могут быть значения GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE или GL_LUMINANCE_ALPHA. Предпоследний параметр - тип в котором хранятся цветовые данные (может быть GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT или GL_FLOAT). Последний параметр - указатель на массив текстуры. Надо заметить, что в качестве последнего параметра должна передаватся реальная ссылка на текстуру. Прежде чем вызывать glTexImage2d, текстура должна быть уже загружена и подготовлена в этой переменной. Чуть позже я покажу, как загружается текстура. После всех этих настроек, можно включить текстуру. Я это дулаю с помощью: glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_2D); Первые две необязательны. Они просто включают использование определённых функций текстуры. Я их привёл только для примера, и в большинстве случаев они вам не понадобятся. Последний непосредственно включает показ текстуры. Теперь, все объекты которые мы будем рисовать, будут обтянуты выбранной текстурой. Это будет происходить, пока мы не отключим текстуру с помощью glDisable(GL_TEXTURE_2D) . Всё остальное должно быть понятно. Так что давай ещё рассмотрим процедуру для загрузки текстуры из системной иконки. procedure TForm1.GetTexture; var BMInfo :TBitmapInfo; I,ImageSize :Integer; Temp :Byte;

http://www.vr-online.ru

9


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Bitmap :Graphics.TBitmap; TempImage :TBitmap; MemDC : HDC; begin //Подготавливаю переменные, для работы с картинками. Bitmap:=TBitmap.Create; TempImage:=TBitmap.Create; TempImage.Width:=32; TempImage.Height:=32; //Прорисовываю системную иконку (Icon) в TempImage //Если захочешь использовать текстуру из BMP файла //то можно его напрямую засунуть в TempImage. //Для этого достаточно написать TempImage.LoadFromFile('filename.bmp'); TempImage.Canvas.Draw(0,0,Icon); //Определяю ближайшие размеры текстуры которые воспримет OpenGL. Bitmap.Width:=RoundUpToPowerOf2(TempImage.Width); Bitmap.Height:=RoundUpToPowerOf2(TempImage.Height); //Копирую текстуру из TempImage в Bitmap с учётом размеров //воспринимаемых OpenGL Bitmap.Canvas.CopyRect(Rect(0,0,Bitmap.Width,Bitmap.Height), TempImage.Canvas, Rect(0,0,32,32)); //Создаю контекст в памяти. MemDC:=CreateCompatibleDC(0); try with bitmap do begin ImageSize:=bitmap.Width*bitmap.Height; TextureW:=bitmap.Width; TextureH:=bitmap.Height; //Выделяю память для переменной Texture, в которой будет //хранится преобразованная текстура. Обрати внимание, как она //объявлена. GetMem(Texture,ImageSize*3); MemDC:=CreateCompatibleDC(0); FillChar(BMInfo,SizeOf(BMInfo),0); //Заполняю BMInfo информацией о текстуре. With BMInfo.bmiHeader do begin biSize:=sizeof(TBitmapInfoHeader); biBitCount:=24; biWidth:=bitmap.Width; biHeight:=-bitmap.Height; biPlanes:=1; biCompression:=BI_RGB; end; //Копирую данные из Bitmap в Texture GetDIBits(MemDC,Bitmap.Handle,0,bitmap.Height, Texture,BMInfo,DIB_RGB_COLORS); {$R-} //Запускаю цикл, в котором меняются местами цветовые //компоненты красного и голубого т.е. идёт перевод из RGB в BGR for i:=0 to ImageSize-1 do begin Temp:=Texture^[i*3]; Texture^[I*3]:=Texture^[I*3+2]; Texture^[I*3+2]:=Temp; end; {$R-} glPixelStorei(GL_UNPACK_ALIGNMENT,0); glPixelStorei(GL_UNPACK_ROW_LENGTH,0); glPixelStorei(GL_UNPACK_SKIP_ROWS,0); glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);

http://www.vr-online.ru

10


VR-online Journal (Horrific and VR-Team)

Для программистов №6

end; finally //Освобождаю всё не нужное. Bitmap.Free; TempImage.Free; DeleteDC(MemDC); end; end; Я не буду её расписывать, потому что она не совсем относится к OpenGL, но я постарался снабдить текст комментариями, чтобы можно было разобраться. Обязательно посмотри на них, там я описал много интересного. Для большей ясности я дам ещё несколько заметок: Формат изображения нужного OpenGL очень похож на BMP. Только в BMP используется цвет RGB (красный, зелёный, голубой), а в OpenGL используется BGR (голубой, зелёный, красный). Это значит, что нам нужно каждый третий байт цвета поменять местами с первым. У картинки должно быть определённое отношение ширины к высоте (ширина=2^n + 2, а высота=2^m + 2. Двойку нужно прибавлять при использовании обромлений). Чтобы не забивать особо голову этими функциями я написал небольшую функцию, которая поможет нам в определёнии размеров, так что используй её в своих творениях: function TForm1.RoundUpToPowerOf2(Value: Integer): Integer; var LogTwo : Extended; begin LogTwo:=log2(Value); if Trunc(LogTwo) < LogTwo then Result:=Trunc(Power(2,Trunc(LogTwo)+1)) else Result:=value; end; На сегодня всё. Можешь качать и играться с исходниками. Исходники примера находятся в файле opengl.zip Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

11


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Реклама в журнале VR-online Почему вы обязаны разместить рекламу на страницах VRonline:

4. 5. 6. 7.

1. Таких низких цен вы не видели ни где. 2. У нас располагается нестареющая информация. Которая будет актуальна всегда. 3. Вы имеете возможность пожизненно расположить свой банер на наших страницах по самым низким ценам. Пожизненность гарантируется в не зависимости от роста числа посещаемости. У нас есть потенциал для роста, как в объемах страниц, так и в посещаемости. Наши материалы очень часто сохраняются на дисках посетителей. Ваша реклама будет доступна в любых вариантах журнала. Журнал распространяется не только с сайта VR-online, но и другими сайтами и даже на CD, поэтому тираж огромен.

Если вы собираетесь рекламировать не просто сайт в интернете, а компанию, которая занимается информационными технологиями, то ваша дорога лежит сюда. Это лучшее рекламное место, которое можно найти в сети. Торопитесь такие цены не надолго. Расценки на размещение рекламы на страницах VR-online: • Банер 100х100 на главной странице сайта в течении месяца-$25 • Банер 468х60 на главной странице сайта в течении месяца-$30 • Банер 100х100 на странице оглавления на сайте 1-го номера (пожизненно)-$25 • Банер 468х60 на странице оглавления на сайте 1-го номера (пожизненно)-$30 • Страница в журнале-$200 • Половина страницы в журнале-$100 • Банер на странице статьи журнала.-$50

http://www.vr-online.ru

12


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi (DirectX): DirectX без VCL До сегодняшнего дня мы писали DirectX приложения на основе созданной Delphi формы. Мы привязывали к ней DirectDraw и рисовали на ней. Сегодня мы откажемся от этого и напишем приложение на основе своего окна, без использования VCL форм. Когда ты создаёшь новый проект, Delphi создаёт главную форму. Она нам не нужны, поэтому её надо удалить. Для этого выбери View -> Project Manager. Перед тобой откроется окно, как на рисунке 1. Щёлкни правой кнопкой крысы по Unit1 . В появившемся меню выбери Remove from project . Теперь у нас есть пустой проект. Щёлкни Рис 1. Пример формы правой кнопкой крысы по Project1 . В появившемся меню выбери View Source . Перед тобой откроется вот такой текст: program Project1; uses Forms; {$R *.RES} begin Application.Initialize; Application.Run; end. Лёгким стуком по клавиатуре, преврати этот текст в такой: program Project1; uses windows, messages, graphics, sysutils, forms, directx; {$R *.RES} var Instance: HWnd;//Поток WindowClass: TWndClass;//Класс окна

http://www.vr-online.ru

13


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Handle: HWnd;//Указатель на окно msg: TMsg;//Переменная для системных сообщений //Со следующими переменными мы уже работали //они нам понадобятся для работы с DirectX FDrawObject : IDirectDraw; FBackCaps: TDDSCaps; FPrimarySurface : IDirectDrawSurface; FSecondarySurface : IDirectDrawSurface; FSurfaceDescription: TDDSurfaceDesc; begin //Получаем новый поток instance :=GetModuleHandle(nil); //Создаём класс окна with WindowClass do begin style:=CS_HRedraw or CS_VRedraw; //В Lpfnwndproc присваиваем указатель на процедуру //которая будет откликаться на системные сообщения. //Эту процедуру я напишу чуть позже. Lpfnwndproc:=@windowproc; Hinstance:=Instance; HbrBackground:= color_btnface; LpszClassName:='VR_DX'; Hcursor:=LoadCursor(0,IDC_ARROW); end; //Регистрируем новый класс RegisterClass (WindowClass); //Создаём окно Handle:=CreateWindowEx (0,'VR_DX','',WS_POPUP, 5,5, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN),0,0,instance, nil); //Обновляем окно UpdateWindow(Handle); //Здесь мы вставим инициализацию DirectX // Запускаем цикл, в котором будет проходить проверка // системных сообщений. while true do begin //Получить системное сообщение. translatemessage(msg); //Отправляем его окну dispatchmessage (msg); //Даём поработать другим application.processmessages; end; end. С большинством кода можно разобраться по комментариям. Я остановлюсь только на одной функции: Функиция CreateWindowEx создаёт новое окно. Первый параметр - стиль окна, который нам не нужен, поэтому 0. Второй - класс окна. Он должен быть таким же, как и у WindowClass.LpszClassName. Третий - заголовок, который нам тоже не нужен, всё равно его не будет видно. Четвёртый - снова стиль, но немного другой. Здесь нам достаточно WS_POPUP. Следующие два параметра - левая и правая позиции окна. Потом идут ширина и высота. Девятый параметр - указатель на владельца окна. Наше окно главное, поэтому 0. Десятый - указатель на меню. Следующий - указатель на поток. Последний параметр нас тоже не очень интересует.

http://www.vr-online.ru

14


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Теперь напишем процедуру, которая будет откликаться на системные сообщения: function windowproc (Hwn,msg,wpr,lpr: longint): longint; stdcall; begin //Вызываем обработчик события по умолчанию result:=defwindowproc(hwn,msg,wpr,lpr); //Если окно уничтожается, то вызвать процедуру DoExit; //эту процедуру мы напишем чуть позже if msg=wm_destroy then DoExit; //Если нажата клавиша то ... if msg=wm_KeyDown then // Если это клавиша ESC то выход if wpr=VK_ESCAPE then DoExit; end; Её нужно вписывать после объявлений var и перед первым begin, иначе Delphi её не найдёт. Теперь напишем функцию DoExit, которая будет уничтожать окно. Её нужно писать между объявлениями var и процедурой windowproc. procedure DoExit; begin FSecondarySurface:=nil; FPrimarySurface:=nil; FDrawObject:=nil; Halt; end; Здесь всё ясно. Она уничтожает объекты DirectDraw, которые мы ещё не создали :). Давай же создадим их. Напиши следующий текст после токо как мы вызывали UpdateWindow, и перед циклом проверки системных сообщений. Это там, где мы писали смый первый код, я там ещё поставил комментарий, где нужно написать следующее: DirectDrawCreate (nil,FDrawObject,nil); FDrawObject.SetCooperativeLevel (handle, DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN); FDrawObject.SetDisplayMode (800,600,16); with FSurfaceDescription do begin dwSize := sizeof(FSurfaceDescription); dwFlags := DDSD_CAPS or DDSD_BACKBUFFERCOUNT; ddsCaps.dwCaps :=DDSCAPS_PRIMARYSURFACE or DDSCAPS_FLIP or DDSCAPS_COMPLEX; DwBackBufferCount := 1; end; FDrawObject.CreateSurface (FSurfaceDescription,FPrimarySurface,nil); FBackCaps.dwCaps := DDSCAPS_BACKBUFFER; FPrimarySurface.GetAttachedSurface (FBackCaps,FSecondarySurface); FPrimarySurface.Flip(nil, DDFLIP_WAIT); Здесь тебе должно быть уже всё ясно. Со всеми процедурами мы уже знакомы. Программа готова!!! Она ничего не делает, кроме инициализации DirectDraw и создания поверхностей. Вроде бы ничего особенного, но всё это происходит без использования

http://www.vr-online.ru

15


VR-online Journal (Horrific and VR-Team)

Для программистов №6

VCL. Если ты захочишь написать быстродействующее прилоение DirectDraw, то тебе придёться писать его именно так. Если ты захочешь добавить в программу рисование, то обработай сообщение WM_PAINT и рисуй сколько угодно. Для этого нужно подправть процедуру windowproc вот так: function windowproc (Hwn,msg,wpr,lpr: longint): longint; stdcall; begin result:=defwindowproc(hwn,msg,wpr,lpr); if msg=wm_destroy then DoExit; if msg=wm_paint then begin //Здесь ты можешь рисовать, сколько тебе влезет. end; if msg=wm_KeyDown then begin if wpr=VK_ESCAPE then DoExit; end; end; Исходники примера находятся в файле dx.zip Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

16


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Программирование в Delphi глазами хакера Автор: Фленов Михаил aka Horrific Из книги ты узнаешь: • Кто такой Хакер и как им стать; • Как создавать программы маленького размера; • Как оптимизировать код программы; • Как заставить летать кнопку «Пуск»; • Научишься контролировать системную палитру; • Научишься изменять разрешение экрана из своих программ; • Увидишь множество шуточного кода; • Узнаешь, как подсматриваем пароли, спрятанные под звездочками; • Напишешь программу мониторинга запускных файлов и клавиатурный шпион; • Сможешь портить окна чужих программ; • Как создавать окна неправильной формы; • Научишься работать с сетью через компоненты Delphi и увидишь как создаются сканеры портов, утилиты ping и др. • Узнаешь, как работать с сетью на уровне библиотеки WinSock; • Узнаешь, как работать с железом И многое другое. Посмотри на содержимое диска, и ты поймёшь, что он стоит того, чтобы купить эту книгу с диском: \Headers - Все необходимые заголовочные файлы, которые нужно будет подключать к Delphi для компиляции некоторых примеров \Source - Исходные коды своих простых программ, чтобы вы могли ознакомиться с реальными приложениями. Их немного, но посмотреть стоит. \Soft - Инсталляционный пакет программы Adobe Acrobat Reader v5.0. Если у вас нет этой программы, то вы должны её установить, чтобы можно было читать документацию, расположенную на диске. \Vr-online - Полная копия сайта автора, а это 100 мегабайт документации, полезной информации, исходных кодов и компонентов. Здесь же вы можете найти мою книгу "Библия Delphi" - в электронном виде. В ней вы найдёте все необходимые для понимания этого материала основы и если вы ещё ни разу не видели Delphi, то после прочтения этой книги вы сможете понять всё описанное здесь. \Документация - Дополнительная документация, которая может понадобиться для понимания каких-то глав. \Иконки - В этой директории вы найдёте большую коллекцию иконок, которые вы можете использовать в своих программах. Эту коллекцию я подбирал достаточно долго и все иконки хорошего качества. \Компоненты - Дополнительные компоненты, которые будут использоваться в примерах книги. \Программы - Программы, которые пригодятся в программировании. Среди них Header Convert - программа, которая конвертирует заголовочные файлы с языка С на Delphi и ASPack - программа сжатия запускных файлов. Спрашивай книгу в книжных магазинах своего города!!!

http://www.vr-online.ru

17


VR-online Journal (Horrific and VR-Team)

Для программистов №6

VRML Начиная с сегодняшнего дня я опубликую несколько уроков по программированию с помощью языка VRML (Virtual Realty Modelling Languagy). Этот язык предназначен для построения 3D миров. Он работает на уровне трёхмерных объектов и их расположении в пространстве. В качестве объектов используются куб, сфера, цилиндр и конус. Во время изучения ты увидишь, что VRML имеет что-то общее с OpenGL. Что такое VRML файл? Это простой текстовый файл с расширением wrl. Для просмотра 3D сцены необходим браузер и специальный plug-in к нему (я буду называть его просмотрщиком) , который и будет отображать VRML мир. Самыми распространёнными просмотрщиками являются Cosmo Player и Live3D. Выбирая себе просмотрщик, ты должен знать, что каждый из них показывает сцену по разному. Поэтому нужно выбирать самый распространённый, чтобы у большинства твоих пользователей мир выглядел также, как и у тебя. Для создания сложных миров, я бы посоветовал тебе воспользоваться специализированными редакторами или даже 3D Studio Max, с помощью которого можно создать мир любой сложности. Цель моих статей будет просто научить тебя основам этого языка. Возможно, что тебе пригодятся эти навыки при построении твоей странички в сети или ты захочешь вставить поддержку этого языка в своей проге. Не пугайся, использовать VRML очень легко, особенно, если ты читаешь мои статьи по OpenGL. В VRML принята не очень обычная система координат. Точнее координаты расположены правильно - ось Х смотрит вправо, ось Y смотрит вверх, а ось Z смотрит на нас или от нас. А вот с разметкой разработчики грубонули - все размеры вычисляются в метрах. Не могу понять, что же они так мелочились, могли бы уже и километрами измерять :). А для измерения углов почему-то используются радианы. Я думаю хватит тебя травить всякой ерундой. Пора приступить к делам. Как я уже говорил, VRML файлы - это простые текстовые файлы. Ты можешь создавать их прямо в блокноте, как это многие (в том числе и я) делают с HTML файлами. Первой строкой файла должна стоять:

Рис 1. Система координат

#VRML V1.0 ascii По этой строке, просмотрщик убедится, что перед нами VRML документ. В этой строке "V1.0" означает версию VRML документа. Её обязательно нужно указывать правильно, потому что уже существует (если мне не изменять память) вторая версия. Текст "ascii" означает, что данные хранятся как простой ascii текст. Ты можешь спросить, а зачем это указывать, если этот файл и так текстовый? А потому что я тебя немного обманул. Файл та текстовый, но он может быть сжать. По спецификации но VRML есть возможность на сжатие данных в файле, что позволяет дополнительно уменьшить размер файлов.

http://www.vr-online.ru

18


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Начнём знакомство с примитивами VRML и заодно напишем первый файл, который будет отображать нашу сцену. Первым примитивом будет куб: Cube { width 4 # ширина height 3 # высота depth 7 # глубина } Сразу обращаю твой зоркий глаз на значок #. Все что стоит после него - это комментарии и игнорируется просмотрщиком. Так что, с помощью этих комментариев прекрасно видно, что первый параметр задаёт ширину, второй высоту, а третий глубину. Теперь я создал файл sampl1.wrl вот с таким содержанием: #VRML V1.0 ascii Cube { width 4 height 3 depth 7 } Теперь посмотрим на результат в действии: Прежде чем приступить к дальнейшему изучению VRML примитивов, я остановлюсь на том, как можно отображать нашу сцену в просмотрщике. Для этого можно открывать файл как простую html страницу с помощью IE или Netscape Navigator. Если установлен специальный plug-in, то ты увидишь результат в действии. В этом случае сцена будет просматриваться во всё окно браузера. Я использую более сложный, но более интересный способ. А именно, я использую JavaScript, чтобы увидеть VRML мир внутри странички. Вот этот скрипт: <script LANGUAGE="JavaScript"> <!-var BrowserName = navigator.appName; BrowserVer = parseInt (navigator.appVersion); if ((BrowserName == "Netscape") && (BrowserVer > 2)) { if (navigator.mimeTypes["x-world/x-vrml"].enabledPlugin==null) { dоcument.writeln ("<H4>Ваш браузер не поддерживает VRML</H4>"); } else { document.writeln ("<EMBED WIDTH='400' HEIGHT='200' SRC='sampl1.wrl'>"); } } else { document.writeln ("<EMBED WIDTH='400' HEIGHT='200' SRC='sampl1.wrl'>"); } //--> </script>

http://www.vr-online.ru

19


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Вроде всё. Хотя стоп. Я же забыл познакомить тебя с остальными примитивами VRML, а их осталось ещё три. Вот как выглядит сфера: Sphere { radius 1 # радиус } Как видишь, здесь задаётся только один параметр - радиус. Это самый лёгкий в реализации среди примитивов VRML. Вот как выглядит конус: Cone { parts ALL #видимость основания, и боковой части конуса bottomRadius 1 #радиус основания height 2 #высота } Со вторым и третьим параметром всё ясно, а вот на первом надо остановится. Я указал параметр ALL, это означает, что я хочу увидеть весь конус. Если мне понадобиться только основание (т.е. круг), то я должен указать первым параметром BOTTOM. Если мне нужны только стороны, без основания, то нужно указать SIDES. Теперь знакомимся с целиндром: Cylinder { parts ALL #Видимость частей radius 1 #радиус основания height 2 #высота цилиндра } Я думаю, что объяснения не нужны. Попробуй поиграть изученными предметами, а через месяц я постараюсь подготовить ещё что-нибудь интересное Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

20


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Ты ищешь хорошую книгу по Delphi? Зайди на www.vr-online.ru и скачай полный электронный вариант Библии Delphi от Фленова Михаила абсолютно бесплатно. Эта книгу научит тебя программировать, даже если ты никогда в жизни не написал ни строчки кода. В ней описано всё, начиная от основ программирования и заканчивая реальными примерами программ и задач, которые программисты решают каждый день. Библия Delphi – самая иллюстрированная и самая бесплатная книга. По ней научились программировать множество людей и ты тоже сможешь.

http://www.vr-online.ru

21


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Форматы файлов: Potoshop PSD Я уже давно не писал про форматы графических файлов, хотя эта тема многих интересует. Сегодня я вернулся к этой теме с очередным форматом, который интересует многих программистов - Adobe Photoshop. Этот формат очень сильно распространён, поэтому мне кажется, что эта статья будет самой интересной для тех, кто хочет заниматься графикой профессионально. Самое главное преимущество формата Photoshop это то, что он является платформенно-независимым. Он поддерживается не только в PC-совместимых, но и в яблоках от Apple. Файл PSD состоит из пяти основных частей - заголовок, блок данных цветового режима, блок ресурсов изображения, блок информации о слоях и на конец данные изображения. Все блоки, кроме заголовка имеют переменную длину. Только заголовок состоит из фиксированных 26 байтов. Я покажу тебе его в виде структуры для Delphi и С++: Для Delphi TPSDHeader = record Signature: array[0..3] of Char; Version: Word; Reserved: array[0..5] of Byte; Channels: Word; Rows, Columns: Cardinal; Depth: Word; Mode: Word; end; Для С++ struct _PSD_HEADER { BYTE Signature[4]; WORD Version; BYTE Reserved[6]; WORD Channels; LONG Rows, Columns; WORD Depth, Mode; }; Теперь рассмотрим каждый параметр в отдельности: Signature - идентификатор файла. Он должен быть всегда "8BPS"; Version - номер версии, всегда равен единице (1); Reserved - резерв, он и в Африке резерв. Он должен быть обнулён. Channels - количество цветовых каналов, включая альфа-канал. Может принимать значения от 1 до 24. Rows и Columns - высота и ширина изображения. Изменяется от 1 до 30000. Depth - глубина цвета или количество бит на канал. Может быть 1, 8 или 16.

http://www.vr-online.ru

22


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Mode - цветовой режим. Цветовой режим (Mode) может принимать значения: 0 - растровое изображение 1 - шкала серого 2 - индексированный цвет (используется палитра) 3 - в виде цветов RGB 4 - в виде цветов CMYK 5 - многоканальный цвет 6 - полутоновое изображение (дуплекс) 7 - цветовая модель Lab. Когда ты прочитаешь заголовок, не торопись его использовать. Сначала нужно обратить своё внимание на то, что PSD файл - межплатформенный, поэтому его данные записаны не в формате PC. А именно, старший и младший бай поменяны местами, поэтому прежде чем использовать параметры их надо перевернуть. Функция для переворота целого есть в Delphi и называется она как: function Swap(X); Для переворота длинного целого числа я не видел функции, поэтому придётся это делать самостоятельно: function SwapLong(Value: Cardinal): Cardinal; overload; asm BSWAP EAX end; Итак, все параметры, которые хранятся в виде WORD нужно переворачивать с помощью Swap, а все параметры в виде LONG нужно переворачивать с помощью SwapLong.Это правило действует не только для заголовка, но и для всех последующих данных. После заголовка идет блок данных цветового режима. Длина этого блока записана сразу после заголовка PSD файла в виде длинного целого числа. Прочитав это число, ты "сможешь" узнать длину блока данных цветового режима. Я подчёркиваю, что ты "сможешь", но сразу не узнаешь, потому что это число тоже перевёрнуто. Не забудь его перевернуть с помощью SwapLong. После того, как ты узнал длину блока данных цветового режима, можно приступать к его чтению. Хранящиеся в этом блоке данные зависят от параметра mode (цветовой режим). Если mode равно 2 (индексированный цвет), то последующие данные состоят из 768 байтов и содержат 256-ю палитру. Если mode = 6 (полутоновое изображение), то последующие данные хранят в себе специфическую информацию об экране. При других значениях mode длинна блока должна быть равна нулю и после 4-х байтового параметра указывающего его длину будет идти блок ресурсов изображения. Блок ресурсов изображения - находится сразу же за блоком данных цветового режима. В нём также, в самом начале находятся четыре байта (число типа LONG), указывающее на длину блока. Весь блок - это структура, хотя и переменной длинны: Для Delphi TColorModeDataBlock = record Type: array[0..3] of Char; ID: Word; Byte: string; Size: Cardinal;

http://www.vr-online.ru

23


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Data: array [0..Size] of Char; end; Для С++ struct _ColorModeDataBlock { BYTE Type[4]; WORD ID; BYTE Name[ ]; LONG Size; BYTE Data[ ]; }; Теперь снова о каждом параметре в отдельности: Type - Первый параметр похож на сигнатуру и всегда 8BIM. По этой последовательности ты можешь проверить, в том ли ты находишься месте? Если нет, то можно поднимать панику. Это может означать испорченность данных. ID - тип. В зависимости от значения этого параметра будет изменяться содержимое параметра Data. Немного позже я покажу возможные здесь варианты. Name здесь находится простое имя, которое можно игнорировать. Самое интересное, что эта строка символов хранится в формате Паскаль. Size - Длинна поля Data. Data - непосредственно данные. Они могут быть длинной Size и их содержимое зависит от значения параметра ID. Теперь о возможных значениях параметра ID. Я знаю далеко не все возможные значения, потому что фирма Adobe не хочет делиться своими секретами. Но то, что я смог выяснить я расскажу. Для этого я создал специальную таблицу: ID 03e8 03eb 03ed 03f0

Тип array[0..4] of Char Структура string

03f4 03f5 03f6 03f8 03f9 03f7 0401 0406

Значение в поле Data Строки, столбцы, режим, глубина, каналы. Таблица индексированных цветов. Инфа о разрешении. Заголовок, строка в формате Паскаль. Инфа о формате пикселя в шкале серого и полутонового изображения. Инфа о формате пикселя полутонового изображения. Инфа о формате пикселя дуплексного полутонового изображения. Функции передачи для цветных изображений. Функции передачи для дуплексных изображений. Функции передачи для "серых" изображений. Рабочий контур. Качество JPEG.

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

http://www.vr-online.ru

24


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Прежде чем окончательно покончить с этим блоком я немного остановлюсь на идентификаторе 03ed. Как ты можешь видеть в моей таблице, данные будут содержать структуру. Возможно, ты захочешь прочитать её и воспользоваться хранящимися в ней данными. Вот как она выглядит: Для Delphi TPSDResInfo = record HRes: Cardinal; hResUnit, WidthUnit:Word; vRes: Cardinal; vResUnit, HeightUnit:Word; end; Для С++ struct _PSD_ResInfo { LONG hRes; WORD hResUnit, WidthUnit; LONG vRes; WORD vResUnit, HeightUnit; }; А теперь о содержимом: hRes - горизонтальное количество пикселей на дюйм. hResUnit - горизонтальная единица измерения. Если 1 - дюймы. 2 - сантиметры. WidthUnit - горизантальная единица измерения ширины. Если 1 - дюймы. 2 сантиметры, 3- точек, 4 - кегль, 5 - столбцы. vRes - вертикальное количество пикселей на дюйм. vResUnit - вертикальная единица измерения. Если 1 - дюймы. 2 - сантиметры. HeightUnit - вертикальная единица измерения ширины. Если 1 - дюймы. 2 сантиметры, 3- точек, 4 - кегль, 5 - столбцы. Ну всё. На сегодня мне кажется хватит. В следующий раз я познакомлю тебя с остальными блоками. Если будет время, то я напишу маленький пример на Delphi для чтения PSD файла. Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

25


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi: Docking – перемещение компонентов Почему-то меня очень часто просят рассказать, как можно добиться такого эффекта как у ToolBar-ов в M$ Office. Для большей ясности - это когда палитру с кнопками можно оторвать от окна и прилепить в другое место или вообще превратить в отдельное окно. Лично мне казался этот материал очень простым. Но так как таких писем стало уже очень много, я решил написать статью, чтобы не объяснять каждому в отдельности. Для того, чтобы TToolBar можно было перемещать, достаточно установить в нём свойство DragKind в dkDock. Вот и всё. Но главная проблема не в этом. Самое сложное здесь - это сохранить положение TToolBar после выхода из проги и восстановить его при запуске. Для примера я написал маленькую прогу, которую ты должен доделать до полноценной. Для демонстрации мне понадобилась кнопка, по нажатию которой будет выводится положение TToolBar:

Рис 1. Пример формы

procedure TForm1.Button1Click(Sender: TObject); var r:TRect; begin if ToolBar1.HostDockSite<>ControlBar1 then begin GetWindowRect(ToolBar1.Handle, R); Application.MessageBox(PChar(IntToStr(r.Left)+'--'+IntToStr(r.Top)), 'MM',IDOK); end; end; В первой строке я проверяю, лежит ли ToolBar1 на ControlBar1 с помощью (ToolBar1.HostDockSite<>ControlBar1). Если он лежит, то получить положение ToolBar1 очень просто. Для этого можно узнать всего лишь ToolBar1.Left и ToolBar1.Top. Если ToolBar1 не лежит на ControlBar1 (ToolBar1 выглядит как отдельное окно), то задача усложняется. Тебе придётся вызывать GetWindowRect, чтобы получить реальное положение ToolBar1 на экране. В качестве первого параметра ты должен передать указатель на ToolBar1, а второй - это переменная типа TRect в которую запишется

http://www.vr-online.ru

26


VR-online Journal (Horrific and VR-Team)

Для программистов №6

реальное положение окна. Для удобства я вывожу эти знчения в окне сообщения Application.MessageBox. Всё это я делаю для наглядности. Теперь ты можешь запустить прогу и переместить ToolBar1 по экрану. Каждый раз, когда ты будешь нажимать кнопку, программа будет выводить окно и показывать тебе реальное положение ToolBar1. По событию OnShow я написал: procedure TForm1.FormShow(Sender: TObject); begin ToolBar1.ManualDock(nil,nil,alNone); ToolBar1.ManualFloat(Bounds(100, 500, ToolBar1.UndockWidth, ToolBar1.UndockHeight)); end; ToolBar1.ManualDock заставляет переместится ToolBar1 на новый компонент. В качестве первого параметра указывается указатель на компонент или окно, к которому мы хотим прилепить ToolBar1. Я хочу, чтобы после загрузки ToolBar1 превратился в отдельное окно, поэтому я указываю nil. Второй параметр можешь ставить nil. Он означает компонент внутри компонента указанного в качестве первого параметра, на который мы хотим поместить ToolBar1. Я указал nil. Третий параметр - выравнивание. С помощью ToolBar1.ManualFloat я просто двигаю ToolBar1 внутри нового компонента. У меня новый компонент nil, т.е. окно, поэтому я двигаю ToolBar1 по окну. Может не совсем понятно? Попробуй запустить пример и поиграть с ним, тогда всё встанет на свои места. И ещё ToolBar1.UndockWidth и ToolBar1.UndockHeight возвращают размер ToolBar1, когда он выглядит как окно, а не лежит на ControlBar1. Когда ты будешь использовать это в своей проге для сохранения положения ToolBar1, тебе надо будет написать примерно следующее по событию OnClose: var r:TRect; begin if ToolBar1.HostDockSite<>ControlBar1 then begin GetWindowRect(ToolBar1.Handle, R); Здесь надо сохранить в реестре R.Left и R.Top. А также признак, что ToolBar1 не лежит на ControlBar1 end else begin Здесь надо сохранить в реестре ToolBar1.Left и ToolBar1.Top. А также признак, что ToolBar1 лежит на ControlBar1 end; end; На запуск программы ты должен написать примерно следующее: procedure TForm1.FormShow(Sender: TObject); begin Прочитать положение ToolBar1. ControlBar1 то Begin ToolBar1.Left:=Сохранённая левая позиция ToolBar1.Topt:=Сохранённая верхняя позиция

http://www.vr-online.ru

27


VR-online Journal (Horrific and VR-Team)

Для программистов №6

End; Иначе begin ToolBar1.ManualDock(nil,nil,alNone); ToolBar1.ManualFloat(Bounds(Сохранённая левая позиция, Сохранённая правая позиция, ToolBar1.UndockWidth, ToolBar1.UndockHeight)); End; end; Как видишь, подводные булыжники есть. Но всё же ничего сильно сложного нет. Теперь мы сделаем менюшку в стиле M$. Для этого нужно поставить ещё один ToolBar и установим его свойство ShowCaption в true.Создадим на нём две кнопки и назовём их File и Edit . Теперь установим компонент MainMenu и сделаем его таким как на рисунке 2. Меню Not visible сделаем невидимым (Visible=false), в этом случае всё меню будет подключено к форме но будет не видно. Для чего я это делаю, ведь можно было использовать PopupMenu? А потому что при использовании PopupMenu приходится Рис 2. Меню мучится с клавишами быстрого вызова, а в моём способе они подключаются автоматически вместе с главным меню. Примечание!!! Чтобы создать подменю для меню File, нужно щёлкнуть по нём правой кнопкой и выбрать Create Submenu или нажать CTRL+Стрелка в право. Теперь кнопке File в свойстве MenuItem ставим File1 (имя пункта меню), а кнопке Edit ставим Edit1. И на последок обеим кнопкам нужно установить свойство Grouped в true. Запускаем, наслаждаемся!!!! Исходники примера можете взять в файле delphi.zip.

Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

28


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi: Прозрачные окна Прозрачность окна – миф или реальность? Сегодня я превращу этот миф в программу. Посмотри на рисунок в этой статье и ты увидишь, что моя форма прозрачна. Сквозь окно виден текст проги на Delphi. Это не какой-то эффект фотожопа, это ловкость рук и пара недокументированных API из окон.

Рис 1. Форма Как всегда, меньше болтовни, а больше дела. Пример работает только под Win2000. Смотри на полный исходник проги и ты всё сам увидишь: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Edit1: TEdit; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; //Описываю недокументированную функцию SetLayeredWindowAttributes function SetLayeredWindowAttributes(hwnd: longint; crey: byte; bAlpha: byte; dwFlags: longint): longint; stdcall; external 'USER32.DLL'; implementation

http://www.vr-online.ru

29


VR-online Journal (Horrific and VR-Team)

Для программистов №6

{$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); var old: longint; begin old:=GetWindowLongA(Handle,GWL_EXSTYLE); SetWindowLongA(Handle,GWL_EXSTYLE,old or $80000); SetLayeredWindowAttributes(handle, 0, 150, $2); end; end. Я думаю, что всё понятно по комментариям. Мы рассмотрим тут только самую интересную функцию SetLayeredWindowAttributes. Первый параметр – указатель на окно. Второй мне не известен. Третий – число указывающее на прозрачность и изменяться в пределах от 0 до 255. Я подставил прозрачность равную 150, но если ты захочешь рассчитывать в процентах, то можешь вставить сюда формулу (255 * х) DIV 100, где х – процент прозрачность от 0 до 100. Последний параметр – константа и обязана быть такой. Всё!!! Абсолютно ничего сложного. Только ловкость рук, а не рукоблудство. Пример прекрасно работает в Windows 2000. Кстати, есть способ проще: 1. Установить свойство AlphaBlend у формы в true. 2. После этого, свойство AlphaBlendValue будет указывать на степень прозрачности. Но эта возможность появилась, кажется, только в Delphi6. Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

30


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Delphi (ActiveX): Программы для Internet Это ещё один новый раздел, который будет состоять из нескольких статей. В нём я расскажу о программировании ActiveX компонентов. Это очень сильная вещь, поэтому я советую тебе обратить на него внимание. Сегодня я научу тебя писать проги, которые можно публиковать на страничках в сети Internet. Эти проги смогут загружаться в окно браузера IE и выполнятся прямо в нём, как это делает Java. Какие преимущества даёт ActiveX? Он позволяет практически всё. Какие недостатки? Его разрабатывала Microsoft, поэтому там слабая безопасность. Из-за плохой безопасности, ActiveX может таить в себе большие угрозы для пользователя, поэтому большинство из них отключает возможность их загрузки в браузеры. Но если ты будешь разрабатывать приложения для своей корпоративной или другой сети, то преимущества от ActiveX тут будут громадны.

Рис 1. Создание ActiveX Действие сегодняшнего примера не будет ограничиваться только браузером. Зарегистрировав его в системе, ты сможешь использовать его вставляя в свои проекты на Delphi. Такие ActiveX-формы будут выглядеть как простые компоненты. А главное преимущество, что такие компоненты можно использовать не только в Delphi, но и в Visual Basic и даже Visual C++. Таким образом очень легко объединить труд нескольких программистов пишущих на различных языках. Несколько таких компонент может быть написано на любом языке и собрано в кучу в другом. Ну хватит хвалить ActiveX, пора переходить к делу. Для создания нового проекта, ты должен выбрать New из меню File . Перед тобой откроется окно, как на рисунке 1. Выбери закладку ActiveX и дважды щёлкни по ActiveForm.

http://www.vr-online.ru

31


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Рис 2. Свойства нового ActiveX После этого, перед тобой откроется окно, как на рисунке 2. В этом окне ты должен заполнить: • • • • • • •

New ActiveX Name – имя твоего ActiveX. Постарайся дать здесь разумное имя, потому что оно будет потом использоваться для отображения в системе. Не очень приятно будет смотреть на компонент с именем ActiveFormX. Implementation Unit – имя исполнительного модуля. Project Name – имя проекта, тоже постарайся дать разумное имя. Threading Model – для нас достаточно здесь значения по умолчанию. Make Control Licensed – создать лицензию для компонента. Include Version Information – включить в компонент информацию о версии. Include About Box – включить окно «About».

Рис 3. Пример моей формы Я поменял только имя компонента и проекта. CheckBox-ы оставил без изменений. Жми ОК и перед тобой появится привычная форма. Смело располагай на ней компоненты и работай, как с привычным проектом. Ты можешь засунуть сюда целую программу по учёту заработной платы депутатов. Я не стал сильно извращаться, потому что я делаю простой пример. На рисунке 3 ты можешь увидит моё творение. После того, как ты установил все компоненты, откомпилируй проект нажав Ctrl+F9. OCX файл готов. Теперь надо зарегистрировать его в системе, чтобы можно было его протестировать. Для этого выбери register ActiveX Server из меню Run .

http://www.vr-online.ru

32


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Рис 4. Настройка публикации Можно переходить к тестированию. Для этого выбери «Web Deployment Option» из меню “Project”, и перед тобой откроется окно, как на рис. 4. Рассмотрим каждый параметр в отдельности: • • • •

Target Dir - директория, в которую попадёт скомпилированный файл OCX. Target URL - Адрес в инете, откуда будет загружен OCX, если пользователь открыл страницу через IE-браузер. HTML Dir - директория, в которую попадёт HTML-файл. Use CAB compression - упаковать ocx файл в CAB архив.

http://www.vr-online.ru

33


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Рис 5. результат запуска HTML-файла

Рис 6. инсталяция OCX файла Я советую тебе выбирать «Target Dir» и «HTML Dir» отличную от той в которой лежит твой проект. После того, как ты заполнишь здесь все данные, жми «ОК». Теперь

http://www.vr-online.ru

34


VR-online Journal (Horrific and VR-Team)

Для программистов №6

выбираем «Web Deploy» из меню “Project”. Через пару сек всё закончится и ты сможешь запустить созданную Дельфой HTML страницу. Запусти её и посмотри на результат. Есть ещё один способ протестить твою прогу. Для этого выбери “Import ActiveX Control …» из меню “Component” и ты увидишь окно, как на рис 5. Найди в верхнем списке имя твоего компонента и нажми Install. Delphi установить этот компонент и его иконка появится на закладке ActiveX палитры компонентов. Теперь ты сможешь устанавливать его на любую форму и вообще, использовать как простой компонент. Исходники забирай в файде delphi2.zip Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

35


VR-online Journal (Horrific and VR-Team)

Для программистов №6

SQL: Запросы с подзапросами В прошлом месяце я немного поторопился, когда начал тебе рассказывать про объединения, потому что сегодняшние знания я должен был дать немного раньше. В принципе, особой разницы нет, но всё же было бы удобнее сначала воспринять этот материал, а потом уже объединения. В дальнейшем я постараюсь давать материал более последовательно, не забегая вперёд.

Рис 1. Связь между таблицами. Итак, мы переходим к дальнейшему изучению SQL. Сегодня нам предстоит изучить подзапросы. Что это значит? SQL позволяет вставлять одни запросы внутрь других. Сейчас мы рассмотрим пример, но сначала я напомню тебе структуру наших таблиц, смотри рисунок 1. Представим, что нам надо вывести все записи из таблицы User.db, которые соответствуют программе MyProg.exe. На первый взгляд запрос очень простой. Нужно написать: SELECT * FROM User1.db WHERE Key2 = Key1 для программы MyProg.exe; Возникает вопрос: "Какой ключ 1 у программы?". Для того, чтобы это узнать мы можем воспользоваться вложенным запросом. Теперь посмотрим на этот запрос: SELECT * FROM User1.db WHERE Key2 = (SELECT Key1 FROM Prog WHERE ProgName LIKE 'MyProg.exe');

http://www.vr-online.ru

36


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Сначала SQL выполнит внутренний запрос, который расположен в скобках и результат подставит в внешний запрос. Всё прекрасно, но должно выполнятся два условия: у внутреннего запроса, в качестве результата должен быть только один столбец. Это значит, что ты не можешь написать во внутреннем запросе SELECT * , а можно только SELECT ИмяОдногоПоля. Помни, что имя должно быть только одно и тип его должен совпадать с типом сравниваемого значения (в нашем случае с типом key2 из таблицы User1). Результатом внутреннего запроса, должна быть только одна строка. Если внутренний запрос вернёт несколько строк или вообще ничего не вернёт, то могут возникнуть проблемы. Так что ты должен очень аккуратно использовать подзапросы, потому что они могут привести к ошибке. Для большей надёжности используй с подзапросом оператор DISTINCT. Единственный случай, когда подзапрос может выдавать в результате несколько строк, это когда в основном запросе используется оператор IN: SELECT * FROM User1.db WHERE Key2 IN (SELECT Key1 FROM Prog WHERE ProgName LIKE 'MyProg.exe'); Здесь, вместо знака равно я использовал оператор IN (key2 IN (подзапрос)). Так что для надёжности запроса можно использовать не только DISTINCT, но и оператор IN. Это желательно делать даже в тех случаях, когда ты уверен, что результатом будет только одна строка. Хочу ещё обратить твоё внимание, что я написал запрос так: key2= (подзапрос). Ты должен писать также. Ни в коем случае нельзя эту запись написать как (подзапрос)=Key2. Подзапрос должен идти после знака = или любого другого, но никак ни перед. Самое сильно, что ты можешь обращаться из внутреннего запроса к внешнему. Как это делать? SELECT * FROM User1.db outer WHERE Key2 = (SELECT Key1 FROM Prog inner WHERE key1 = outer.Key2); Слова outer и inner - псевдонимы, которые назначаются таблицам user1 и prog соответственно. Это значит, что когда мы пишем outer, это то же самое, что и написать User1. Такой запрос будет выполнятся по следующему алгоритму: Выбрать строку из таблицы User1.db в внешнем запросе. Это будет текущая строкакандидат. Сохранить значения из этой строки-кандидата в псевдониме с именем outer. Выполнить подзапрос. Везде, где псевдоним данный для внешнего запроса найден (в этом случае "outer"), использовать значение для текущей строки-кандидата. key1 = outer.Key2. Использование значения из строки- кандидата внешнего запроса в подзапросе называется - внешней ссылкой. Оценить предикат внешнего запроса на основе результатов подзапроса выполняемого в предыдущем шаге. Он определяет - выбирается ли строка-кандидат для вывода.

http://www.vr-online.ru

37


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Пример не совсем удачный, но возможно ты придумаешь лучше. Попробуй остановится на секунду и подумать над предложенным мной запросом. Если ты сможешь с эти разобраться, то ты поймёшь всю силу программирования на SQL. Я больше не буду забивать тебе сегодня голову, потому что я и так дал достаточно сложный материал. До скорых встреч!!! Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

38


VR-online Journal (Horrific and VR-Team)

Для программистов №6

OpenGL: Освещение Мы практически подобрались к концу наших занятий по OpenGL. Практически все основы я уже дал, и со следующих номеров мы будем заниматься только практикой. Освоив освещение, ты сможешь уже сам создавать полноценную 3D анимацию. А я только буду тебе помогать, выкладывая на свои странички различные примеры. Таким образом, ты увидишь все тонкости прелести OpenGL.

Рис 1. Результат Как и все остальные примочки, освещение включается с помощью команды glEnable . Без освещения наши сцены трудно назвать трёхмерными, потому что конус выглядит как треугольник или вообще не понятно что, а сфера выглядит как круг. Без освещения объект выглядит монотонно и практически незаметны его загогулины и выпиндрёжы. По умолчанию освещённость отключена, но когда ты её включишь, то рассеянный свет примет значение (0.2, 0.2, 0.2, 1). Это практически минимальная освещённость. Максимальная равна (1, 1, 1, 1). Параметры освещения задаются с помощью команды glLightModel. Для этой команды нужны два параметры. Параметр света, который нужно изменить. Значение Если ты будешь вызывать эту функцию как glLightModelf или glLightModeli (разница в последних буквах), то первый параметр сможет принимать значения GL_ LIGHT_ MODEL_ LOCAL_ VIEWER или GL_ LIGHT_ MODEL_ TWO_ SIDE, а второй GL_TRUE или GL_FALSE.

http://www.vr-online.ru

39


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Если функция будет выглядеть как glLightModelfv или glLightModeliv, то первый параметр сможет выглядеть как GL_LIGHT_MODEL_AMBIENT, GL_LIGHT_MODEL_LOCAL_VIEWER или GL_LIGHT_MODEL_TWO_SIDE, а второй параметр - массив значений. Вот как будет выглядеть установка значения рассеянного света в синий цвет: const ambient : Array [0..3] of GLFloat = (0.0, 0.0, 1.0, 1.0); begin glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); end; Прежде чем приступить к дальнейшему изучению освещённости нам необходимо ещё понять как работать с материалами. Освещённость объекта зависит от материала объекта. Это ни чем не отличается от реального мира. Например, метал имеет менее освещённую поверхность из-за его меньшей отражающей способности, полимеры тоже имеют свои особенности в зависимости от состава. Материал может как отражать, так и излучать свет. Свойства материала устанавливаются с помощью функции glMaterialfv. Для неё нужно три параметра: Первый параметр - это грань к которой будет применён материал. GL_BACK - задняя грань, GL_FONT - передняя грань и GL_FRONT_AND_BACK - обе грани. Второй параметр - свойства материала. Может быть: GL_AMBIENT - рассеянный свет, GL_DIFFUSE - рассеянный свет, GL_SPECULAR - отраженный свет, GL_EMISSION излучаемый свет, GL_SHININESS - степень отраженного света, GL_AMBIENT_AND_DIFFUSE - оба рассеянных света. Третий параметр - значение цвета в формате RGBA. С теорией покончено. Теперь посмотрим на пример и после него немного поднимем свои знания об освещённости. procedure TForm1.FormPaint(Sender: TObject); const emission : Array [0..3] of GLFloat = (0.0, 0.0, 1.0, 1.0); ambient : Array [0..3] of GLFloat = (0.0, 0.0, 1.0, 1.0); diffuse : Array [0..3] of GLFloat = (1.0, 0.0, 0.0, 1.0); pos : Array [0..3] of GLFloat = (5.0, 10.0, -20.0, 1.0); shiness : GLFloat = 70.0; var ps:TPaintStruct; begin BeginPaint(Handle,ps); glClearColor(1,0.5,0.5,1); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //Включаю освещение glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); //Задаю позицию источника света glLightfv(GL_LIGHT0, GL_POSITION, @Pos); glPushMatrix; glRotated(45,1,0,0); //Синий материал для сферы

http://www.vr-online.ru

40


VR-online Journal (Horrific and VR-Team)

Для программистов №6

glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, @emission ); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, @ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS,@shiness ); gluQuadricDrawStyle (quadObj, GLU_FILL); glColor3f(1,0,0); gluSphere (quadObj,1, 100, 10); //Сине-красный материал для конусов. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, @emission ); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, @diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,@diffuse ); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,@diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS,@shiness ); glTranslatef(1.5,1,1); gluCylinder (quadObj,0, 0.2, 1, gluDisk (quadObj, 0.2, 0.3, 20, glTranslatef(-3,0,0); gluCylinder (quadObj,0, 0.2, 1, gluDisk (quadObj, 0.2, 0.3, 20, glPopMatrix;

30, 10); 2); 30, 10); 2);

glFlush(); swapBuffers(dc); EndPaint(Handle,ps); end; В наиболее интересных местах я поставил комментарии. Единственное, что я забыл рассказать, так это про функцию glLightfv. Она устанавливает параметры света и требует три параметра: Номер источника света. Они нумеруются как GL_LIGHT0, GL_LIGHT1, GL_LIGHT2 и так до GL_LIGHT9. Как я уже говорил, источник включается с помощью glEnable(GL_LIGHT0), в скобках указан номер источника. Параметр, который нужно изменить: GL_POSITION (позиция источника) или GL_SPOT_DIRECTION (позиция точки в которую светит источник). Значение устанавливаемого параметра. Вот и всё. Да будет свет сказал программист и выключил Back-UPS. Теперь я с уверенностью могу сказать, что со светом мы покончили. В будущих номерах я буду выкладывать демки, в которых более подробно расскажу о хитростях и о свете (с маленькой буквы:)) тоже. Исходники находятся в файле opengl1.zip Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

41


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Java: Компоненты часть вторая Сегодня мы продолжим знакомится с компонентами Java. Я не стал включать откомпилированные примеры, для лучшей загрузки страницы, поэтому тебе придётся откомпилировать самому. Так что читай, изучай, запоминай всё, что я тебе буду говорить. Начнём мы с компонента, похожего на TRadioBox в Delphi. import java.awt.*; import java.applet.*; public class CheckboxGroupDemo extends Applet { public void init() { setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer.parseInt(getParameter("height")); CheckboxGroup g = new CheckboxGroup(); Checkbox g1 = new Checkbox("Java", g, true); Checkbox g2 = new Checkbox("Delphi", g, false); Checkbox g3 = new Checkbox("C++", g, false); add(g1); add(g2); add(g3); g1.reshape(0, 0, width, height / 3); g2. reshape(0, height / 3, width, height / 3); g3.reshape(0, 2 * height / 3, width, height / 3); }} Ты уже знаешь все операторы, которые я использовал здесь, поэтому нет смысла рассказывать в очередной раз всё, что здесь написано. Для экономии места, я буду приводить примеры, и останавливаться, только на индивидуальных особенностях. Теперь познакомимся с выпадающим списком (аналог TcomboBox): import java.awt.*; import java.applet.*; public class ChoiceDemo extends Applet { public void init() { setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer.parseInt(getParameter("height")); Choice b = new Choice(); b.addItem("Java"); b.addItem("Delphi"); b.addItem("C++"); b.select("Java"); add(b); b.reshape(0, height / 2, width, height / 2); }}

http://www.vr-online.ru

42


VR-online Journal (Horrific and VR-Team)

Для программистов №6

Строка Choice b = new Choice() Создаёт новый выпадающий список. С помощью b.addItem("Java") я добавляю новый элемент с надписью "Java". b.select("Java") делает элемент Java выделенным. Ну а далее, всё как всегда: добавляем элемент к апплету и изменяем его размеры. Теперь познакомимся с простым списком (аналог TListBox): import java.awt.*; import java.applet.*; public class ListDemo extends Applet { public void init() { setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer.parseInt(getParameter("height")); List b1 = new List(0, true); List b2 = new List(0, false); b1.addItem("Java"); b1.addItem("Delphi"); b1.addItem("C++"); b1.addItem("ADA"); b2.addItem("Line 1"); b2.addItem("Line 2"); b2.addItem("Line 3"); b2.addItem("Line 4"); b2.addItem("Line 5"); browser.select(1); add(b1); add(b2); b1.reshape(0, 0, width, height / 2); b2.reshape(0, height / 2, width, height / 2); }} Здесь всё очень похоже на выпадающий список. В принципе, этого и следовало ожидать, потому что компоненты очень похожи, просто один выпадает а другой нет. Двигаемся дальше вместе с полосами прокрутки: import java.awt.*; import java.applet.*; public class ScrollbarDemo extends Applet { public void init() { setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer. parseInt(getParameter("height")); Scrollbar hs = new Scrollbar(Scrollbar.HORIZONTAL, 50, width / 10, 0,100); Scrollbar vs = new Scrollbar(Scrollbar.VERTICAL, 50, height / 2, 0, 100); add(hs); add(vs); int thickness = 16; hs.reshape(0, height - thickness, width - thickness, thickness); vs.reshape(width - thickness, 0, thickness, height - thickness); }} Теперь познакомимся с текстовым полем: import java.awt.*; import java.applet.*; public class TextAreaDemo extends Applet { public void init() {

http://www.vr-online.ru

43


VR-online Journal (Horrific and VR-Team)

Для программистов №6

setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer.parseInt(getParameter("height")); String val = "This is first lene.\n" + "this is 2 line"; TextArea text = new TextArea(val, 80, 40); add(text); text.setBounds(0, 0, width, height); }} С помощью String val = "This is first lene.\n" + "this is 2 line" я создаю текстовую переменную val в которую заношу текст. Текст состоит из двух строк. В качестве разделителя строк выступает "\n" (слэш и буква n). При создании нового текстового поля, я указываю эту переменную (val) в качестве первого параметра (TextArea text = new TextArea(val, 80, 40)). Этим я заношу текст из переменной val в текстовое поле. Остальные операторы как всегда. И напоследок я покажу как создать два лейбла (мы их уже изучали) и два поля для ввода текста. Я оформил всё это как приглашение ввести пароль: import java.awt.*; import java.applet.*; public class TextFieldDemo extends Applet { public void init() { setLayout(null); int width = Integer.parseInt(getParameter("width")); int height = Integer.parseInt(getParameter("height")); Label namep = new Label("Name : ", Label.RIGHT); Label passp = new Label("Password : ", Label.RIGHT); TextField name = new TextField(8); TextField pass = new TextField(8); pass.setEchoChar('*'); add(namep); add(name); add(passp); add(pass); int space = 30; int w1 = width / 3; namep.setBounds(0, 10, w1, space); name.setBounds(w1, 10, w1, space); passp.setBounds(0, 60, w1, space); pass.setBounds(w1, 60, w1, space); }} В принципе, всё должно быть ясно. Толь ко один оператор может вызвать у тебя смущение - pass.setEchoChar('*'). Он указывает символ, который будет показывается в строке ввода вместо набираемых символов. Я указал звёздочку, которая часто используется в полях для ввода пароля. Когда ты запустишь этот пример, то перед тобой появится два поля ввода. Если ты будешь вводить текст в первое поле, то ты увидишь всё что вводишь. Если вводить во второй окно, то увидишь, только звёздочки. Вот это и есть эффект pass.setEchoChar('*'). На сегодня всё. Я не делал архив с примерам, потому что они полностью даны в статье. Просто копируй их и сохраняй в файл. Так мы и узнаем, как хорошо ты читал всё, что я тебе рассказывал. Copyright © Фленов Михаил aka Horrific

http://www.vr-online.ru

44


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.