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

Page 1

VR-online JOURNAL Фленов Михаил and VR-Team VR-online для программистов №4

Delphi (Графика): Графические подсказки .................................................................................3 Delphi: Хранители экрана .............................................................................................................7 Delphi (Базы данных): Моментальный поиск ...........................................................................11 Delphi: Работа с дисками ............................................................................................................14 Delphi (графика): Работа с рабочим столом..............................................................................20 DirectX: Первый 3D.....................................................................................................................23 Java: Занятие второе ....................................................................................................................27 SQL: Занятие третье ....................................................................................................................29 SQL: Работа с несколькими таблицами.....................................................................................31 OpenGL: Рисование картинок ....................................................................................................34

Copyright: VR-online Journal http://www.cydsoft.com/vr-online


VR-online Journal (Horrific and VR-Team)

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

Недавно на нашем форуме кто-то завёл тему о смысле жизни. Я не знаю, зачем люди ищут ответ на этот вечный вопрос. На него нет ответа, не было и не будет. Лично я считаю так, если в старости тебе будет что вспомнить, то ты прожил свою жизнь со смыслом. Если вспомнить нечего, то ты потратил её зря. Не задавай себе таких глобальных вопросов, иначе ты зря будешь тратить время в поисках ответа. Просто живи ради жизни, но задумывайся о своих поступках, которые ты совершаешь. Если сейчас ты считаешь это правильным, то в будущем ты можешь увидеть это диким. Простейший пример: мой знакомый проколол ухо и ходил с серёжкой. Я ему задал только один вопрос – «Что ты скажешь своим детям и внукам?». Сейчас ходить с серёжкой, это нормально, но ты должен отдавать себе отчёт в том, что в будущем это может оказаться излишним. Мода меняется, а твоё тело остаётся, и воспринимай его таким, какое оно есть. Наслаждай жизнью, но не порть её алкоголем и наркотиками. Я в своё время пил очень сильно и как в голливудской истории из алкоголика превратился в цивилизованного человека с достаточно большими знаниями и большой популярностью. Но если бы мне предложили что-то изменить, то я бы не пил в своей молодости. Я не успел угробить здоровье, и это были весёлые годы в моей жизни, но я не понимаю, почему нельзя было развлекаться без водки. Можно выпить 50 или 100 грамм, но не так, как мы с кумом по 1,5 литра на морду, и потом весь новый год обнимать унитаз. Когда меня жена спросила, когда у кума день рождения, то я сказал – «Где-то за пару дней до нового года». Оказалось 20 декабря. Это надо же было так пить, начиная с 20 декабря и заканчивая 15 января без перерыва. Это алкоголизм и болезнь. А люди говорят, что компьютеры – это болезнь. Это лекарство, которое вылечило меня от алкоголизма и теперь у меня совершенно другой смысл жизни – жить. Что-то мои мысли сегодня раскидало по разным темам.

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

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

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

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

Horrific

http://www.cydsoft.com/vr-online

2


VR-online Journal (Horrific and VR-Team)

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

Delphi (Графика): Графические подсказки Что я имел ввиду под выражением "графические подсказки"? Всё очень просто. Ты каждый день встречаешь в программах строку состояния внизу экрана, в которой выскакивают подсказки. Сегодня я покажу тебе, как сделать эти подсказки трёхмерными.

Рис 1. Пример На рисунке 1 показана форма, которая будет использоваться нами для вывода графической подсказки. Прежде чем мы приступим, я хочу рассказать, как вообще выводятся подсказки. Вот пример программы (точнее огрызок от программы), которая выводит подсказки: procedure TForm1.FormCreate(Sender: TObject); begin Application.OnHint := ShowHint; end; procedure TForm1.ShowHint(Sender: TObject); begin StatusBar1.SimpleText:=Application.Hint; end; Теперь о том, что же здесь происходит. В процедуре FormCreate, мы устанавливаем событию Application.OnHint свою процедуру ShowHint . Теперь, когда будет происходить событие OnHint (т.е. когда нужно вывести подсказку), будет вызываться процедура ShowHint . В этой процедуре я просто вывожу подсказку в StatusBar1. Как видишь, всё очень просто. Теперь можно переходить к графической подсказке. Вот полный исходник: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;

http://www.cydsoft.com/vr-online

3


VR-online Journal (Horrific and VR-Team)

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

type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; StatusBar1: TStatusBar; RadioButton1: TRadioButton; RadioButton2: TRadioButton; procedure FormCreate(Sender: TObject); private { Private declarations } procedure ShowHint(Sender: TObject); public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin Application.OnHint := ShowHint; end; procedure TForm1.ShowHint(Sender: TObject); var l,t:Integer; begin StatusBar1.Repaint; with StatusBar1.Canvas do begin Brush.Style:=bsClear; Font.Color:=clWhite; l:=10; t:=1; TextOut(l,t,Application.Hint); if RadioButton1.Checked then begin inc(l); inc(t); end else begin dec(l); dec(t); end; Font.Color:=clBlue; TextOut(l,t,Application.Hint); end; end; end.

http://www.cydsoft.com/vr-online

4


VR-online Journal (Horrific and VR-Team)

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

Здесь тоже ничего сложного нет. Я просто вывожу два раза текст подсказки с разным цветом и небольшим смещением. Единственное, что может показаться для тебя новым, так это конструкция: with StatusBar1.Canvas do begin end; Как я помню, я уже говорил о ней, но всё же решил вернуться и объяснить ещё раз. Она означает, что всё, что находиться между begin и end будет выполняться вместе с StatusBar1.Canvas. На первый взгляд не понятно. Сейчас попробую растолковать. Если ты просто напишешь в процедуре Font:=MyFont, то измениться свойство Font у твоей формы. А если ты напишешь тоже самое внутри конструкции WITH, то измениться Font у StatusBar1.Canvas. Конечно же ты мог бы записать это как StatusBar1.Canvas.Font:=MyFont, но представь, что тебе надо обработать несколько параметров у StatusBar1.Canvas. В этом случае у тебя может конструкция вырости до больших размеров. Например: StatusBar1.Canvas.Font:=MyFont StatusBar1.Canvas.Brush:=MyBrush; Намного проще записать всё это так: with StatusBar1.Canvas do begin Font:=MyFont StatusBar1.Canvas.Brush:=MyBrush; end; Так тот же код выглядит намного компактнее, хотя для неопытного пользователя может создать проблемы с чтением. Всё же тебе стоит приучаться к этой конструкции, потому что она очень часто используется другими. Если ты её не поймёшь, то не сможешь читать тексты других программистов. На сегодня новостей больше нет. Удачи тебе.

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

http://www.cydsoft.com/vr-online

5


VR-online Journal (Horrific and VR-Team)

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

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

http://www.cydsoft.com/vr-online

6


VR-online Journal (Horrific and VR-Team)

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

Delphi: Хранители экрана Если ты до сих пор считаешь, что Delphi это язык, предназначенный для работы с базами данных, то сегодня я окончательно опровергну твоё мнение. Здесь я покажу, что на Delphi можно написать даже хранитель экрана. Самое главное, что никаких особых усилий не понадобится. С одной стороны, эта статья должна была идти в разделе "Работа с графикой", потому что мы будем много рисовать. Но я решил её вставить сюда, потому что используемые здесь графические функции мы уже изучили. А вот само программирование будет очень интересным. Для того, чтобы Delphi мог создать хранитель экрана, ты должен сделать несколько установок для своей формы: • • • • • •

Перед объявлением типов вставить вот такую строку: {$D SCRNSAVE Raver}. Свойство формы BorderStyle поменять на bsNone . Это означает, что у формы не должно быть никаких заголовков и обрамлений. Все параметры в Border Icons установить в False. Свойство формы WindowState поменять на wsMaximized . Создать событие OnKeyPress и вставить туда всего лишь одну процедуру Close() . На событие FormActivate значения Left и Top нужно установить в ноль.

Теперь Delphi создаст хранитель экрана. Остаётся одна деталь - у хранителя расширение SCR. Ты можешь после создания переименовать файл в *.scr или возложить этот тяжёлый труд на Delphi. Для этого необходимо выбрать пункт Option из меню Project и на закладке Application в строке Target file extension написать SCR. В этом случае Delphi сам подставить это расширение. Подготовительные работы закончены. Можно приступать к написанию хранителя экрана. Ты уже знаешь достаточно много, и сможешь сам написать что-нибудь интересное. А я всё же покажу простейший пример. Для моего примера понадобится объявить три переменные в разделе private : private { Private declarations } BGbitmap:TBitmap; DC : hDC; BackgroundCanvas : TCanvas; Затем посмотрим на мой обработчик события OnCreate procedure TForm1.FormCreate(Sender: TObject); begin BGbitmap:=TBitmap.Create;//Инициализация

http://www.cydsoft.com/vr-online

7


VR-online Journal (Horrific and VR-Team)

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

// Выставляем размеры картинки как у экрана BGbitmap.Width := Screen.Width; BGbitmap.Height := Screen.Height; DC := GetDC (0); BackgroundCanvas := TCanvas.Create; BackgroundCanvas.Handle := DC; BGBitmap.Canvas.CopyRect(Rect (0, 0, Screen.Width, Screen.Height), BackgroundCanvas, Rect (0, 0, Screen.Width, Screen.Height)); BackgroundCanvas.Free; randomize; end; Что здесь творится? В самом начале я инициализирую BGbitmap и устанавливаю ему размер как у экрана. Потом в переменную DC заноситься указатель на контекст вывода экрана. На первый взгляд это происходит не явно, но всё очень просто. GetDC возвращает указатель на контекст указанного в качестве параметра устройства или формы. Если указать 0, то GetDC вернёт указатель на контекст воспроизведения экрана. Если ты захочешь получить контекст воспроизведения твоей формы, то ты должен написать GetDC(Handle). В качестве параметра выступает Handle (указатель) окна. Но ты в таком виде не будешь никогда использовать GetDC, потому что у тебя уже есть контекст воспроизведения формы - это Canvas, а указатель на него Canvas.Handle. Дальше я создаю BackgroundCanvas - это TСanvas, который будет указывать на экран. Я делаю это только для удобства. Я мог бы использовать для рисования DC, но всё же TCanvas более понятен. С помощью следующей строки, я сохраняю копию экрана: BGBitmap.Canvas.CopyRect(Rect (0, 0, Screen.Width, Screen.Height), BackgroundCanvas, Rect (0, 0, Screen.Width, Screen.Height)); Здесь всё очень просто, и твоих знаний уже должно хватать на понимание этого кода. Затем я уничтожаю указатель на контекст экрана (BackgroundCanvas.Free). Самая последняя функция - randomize инициализирует таблицу случайных чисел. Если ты этого не сделаешь, то после запроса у системы случайного числа, тебе вернут значение из текущей таблицы, которая не всегда удачна. Тебе не надо будет видеть таблицу случайных чисел, она прекрасно будет работать без твоих глаз. В обработчике события OnDistroy я уничтожаю картинку: procedure TForm1.FormDestroy(Sender: TObject); begin BGBitmap.Free; end; Последняя функция - это обработчик таймера, который я поставил на форму: procedure TForm1.Timer1Timer(Sender: TObject); const DrawColors: array[0..7] of TColor =(clRed, clBlue, clYellow, clGreen,

http://www.cydsoft.com/vr-online

8


VR-online Journal (Horrific and VR-Team)

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

clAqua, clFuchsia, clMaroon, clSilver); begin BGBitmap.Canvas.Pen.Color:=DrawColors[random(7)]; BGBitmap.Canvas.MoveTo(random(Screen.Width),random(Screen.Height)); BGBitmap.Canvas.LineTo(random(Screen.Width),random(Screen.Height)); Canvas.Draw(0,0,BGBitmap); end; В разделе констант я объявляю массив DrawColors который хранит восемь цветов. Объявление происходит следующим образом: Имя_Массива : array [Индекс_первого_значения .. Индекс_последнего_значения] of Тип_значения_Массива = (Перечисление_значений) В "перечислении_значений" должно быть описано "Индекс_последнего_значения""Индекс_первого_значения"+1 параметров. В моём случае это 7-0+1=8 значений цвета. Дальше меняю цвет у контекста рисования формы BGBitmap.Canvas.Pen.Color случайным цветом из массива DrawColors. Функция random возвращает число из таблицы случайных чисел, при этом, это число будет больше нуля и меньше значения переданного в качестве параметра. Это значит, что random(7) вернёт случайное число от 0 до 7. С помощью BGBitmap.Canvas.MoveTo я перемещаюсь в случайную точку внутри BGBitmap и с помощью BGBitmap.Canvas.LineTo рисую из этой точки в новую точку линию. Canvas.Draw(0,0,BGBitmap); выводит моё произведение на экран. Вот и готов простейший хранитель экрана. Надеюсь, что скоро увидимся. Исходники примера находятся в файле Delphi1.zip Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

9


VR-online Journal (Horrific and VR-Team)

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

Реклама в журнале 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.cydsoft.com/vr-online

10


VR-online Journal (Horrific and VR-Team)

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

Delphi (Базы данных): Моментальный поиск Поиск одного поля с помощью SQL запроса или фильтра, просто ужасно глупая затея. Этот поиск будет проходить очень долго. Есть способ лучше - Рондо. Точнее сказать поиск по ключевым полям. Этот поиск происходит практически моментально, даже на больших базах данных. Недостатки - отсутствие шаблонов, не возможно использовать привязанную таблицу. За счёт чего достигается такая скорость поиска? Всё очень просто, за счёт индексации. Так можно искать только по индексированным полям. Ну, хватит лишних слов, давай переходить к делу. Для работы нам понадобиться всё те же таблицы. В качестве исходного текста, можно воспользоваться примером из прошлой статьи и добавить нововведения или скачать готовое в конце сегодняшней статьи. Но я тебе советую начать с нуля. В качестве основы я взял только одну таблицу - User1.db. Как я уже говорил, для быстрого поиска нужно, чтобы поле было проиндексировано, поэтому добавь ещё один вторичный индекс для поля LastName. Теперь у TTable, к которой привязан у тебя User1.db (у меня это Table2), свойство IndexFieldName измени на LastName . Всё таблица готова к употреблению. Если ты корректируешь пример из предыдущей статьи, то на форме у тебя должно быть несколько сеток таблиц (TDBGrid), и в них ты можешь сразу заметить, что у тебя нарушилась связь. Это из-за того, что ты сменил индекс (я уже говорил об этом недостатке в начале статьи). Но у тебя совсем пропали из виду данные таблицы User1.db. Чтобы они снова стали видны, дважды щёлкни по полю MasterFields и в появившемся окне нажми Clear .

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

http://www.cydsoft.com/vr-online

11


VR-online Journal (Horrific and VR-Team)

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

На рисунке 1 показана форма, которую я буду использовать. Как ты можешь увидеть, нам нужны только кнопка, поле ввода и сетка для таблицы User1.db. Всё остальное я убрал, чтобы не мешалось на глазах. Теперь заканчиваем с болтовнёй и пишем код на событие OnClick для кнопки. procedure TForm1.Button1Click(Sender: TObject); begin DataModule2.Table2.SetKey; DataModule2.Table2LastName.AsString:=Edit1.Text; DataModule2.Table2.GotoKey; end; Здесь всё очень просто. Первая строка говорит, что сейчас я буду устанавливать ключ. Вторая строка устанавливает его. Заметь, что это происходит как изменение содержимого поля, но поле не меняется, потому что мы вызвали перед этим SetKey. И, наконец, последняя строка говорит, что надо найти установленный ключ. Всё время мы создавали одиночные вторичные ключи (состоящие из одного поля), но ты можешь с помощью DatabaseDesktop создавать ключи состоящие из любого количества полей. Для этого в DatabaseDesktop , в выпадающем списке Table properties нужно выбрать Secondary Indexes и нажать кнопку Define . Теперь выбери любое поле, и перемести его в список Indexed fields , затем другое поле и снова перемести его в список Indexed fields . И так хоть все поля. Если у тебя установлен ключ из нескольких полей, то ты должен между вызовами SetKey; и GotoKey установить все ключи. Иначе результат может быть ошибкой. Есть ещё одна процедура, с которой я хочу тебя познакомить - GotoNearest . Если GotoKey не находит нужного ключа, то генерируется ошибка. GotoNearest тоже производит поиск ключевого поля, но если поле не найдено, то ошибка не генерируется, а ищется ближайший похожий ключ. Вот мы и покончили с ключевыми полями, но у нас ещё впереди много интересного, так что увидимся в следующем номере. Исходники примера находятся в файле Database.zip Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

12


VR-online Journal (Horrific and VR-Team)

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

Программирование в 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.cydsoft.com/vr-online

13


VR-online Journal (Horrific and VR-Team)

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

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

Рис 1. Пример формы Итак, ты поставил ТListView на форму и у тебя получился компонент ListView1. В нём нужно изменить следующие свойства: • •

Align устанавливаем в alClient . ViewStyle устанавливаем в vsReport .

Теперь нужно создать колонки. Для этого дважды щёлкни по свойству Columns. Перед тобой откроется окно, как на рисунке 2. Внутри этого окошка нужно нажать на саму левую кнопку, которая создаст новую колонку. Одновременно с созданием Delphi выделить новую строку. Перейди в ObjectInspector и поменяй там свойство Caption на "Имя" и свойство Width сделай побольше (я сделал 100). Создай ещё три колонки и назови их "Тип", "Размер" и "Свободно". Надеюсь, что у тебя получилось нечто похожее на рис 1. Если нет, то попробуй прочесть ещё разок. Теперь мы переходим непосредственно к программированию. Сегодня будет очень много кода и очень много объяснений, поэтому приготовь пару бутылок пива, с ними программируется на много лучше.

http://www.cydsoft.com/vr-online

14


VR-online Journal (Horrific and VR-Team)

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

Рис 2. Для начала создадим обработчик события OnShow в нём напишем следующее: procedure TForm1.FormShow(Sender: TObject); var shInfo: TSHFileInfo; NewItem: TListItem; i: Integer; DiskType: Integer; DiskSize, FreeSize: Integer; Drv: Char; drives: set of 0..25; begin Integer(Drives) := GetLogicalDrives; for i := 0 to 25 do if (i in Drives) then begin Drv := Char(i + Ord('A')); NewItem := ListView1.Items.Add; try SHGetFileInfo(PChar(Drv + ':\'), 0, shInfo, SizeOf(shInfo), SHGFI_SYSICONINDEX or SHGFI_DISPLAYNAME or SHGFI_TYPENAME); NewItem.Caption := StrPas(shInfo.szDisplayName); DiskType := GetDriveType(PChar(Drv + ':\')); NewItem.SubItems.Add(GetDriveTypeStr(Drv + ':\')); if (DiskType <> DRIVE_REMOVABLE) and (DiskType <> DRIVE_CDROM) then begin DiskSize := GetDiskSize(Drv + ':\'); FreeSize := GetFreeDiskSize(Drv + ':\'); end else begin DiskSize := 0; FreeSize := 0; end; if DiskSize > 0 then NewItem.SubItems.Add(FormatFloat('###,###,### Mb', DiskSize div 1000)) else NewItem.SubItems.Add('0 Mb'); if FreeSize > 0 then NewItem.SubItems.Add(FormatFloat('###,###,### Mb', FreeSize div 1000)) else NewItem.SubItems.Add('0 Mb'); NewItem.SubItems.Add(''); NewItem.SubItems.Add(Drv + ':\'); NewItem.SubItems.Add('drv'); except ListView1.Items.Delete(NewItem.Index); end; end;

http://www.cydsoft.com/vr-online

15


VR-online Journal (Horrific and VR-Team)

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

Теперь начнём построчно разбираться с написанным здесь, но для начала нужно перейти в раздел Uses и добавить там модуль ShellAPI. Самая первая функция GetLogicalDrives возвращает маску присутствующих в системе дисков. Результат этой функции мы записываем в переменную drives. После этого мы запускаем цикл от 0 до 25 и проверяем, если I-й бит установлен в переменной drives значит устройство с таким номером присутствует: for i := 0 to 25 do // Запускаем цикл if (i in Drives) then //Проверка на присутствие устройства begin //устройство присутствует end; Drv := Char(i + Ord('A')) - эта строка получает букву относящуюся к найденному устройству. Функция Ord возвращает числовое значение ASCII символа. Например, если найдено нулевое устройство, то выполниться условие 0+"числовое значение буквы А", и в переменной Drv окажется числовое значение буквы А. Если найдено устройство с 2, то 2+"числовое значение буквы А" будет равняться числовому значению буквы С, то есть диск С. Почему я узнал, что С=А+2? Да потому, что С третья буква английского алфавита и её код будет на 2 больше чем у А. Это значит, что D=А+3, Е=А+4 и так далее. NewItem := ListView1.Items.Add - добавляем новый элемент в ListView1 и запоминаем ссылку на него в переменной NewItem (это чтобы мы могли изменить параметры нового элемента). SHGetFileInfo позволяет получить информацию о файле или папке: function SHGetFileInfoA( pszPath: PansiChar; dwFileAttributes: DWORD; var psfi: TSHFileInfoA; cbFileInfo, uFlags: UINT ): DWORD; stdcall;

//Путь к файлу или папке //Сюда занесётся информация о файле //Размер предыдущего параметра // флаги указывающие, какая инфа нам нужна.

В нашем случае, первый параметр - PChar(Drv + ':\') указывает на найденное нами устройство. Второй параметр - переменная типа TSHFileInfo. В неё будет занесён результат. С третьим параметром всё ясно, а вот четвуртый - SHGFI_SYSICONINDEX or SHGFI_DISPLAYNAME or SHGFI_TYPENAME говорит о том, что нам нужна иконка для драйва из системы (сегодня мы её не будем использовать), имя используемое для отображения драйва и тип. NewItem.Caption := StrPas(shInfo.szDisplayName) - задаём заголовок для созданного нами элемента в ListView1. Функция StrPas приводит строку формата Windows в понятный для Delphi (и для нас) вид. DiskType := GetDriveType(PChar(Drv + ':\')) - эта функция возвращает тип найденного устройства в виде числа. Есть несколько типов драйвов: • • • • • • •

0 - Не известное устройство. 1 - Отсутствует. DRIVE_REMOVABLE - сменный диск. DRIVE_FIXED - жёсткий диск. DRIVE_REMOTE - сетевой диск. DRIVE_CDROM - CD-ROM. DRIVE_RAMDISK - диск памяти.

http://www.cydsoft.com/vr-online

16


VR-online Journal (Horrific and VR-Team)

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

NewItem.SubItems.Add(GetDriveTypeStr(Drv + ':\')); - добавляем к элементу новую колонку, в которой храниться тип драйва. GetDriveTypeStr - это функция, которая выглядит так (Добавь её к проекту): function TForm1.GetDriveTypeStr(Root: string): string; var DrvType: Integer; begin DrvType := GetDriveType(PChar(Root)); case DrvType of 0: Result := 'Не знаю такова'; 1: Result := 'Отсутствует'; DRIVE_REMOVABLE: Result := 'Съёмный диск'; DRIVE_FIXED: Result := 'Жёсткий'; DRIVE_REMOTE: Result := 'Сетевой'; DRIVE_CDROM: Result := 'CD-ROM'; DRIVE_RAMDISK: Result := 'RAM'; end; end; После этого идёт проверка, если диск не съёмный, то можно узнать его размер и свободное на диске место. Для того, чтобы узнать размер, я написал функцию: function TForm1.GetDiskSize(Root: string): LongInt; var SpC, BpS, NfC, TnC: DWORD; FreeDiskSize: Double; begin GetDiskFreeSpace(PChar(Root), SpC, BpS, NfC, TnC); FreeDiskSize := (TnC * SpC * BpS) / 1024; Result := Round(FreeDiskSize); end; А эта функция для определения свободного места на диске: function TForm1.GetFreeDiskSize(Root: string): LongInt; var SpC, BpS, NfC, TnC: DWORD; FreeDiskSize: Double; begin GetDiskFreeSpace(PChar(Root), SpC, BpS, NfC, TnC); FreeDiskSize := (NfC * SpC * BpS) / 1024; Result := Round(FreeDiskSize); end; Обе эти функции нужно добавить к проекту. Они очень простые и с ними очень легко разобраться, поэтому я не буду останавливать на них особого внимания. Если хочешь увидеть их описание, то загляни в Windows SDK в меню Help . Дальший код тебе уже должен быть понятен. Я добавляю ещё две колонки к созданному элементу, в которых будет храниться размер и свободное место на диске. Запускай программу и любуйся.

http://www.cydsoft.com/vr-online

17


VR-online Journal (Horrific and VR-Team)

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

Рис 3. Результат работы Вроде всё. Не буду больше загружать твою голову, а то так можно и заглючить. Если что-то не получается, то забирай исходники примера и пробуй поиграть с ними. Удачи!!! Исходники находятся в файле delphi2.zip Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

18


VR-online Journal (Horrific and VR-Team)

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

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

http://www.cydsoft.com/vr-online

19


VR-online Journal (Horrific and VR-Team)

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

Delphi (графика): Работа с рабочим столом В сегодняшнем разделе графики я решил познакомить тебя с издевательством над десктопом. Если говорить точнее, мы сегодня научимся на нём рисовать и запоминать его содержимое. Как всегда, я постараюсь всё хорошенечко растолковать и показать. Надеюсь, что тебе понравится сегодняшнее занятие. Для издевательств нам понадобиться форма с двумя кнопками и одной картинкой. Создай новый проект и поставь на него две пимпы TButton и один штука TImage. Приступим? Для первой кнопки напишем в событии OnClick : procedure TForm1.Button1Click(Sender: TObject); var ScreenDC:HDC; begin ScreenDC := GetDC(0); Rectangle(ScreenDC, 10, 10, 200, 200); ReleaseDC(0,ScreenDC); end; С помощью этой процедуры я рисую прямо на десктопе. Во время рисования, мне насрать на все запущенные приложения. Если они попадаются под руку, то рисование происходит поверх них. Теперь о содержимом. Я объявляю переменную ScreenDC типа HDC. HDC - это контекст рисования в windows, и работает почти так же, как и TCanvas (чуть позже ты увидешь связь). С помощью функции GetDC(0) я возвращаю контекст окна указанного в скобках. Но в этих скобках стоит 0 (ноль), а это значит, что мне нужен глобальный контекст, то есть самого десктопа. Далее, я вызываю функцию Rectangle, она похожа на ту, что мы использовали раньше TCanvas.Rectangle. Есть только одно отличие - первый параметр теперь, это контекст устройства, а затем идут координаты прямоугольника. Это связано с тем, что раньше мы рисовали через объект TCanvas, а сейчас будем рисовать средствами GDI Windows. Скажу по секрету :) TCanvas.Rectangle всего лишь вызывает Rectangle из Windows API и подставляет нужный контекст устройства и размеры. Сейчас мы сами сделаем это, без помощь TCanvas. После рисования, я освобождаю больше не нужный мне контекст через функцию ReleaseDC. Такие вещи обязательно надо освобождать, чтобы не засорять память. Если ты захочешь рисовать не на десктопе, а внутри определённого окна, то в этой процедуре нужно поправить только первую строчку. А именно, в качестве параметра GetDC передавать указатель на окно. Сразу возникает вопрос: "Как узнать указатель окна чужой проги?". Для этого можно воспользоваться функцией FindWindow (с ней мы уже знакомились в предыдущих номерах). Сейчас можно запустить прогу и посмотреть на результат, а мы я пока перейду ко второй пимпе. Для неё мы напишем следующий текст:

http://www.cydsoft.com/vr-online

20


VR-online Journal (Horrific and VR-Team)

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

procedure TForm1.Button2Click(Sender: TObject); var Canvas:TCanvas; ScreenDC:HDC; begin ScreenDC := GetDC(0); Canvas:=TCanvas.Create(); Canvas.Handle:=ScreenDC; Image1.Canvas.Copyrect(Rect(0,0,Image1.Width,Image1.Height), Canvas, Rect(0,0,Screen.Width,Screen.Height)); ReleaseDC(0,ScreenDC); Canvas.Free; end; Сразу скажу, что здесь я получаю копию десктопа. Первая строка такая же, как и в предыдущей процедуре. Я точно также получаю контекст десктопа. Потом я создаю новую переменную Canvas типа ТCanvas (знакомый нам контекст рисования). Потом я связываю их между собой с помощью простого присваивания в Canvas.Handle:=ScreenDC. Теперь мой TCanvas указывает на декстоп, и я могу рисовать на нём, привычными нам методами. Далее, я получаю копию экрана и записываю её в картинку TImage с помощью функции Copyrect у контекста рисования картинки (Image1.Canvas.Copyrect). Эта функция выглядит так: procedure CopyRect( Dest: TRect; //Размеры получаемого изображения Canvas: TCanvas;//Контекст, из которого будет копироваться Source: TRect//Размеры исходного изображения ); CopyRect производит копирование изображения и одновременное масштабирование из размеров Source в Dest. В качестве первого параметра идут размеры получаемого изображения. Размеры передаются в виде переменной типа TRect. TRect - это простая запись, которая содержит четыре параметра: TRect = record Left, Top, Right, Bottom: Integer; end; С этим типом мы ещё не знакомы. Если хорошенько рассмотреть, то можно заметить сходство с объявлением объектов. Это так. Записи - это маленькие объекты, но не имеющие методов (процедур и функций), а только параметры любого типа. Все параметры общедоступны и внутри записи нельзя использовать директивы private, protected или public. Для получения такого типа и использую функцию Rect которая создаёт TRect. В качестве параметров выступают соответствующие размеры Rect(0, 0, Image1.Width, Image1.Height). Второй параметр - контекст рисования Canvas, который у нас ассоциирован с контекстом десктопа. Из него и будет происходить копирование. Третий параметр - размеры исходного изображения.

http://www.cydsoft.com/vr-online

21


VR-online Journal (Horrific and VR-Team)

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

И в самом конце, я освобождаю контекст рисования десктопа ReleaseDC(0,ScreenDC); и Canvas.Free. Запусти прогу и посмотри на результат. Если что-то ещё осталось непонятным, то после этого всё станет на свои места. Попробуй поиграть с этой прогой, это поможет тебе получше вникнуть во всё происходящее в ней. А я прощаюсь до следующего номера. Удачи!!! Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

22


VR-online Journal (Horrific and VR-Team)

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

DirectX: Первый 3D До сих пор мы работали только с плоскими фигурами DirectDraw. Сегодня мы познакомимся с Direct3D, который позволяет строить трёхмерные сцены, которые мы уже умеем делать с помощью OpenGL. Хотя сцену мы не построим, а загрузим из файла. И самое главное, наше приложение будет оконным, а не полноэкранным, как это было в прошлых статьях. Работа с оконным DirectX отличается от полноэкранного и достаточно сильно.

Рис 1. Пример формы Сразу же приготовься и забери исходники сегодняшнего примера в файле dx.zip. А теперь приступим к рассмотрению функции FormCreate. Procedure Tform1.FormCreate(Sender: Tobject); var hr: Hresult; begin Application.OnIdle:=IdleEvent; hr:=Direct3DRMCreate(Fdirect3D); if hr<>D3DRM_OK then ShowMessage(‘Direct3DRMCreate failed’); CreateDevice; end; Direct3DRMCreate – создаёт объект типа Idirect3DRM, с которым будет происходить вся сегодняшняя работа. Этот объект умеет работать с трехмерными объектами, освещением и текстурами, что и предстоит нам сегодня изучить. Далее вызываеться процедура CreateDevice, которая иницаализирует DirectDraw:

http://www.cydsoft.com/vr-online

23


VR-online Journal (Horrific and VR-Team)

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

procedure Tform1.CreateDevice; var hr : Hresult; Bpp : Integer; begin hr:=DirectDrawCreateClipper(0, FD3Dclipper, nil); if(hr<>D3DRM_OK) then ShowMessage(‘DirectDrawCreateClipper failed’); FD3Dclipper.SetHWnd(0, Handle); hr:=Fdirect3D.CreateDeviceFromClipper(FD3Dclipper, nil, ClientWidth, ClientHeight, FD3Device); if(hr<>D3DRM_OK) then ShowMessage(‘CreateDeviceFromClipper failed’); FD3Device.SetQuality(D3DRMRENDER_GOURAUD); bpp:=GetDeviceCaps(Canvas.Handle, BITSPIXEL); case (bpp) of 8: FD3Device.SetDither(false); 16: begin FD3Device.SetShades(32); Fdirect3D.SetDefaultTextureColors(64); Fdirect3D.SetDefaultTextureShades(32); FD3Device.SetDither(false); end; 24, 32: begin FD3Device.SetShades(256); Fdirect3D.SetDefaultTextureColors(64); Fdirect3D.SetDefaultTextureShades(256); FD3Device.SetDither(false); end; end; hr:=Fdirect3D.CreateFrame(nil, FD3Dscene); if(hr<>D3DRM_OK) then ShowMessage(‘CreateFrame failed’); CreateScene; end; Сегодняшнее приложение я сделаю оконным. Когда ты рограммируешь обычными средствами Windows, то он сам следит за тем, что попадает в окно, а что нет. Если какая-то точка не попадет в область вывода, то Windows самостоятельно отсекает её. В случае работы с DirectDraw, этого не происходит. Ты сам должен следить за всем, что происходит в окне, отсекая ненужное. Но есть способ лучше, в DirectDraw есть встроенный объект, который может сделать за тебя эту рутинную работу – объект отсечения. Чтобы он начал работать, ты должен его инициализировать. DirectDrawCreateClipper создаёт объект отсечения, который будет отсекать всё, что не попадает в область вывода. Первый параметр – должен быть 0. Второй – указатель на объект типа IdirectDrawClipper, который будет проинициализирован и использоваться для отсечения. Третий – не используется и должен быть nil. FD3Dclipper.SetHWnd – устанавливает объекту отсечения окно, за которым он будет следить и отсекать всё, что в него не попадает. CreateDeviceFromClipper – привязывает нашему объекту сцены, который мы создали в процедуре FormCreate, объект отсечения. Первый параметр – ссылка на объект отсечения. Второй – глобальный идентификатор (можно использовать nil). Третий и

http://www.cydsoft.com/vr-online

24


VR-online Journal (Horrific and VR-Team)

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

четвёртый – ширина и высота окна. Последний – указатель типа Idirect3DRMDevice, который будет проинициализирован с указанными новыми возможностями. SetQuality – устанавливает качество отображения сцены. В качестве параметра указывается константа, которая может быть: • • •

D3DRMRENDER_GOURAUD – для отображения использовать метод какого-то Гуро. D3DRMRENDER_FLAT – метод сглаживания. D3DRMRENDER_WIREFRAME – рисовать линиями. Объекты получаться как из проволок.

GetDeviceCaps – это функция из WinAPI и не относится к DirectX, но я её распишу. Она возвращает текущие свойства контекста рисования. Первый параметр – указатель на контекст экрана. Второй – константа, которая указывает, какой параметр нам нужен. Мне нужно установленное с системе количество бит на пиксел. Остальные константы смотри в документации по WinAPI. Далее, в зависимости от количества бит на пиксел, я использую разную инициализацию. SetDither – устанавливает сглаживание. Если в качестве параметра будет true, то при рисовании будет происходить сглаживание сцены, иначе изображение получается немного грубым. SetShades – устанавливает количество оттенков цветов. SetDefaultTextureColors – устанавливает значение по умолчанию для количества цветов текстуры. SetDefaultTextureShades – устанавливает значение по умолчанию для количества оттенков текстуры. CreateFrame – создаёт новый слой для родительского. Первый параметр – указатель на родительский слой. Если он отсутствует, то инициализируется слой со значениями по умолчанию. Второй параметр – укачатель на объект типа Idirect3DRMFrame, который будет создан. В самом конце я вызываю функцию CreateScene, которая производит дальнейшую инициализацию: procedure Tform1.CreateScene; var D3DambientLight : Idirect3DRMLight; D3DambientLightFrame : Idirect3DRMFrame; begin if not (LoadScene()) then Exit; FD3DTextureWrapType:=D3DRMWRAP_FLAT; if not (LoadWrapTexture()) then Exit; FDirect3D.CreateLightRGB(D3DRMLIGHT_AMBIENT, 1, 1, 1, D3DAmbientLight); FDirect3D.CreateFrame(FD3DScene, D3DAmbientLightFrame); D3DAmbientLightFrame.AddLight(D3DAmbientLight); D3DAmbientLightFrame:=nil; D3DAmbientLight:=nil;

http://www.cydsoft.com/vr-online

25


VR-online Journal (Horrific and VR-Team)

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

FDirect3D.CreateFrame(FD3DScene, FD3DCamera); FD3DCamera.SetPosition(FD3DScene, 0, 0, -50); FDirect3D.CreateViewport(FD3Device, FD3DCamera,0, 0, FD3Device.GetWidth(), FD3Device.GetHeight(), FD3DViewPort); Flat2Click(nil); FD3DScene.SetSceneBackgroundRGB(0, 0, 1); end; LoadScene - моя фунция, которая загружает сцену. Эту функцию мы рассмотрим через месяц. FD3DTextureWrapType - устанавливает тип текстуры. D3DRMWRAP_FLAT - означает, что текстура должна быть сглаженная. LoadWrapTexture - моя процедура, которая загружает текстуру. Её мы также рассмотрим в следующий раз. Если сможешь, попробуй разобраться сам, она есть в примере. CreateLightRGB - создаём освещение. Первый параметр - тип. D3DRMLIGHT_AMBIENT означает, что нам нужно рассеянное освещение. Следующие три параметра интенсивности красного, зелёного и синего, которые вместе означают цвет освещения. Последний параметр - указатель на объект типа IDirect3DRMLight, это источник света, который будет создан. Далее мы создаём новый кадр с помощью CreateFrame. Новый кадр будет дочерним к уже созданному FD3DScene. AddLight - добавляет источник освещения к нашей сцене. Далее мы создаём камеру. Для этого создаём новый дочерний кадр с помощью CreateFrame и устанавливаем позицию наблюдателя SetPosition, что создаёт эффект камеры. SetPosition - устанавливает позицию наблюдателя. Первый параметр - указатель на сцену, в которой надо установить позицию. Следующие три параметра - позиции по оси X,Y и Z. CreateViewport - устанавливает область просмотра. Первый параметр - указатель на устройство. Второй - указатель на камеру. Следующие четыре параметра - левая, правая позиции и ширина и высота области просмотра. Последний параметр указатель на объект типа IDirect3DRMViewport, который будет проинициализирован с новыми параметрами. SetSceneBackgroundRGB - устанавливает цвет фона. В качестве параметров идут интенсивности красного, зелёного и синего. Интенсивность изменяется от 0 до 1, как и в OpenGL. На сегодня хватит. Я продолжу рассматривать этот пример через месяц. А пока попробуй поиграть с примером сам. Может до чего-нибудь дойдёшь без моей помощи. Исходники находятся в файле dx.zip Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

26


VR-online Journal (Horrific and VR-Team)

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

Java: Занятие второе Сегодня мы продолжим знакомится с Java. В прошлый раз я рассказал только об основах, но сегодня мы напишем более рабочий и интересный пример. Для этого нам понадобиться немного мозгов и нормально заточенные руки. Занятие будет короткое, но полезное. Прежде чем начать я отвечу на один часто задаваемый мне вопрос: "Как компилировать созданный на Java код". Отвечаю: я для этого использую JBuilder, но ты можешь воспользоваться любым компилятором, хоть голым Java. Если ты выбрал Jbuilder, то просто открывай написанный мною файл и компилируй его. Для этого в левом верхнем окошке щёлкни правой кнопкой по имени файла и выбери "Rebuild". Если решил использовать голый java, то надо набрать в командной строке javac имя_файла . Теперь перейдём к рассмотрению нашего примера. В принципе я добавил не многое, но результат выглядит не плохо. import java.applet.*;

import java.awt.*; public class HelloWorld extends Applet { final Font f = new Font("Courier", Font.BOLD, 18); public void paint(Graphics g) { Color col; Dimension d = size(); col = new Color(0, 255, 255); g.setColor(Color.white); g.fillRect(0,0,d.width,d.height); col = new Color(0, 128, 128); g.setColor(col); drawCenteredString("VR on-line", d.width, d.height, g); g.drawRect(0,0,d.width-1,d.height-1); } public void drawCenteredString(String s, int w, int h, Graphics g) { FontMetrics fm = g.getFontMetrics(); int x = (w - fm.stringWidth(s)) / 2; int y = (fm.getAscent() + (h - (fm.getAscent() + fm.getDescent()))/2); g.drawString(s, x, y); } } Теперь рассмотрим, что у нас здесь происходит. Color col - это я объявляю переменную col типа Color (цвет). Дальше я создаю этот цвет с помощью col = new Color(0, 255, 255); Так создаётся цвет со значениями указанными в скобках. Теперь для прапорщиков: переменной col присваивается значение новый Цвет (0, 255, 255). Нечто подобное можно встретить и в С/С++ и в Delphi. Поэтому эта конструкция должна быть тебе понятна. Если нет, то посмотри на неё ещё разок. Если опять ничего не понятно, то включи лампочку, ты сидишь в темноте и ничего не видишь.

http://www.cydsoft.com/vr-online

27


VR-online Journal (Horrific and VR-Team)

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

g.setColor(Color.white) - выбираю созданный цвет для рисования на аплете. g.fillRect(0,0,d.width,d.height) - заливаю поле аплета выделенным цветом (в скобачках указаны размеры аплета). После этого я снова создаю новый цвет и устанавливаю его. Далее вызываеться процедура drawCenteredString, которая написана мною ниже и g.drawRect, которая рисует прямоугольник (оборка для моего аплета). С процедурой main всё понятно, но осталась только одна непонятная процедура drawCenteredString. В неё я вынес рисование текста. Давай разберём и её. FontMetrics fm = g.getFontMetrics() - возвращает системные метрики, с помощью которых мы определяем ширину выводимого текста fm.stringWidth(текст). Дальше идут две строки чистой математики. Последняя строка выводит текст по рассчитанным координатам g.drawstring(текст, координата Х, координата У). Вот и всё, ничего сложного тут нет. Если ты закончил хотя бы 5 классов и посещал математику, то особых проблем не будет, а ели ты знаешь один из языков программирования (С/С++ или Delphi), то вообще грех жаловаться. На сегодня всё. Тише едешь дальше будешь. Если что не понятно, то попробуй поиграть с изменением различных чисел и всё само прейдёт. Исходники находятся в файле java.zip Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

28


VR-online Journal (Horrific and VR-Team)

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

SQL: Занятие третье Продолжаем изучать язык запросов SQL. На прошлом занятии мы покончили с булевыми операторами. Сегодня мы познакомимся ещё с несколькими операторами, упрощающими и усиливающими поиск необходимой информации. Сегодня это будут операторы IN, BETWEEN, IS NULL. А также , мы познакомимся с шаблонами. Начну я с оператора IN. В принципе, можно создавать запросы и без него, но он упрощает SQL код и делает его более наглядным. Сразу рассмотрим пример: SELECT * FROM User WHERE Сountry LIKE "USA" or Сountry LIKE "RUSSIA" or Сountry LIKE "GERMANY"; Этот запрос вполне работающий, но представь, что тебе так надо перечислить 20 или более стран. В этом случае запрос раздуется как земной шар. Вот как этот же запрос будет выглядеть с оператором IN. SELECT * FROM User WHERE Сountry IN ("USA", "RUSSIA", "GERMANY"); Намного проще и меньше места. Если внимательно осмотреть два предыдущих запроса, то можно и без моих объяснений понять, что делает оператор IN. В данном случае он выведет все записи, в которых Counrty имеет одно из значений указанных в скобках. Если используется числовое поле, то кавычки надо убрать: SELECT * FROM User WHERE LecNumber IN (1, 2, 3) В этом случае мы увидим все записи, где поле LecNumber равно 1 или 2 или 3. Вместе с оператором IN и со всеми последующими операторами ты можешь смело использовать булевы операторы, например: SELECT * FROM User WHERE LecNumber NOT IN (1, 2, 3) Теперь перейдём к рассмотрению оператора BETWEEN. Он также нужен только для удобства и вы можете спокойно обойтись без него. Снова перейдём к примеру. Допустим, что надо вывести все строки, где поле LecNumber больше либо равно 1 и меньше либо равно 5. Этот запрос будет выглядеть так: SELECT * FROM User WHERE LecNumber >= 1 AND LecNumber <= 5

http://www.cydsoft.com/vr-online

29


VR-online Journal (Horrific and VR-Team)

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

С оператором BETWEEN та же запись будет выглядеть так: SELECT * FROM User WHERE LecNumber BETWEEN 1 AND 5 Как ты уже понял, этот оператор задаёт диапазон чисел. Ты должен помнить, что конечные точки включаются в результат запроса. Этот оператор можно использовать и с строковыми полями: SELECT * FROM User WHERE Сountry BETWEEN "A" AND "R"; В результат этого запроса войдут такие страны как GERMANY, AUSTRY, но не войдёт RUSSIA. Почему? Да потому что "GERMANY" меньше чем "R", а "RUSSIA" больше, потому что в слове "Russia" больше букв. Оператор IS NULL означает нулевое значение. Сразу отмечу, что нулевое значение не равно 0 или "" (пустой строке). Ноль - это ноль, то есть не заполненное значение. В принципе, этот оператор прост, да и не очень важен, потому что ты очень редко будешь с ним работать. Поэтому я просто приведу пример и мы пойдём дальше: SELECT * FROM User WHERE Сountry IS NULL; Теперь рассмотрим ещё два оператора - % (процент) и _ (подчёркивание). Точнее сказать это не операторы, это управляющие символы используемые в шаблонах. Короче, ты их будешь использовать вместе с оператором LIKE. Представь, что тебе нужно вывести все записи, которые в поле Country содержат значение начинающееся на "R". Твой запрос будет выглядеть так: SELECT * FROM User WHERE Сountry LIKE "R%"; Значок % (процент) означает любое количество символов, т.е. в результат войдут все слова начинающиеся на R и содержащие потом любое количество любых символов. Рассмотрим ещё пример: "А%С". В результат такого шаблона войдут слова: ананас, атас и другие, главное, чтобы они начинались на "А" и заканчивались на "С". Теперь познакомимся с _ (подчёркивание) - оно означает один любой символ. Если % означал любое количество символов, то _ означает только один. Рассмотрим пример: "Т_К". В результат такого шаблона войдут слова: ТОК, ТУК, ТИК, но не войдёт ТУПИК и другие слова, содержащие между буквами Т и К больше чем одну букву. Этот символ очень удобен, особенно для тех, кто прекрасно знает русский язык. Представь, что тебе надо найти слово "корова", а ты не знаешь, как писать "корова" или "карова". В этом случае просто пиши "к_рова" и ты не ошибёшься. Или вообще "к_р%". Красиво? А в принципе, это то же самое. Вот если бы в школе диктанты можно было бы так писать :). Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

30


VR-online Journal (Horrific and VR-Team)

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

SQL: Работа с несколькими таблицами С одной таблицей мы научились работать. Теперь пора научиться связывать несколько таблиц, как мы это уже делали на уроках программирования Delphi и базы данных. Помимо этого, нас ждёт несколько приёмов, украшающих вывод. Ещё на первом занятии я нарисовал схему из трёх баз данных. Если ты забыл, то взгляни на рисунок 1, чтобы освежить ту схему в своей оперативной памяти.

Рис 1. Связь между таблицами. До сегодняшнего дня, мы обращались только к одной таблице. Сейчас мы выведем сразу две, причём с учётом связи. Сначала я покажу пример, а потом мы рассмотрим всё построчно. SELECT * FROM Prog, User WHERE Prog.Key1=User.Key2 Первая строка, как всегда говорит, что надо вывести все поля (SELECT *). Вторая строка говорит, из каких баз данных надо это сделать (FROM Prog, User). На этот раз у нас здесь указано сразу две базы. Третья строка показывает связь (Prog.Key1=User.Key2). Для того, чтобы указать к какой базе относиться ключ Key1, я записываю полное имя поля как ИмяБазы.ИмяПоля. Если имя поля уникально для обеих таблиц (как Key1, которое есть только в таблице User), то можно имя таблицы опускать. Например, запрос мог выглядеть так: SELECT * FROM Prog, User WHERE Prog.Key1= Key2

http://www.cydsoft.com/vr-online

31


VR-online Journal (Horrific and VR-Team)

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

А вот Key1 записать без имени таблицы нельзя, потому что такое имя поля есть в обеих таблицах. Поэтому необходимо явно указать, Key1 какой именно таблицы интересует нас. Представим, что у нас есть две таблицы: Prog.db Key1 ProgName Cost -----------------------------------1 Windows 95 100 2 Windows 98 120 User.db Key1 Key2 LastName --------------------------------1 1 Иванов 2 1 Петров 3 2 Сидоров Тогда результатом такого запроса может быть: Prog.db User.db Key1 ProgName Cost Key1 Key2 LastName -----------------------------------------------------1 Windows 95 100 1 1 Иванов 1 Windows 95 100 2 1 Петров 2 Windows 98 120 3 2 Сидоров Рассмотрим ещё пример: SELECT * FROM Prog, User WHERE Prog.Key1= Key2 AND ProgName LIKE 'Windows 95' Результатом этого запроса, при тех же таблицах будет: Prog.db User.db Key1 ProgName Cost Key1 Key2 LastName ---------------------------------------------------------------------------1 Windows 95 100 1 1 Иванов 1 Windows 95 100 2 1 Петров Как видишь, всё очень просто. Ты можешь использовать с такими запросами всё, что мы уже изучали и практически всё, что ещё изучим. Давай теперь приукрасим наши запросы. Например, представим, что цена указана в долларах :), а мы хотим перевести в рубли. Корректируем немного запрос: SELECT Prog.Key1, Prog.ProgName, Prog.Cost*2, Cost.Key1, Cost.Key2, Cost.LastName FROM Prog, User WHERE Prog.Key1= Key2 Под цифрой 2 внутри запроса (Prog.Cost*2) я подразумеваю курс доллара (размечтался я). Результат запроса будет: Prog.db Key1 ProgName

User.db Cost Key1 Key2 LastName

http://www.cydsoft.com/vr-online

32


VR-online Journal (Horrific and VR-Team)

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

---------------------------------------------------------------------------1 Windows 95 200 1 1 Иванов 1 Windows 95 200 2 1 Петров Давай ещё немного украсим: SELECT Prog.Key1, Prog.ProgName, Prog.Cost*2 'руб', Cost.Key1, Cost.Key2, Cost.LastName FROM Prog, User WHERE Prog.Key1= Key2 Prog.Cost*2 'руб' - эта запись говорит, что к каждому значению полю надо прибавить строку 'руб'. Результат этого запроса: Prog.db User.db Key1 ProgName Cost Key1 Key2 LastName ------------------------------------------------------1 Windows 95 200 руб 1 1 Иванов 1 Windows 95 200 руб 2 1 Петров Здесь есть маленький недостаток, приходиться перечислять поля, которые нужно вывести и * уже не работает. Так что если понадобиться вывести все поля, то придётся их все писать после команды SELECT. Вот стало и ещё красивее. Теперь остаётся мне выполнить обещание, и показать, как сортируется вывод. Для сортировки используется команда ORDER BY . После этого пишутся поля, по которым надо отсортировать. В самом конце нужно поставить АSC (сортировать в порядке возрастания) или DESC (в порядке убывания). Если ты не ставишь АSC или DESC , то таблица сортируется по возрастанию и подразумевается параметр АSC . Например: SELECT * FROM Prog ORDER BY ProgName Результатом будет таблица Prog, отсортированная по полю ProgNamе в порядке возрастания . Если ты хочешь отсортировать в обратном порядке, то нужно обязательно поставить DESC : SELECT * FROM Prog ORDER BY ProgName DESC Связанные таблицы сортируются также: SELECT * FROM Prog, User WHERE Prog.Key1= Key2 ORDER BY ProgName, Country ASK Copyright © Фленов Михаил aka Horrific

http://www.cydsoft.com/vr-online

33


VR-online Journal (Horrific and VR-Team)

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

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

Рис 1. Примитивы Давай рассмотрим каждый примитив поподробнее, но для начала взглянём на новую процедуру:

http://www.cydsoft.com/vr-online

34


VR-online Journal (Horrific and VR-Team)

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

glLineWidth(5); Не надо много ума, чтобы догадаться, что эта процедура задаёт толщину линии. Она влияет только на рисование линий, на квадраты и треугольники она не влияет. Теперь рассмотрим первый примитив из двух линий: glBegin(GL_LINES); glColor3f (0.0, 1.0, 0.0); glVertex3f(-2.7,1.7,0); glVertex3f(-2.7,1,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(-2.3,1.7,0); glVertex3f(-2.3,1,0); glEnd; glBegin с параметром GL_LINES открывает набор линий. Я здесь рисую две параллельные линии разного цвета, а ты можешь нарисовать одну или даже 10. Между glBegin(GL_LINES); и glEnd должно быть чётное количество вершин. Если будет нечётное, то последняя будет просто отбрасываться и не повлияет на сцену. glBegin(GL_LINE_STRIP); glColor3f (0.0, 1.0, 0.0); glVertex3f(-1,1.7,0); glVertex3f(-1,1,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(-0.5,1.7,0); glVertex3f(-0.5,1,0); glEnd; glBegin с параметром GL_LINE_STRIP открывает набор линий с продолжением. Это значит, что конец первой линии будет являться началом второй, а конец второй, будет являться началом третей. Здесь может быть любое количество вершин. Почему? Подумай немного и ты поймёшь. glBegin(GL_LINE_LOOP); glColor3f (0.0, 1.0, 0.0); glVertex3f(0.5,1.7,0); glVertex3f(0.5,1,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(1,1.7,0); glVertex3f(1,1,0); glEnd; glBegin с параметром GL_LINE_LOOP открывает набор замкнутых линий. Этот примитив очень похож на предыдущий с одной только разницей - последняя вершина замкнётся с первой. теперь перейдём к треугольникам. Для наглядности смотри на примитивы расположенные на рисунке в центре. glBegin(GL_TRIANGLES); glColor3f (0.0, 1.0, 0.0); glVertex3f(-2.7,0.7,0); glVertex3f(-2.7,0.0,0); glVertex3f(-2.5,0.4,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(-2.3,0.7,0);

http://www.cydsoft.com/vr-online

35


VR-online Journal (Horrific and VR-Team)

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

glVertex3f(-2.3,0.0,0); glVertex3f(-2.1,0.4,0); glEnd; glBegin с параметром GL_TRIANGLES рисует треугольники. Количество вершин должно быть кратное трём, лишние вершины отбрасываются. glBegin(GL_TRIANGLE_STRIP); glColor3f (0.0, 1.0, 0.0); glVertex3f(-0.7,0.7,0); glVertex3f(-0.7,0.0,0); glVertex3f(-0.5,0.4,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(-0.3,0.7,0); glVertex3f(-0.3,0.0,0); glVertex3f(-0.1,0.4,0); glEnd; glBegin с параметром GL_TRIANGLES_STRIP рисует треугольники с замкнутыми вершинами. Последняя вершина первого треугольника является первой вершиной второго треугольника. glBegin(GL_TRIANGLE_FAN); glColor3f (0.0, 1.0, 0.0); glVertex3f(1.3,0.7,0); glVertex3f(1.3,0.0,0); glVertex3f(1.5,0.4,0); glColor3f (0.0, 0.0, 1.0); glVertex3f(1.7,0.7,0); glVertex3f(1.7,0.0,0); glVertex3f(1.9,0.4,0); glEnd; glBegin с параметром GL_TRIANGLE_FAN рисует треугольники с замкнутыми гранями. Последняя грань первого треугольника является первой гранью второго треугольника. Количество вершин может быть любым (не меньше трёх), потому что последняя грань хранит в себе уже две точки, и прибавив ещё одну получается новый треугольник. Теперь мы переходим к квадратам. Здесь я буду писать сокращённо для экономии места. Ты и так уже должен всё хватать на лету. glBegin(GL_QUADS); Рисует квадраты. Количество вершин должно быть кратно 4-м. glBegin(GL_QUAD_STRIP); Рисует квадраты с общей гранью. Последняя грань первого квадрата является первой для второго. Количество вершин должно быть больше или равно 4-м и кратно 2-м. glBegin(GL_POLYGON); Рисует полигон. Это просто набор вершин объединённых между собой. Честно сказать, я не знал какой лучше пример привести. Мой пример не очень удачный, но попробуй сам поиграть с вершинами, подвигай их в разные стороны и посмотри на результат.

http://www.cydsoft.com/vr-online

36


VR-online Journal (Horrific and VR-Team)

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

Вот и всё. Вначале мне казалось, что статья раздуется на десяток страниц, а оказалось всё не так уж и страшно. Теперь тебе не трудно будет нарисовать достаточно сложную сцену. Самое главное, чтобы хватило воображения. Исходники примера можете взять в файле opengl.zip. Заголовочные файлы ты можешь найти на нашем сайте в разделе Download.

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

http://www.cydsoft.com/vr-online

37


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