Отображение графических объектов в Microsoft Windows производится посредством интерфейса
графических устройств (graphics device interface, GDI). Он представлйет собой
аппаратно-независимую модель вывода графики, которая обрабатывает вызовы графических
функций из Windows-приложений и передает их соответствующему драйверу устройства.
Последний выполняет специфические для устройства операции, которые и осуществляют
вывод. Работая как буфер между приложениями и устройствами вывода, GDI представляется
приложению как нечто независящее от самого устройства, но учитывающее формат
устройства при выводе.
Разработчики
приложений используют функциональные средства GDI для отображения и отрисовки
элементов управления, фигур и текста, а также для создания и применения перьев,
кистей и шрифтов. Объект Graphics из WFC вместе с другими объектами WFC — Pen,
Font и Brush — инкапсулирует эти средства в качестве объектов Java. В среде
WFC графический вывод производится через объект Graphics. После создания или
получения объекта Graphics Вы связываете с ним другие графические объекты —
шрифты, перья и кисти — и, используя присущие им методы рисования, строите изображение
на дисплее. Например, для изображения произвольных линий используется метод
set-Pen объекта Graphics для установки пера, которое применяется объектом для
рисования, а затем используется метод drawLine этого же объекта для проведения
линий. Подобные связи объектов можно менять сколь угодно часто.
WFC предоставляет
несколько способов создания объекта Graphics. Явное создание объекта. Объект
Graphics создается явно путем вызова метода createGraphics для любого объекта,
который расширяет класс Control.
Неявное
создание объекта. Объекты Bitmap и Metafile поддерживают неявное создание
объекта Graphics при помощи метода getGraphics.
Явное
создание объекта Graphics
Все классы,
расширяющие класс Control, поддерживают метод createGraphics, который можно
использовать для создания экземпляра объекта Graphics. Следующий фрагмент кода
демонстрирует, как вызвать этот метод изнутри класса, производного от Form:
Graphics g =
this.createGraphics();
Второй подход
для явного создания объекта Graphics предполагает использование описателя контекста
устройства Win32 (HDC). Вообще говоря, единственным случаем создания объекта
Graphics этим способом является вызов метода Win32, который возвращает HDC.
Если Вам просто нужны графические возможности, которые не поддерживаются явно
в объекте Graphics, примените метод объекта getHandle для получения описателя
контекста устройства Win32 и затем передайте этот описатель в соответствующий
метод Win32. Если Вы создаете объект Graphics на основе ранее существовавшего
описателя, то объект Graphics не становится владельцем описателя, и после использования
объекта Вы ответственны за освобождение описателя с помощью соответствующей
функции Win32. Если Ви применяете метод getHandle объекта Graphics для получения
базисного описателя объекта, то объект остается владельцем этого описателя,
и Вы не должны пытаться освободить его.
Дополнительная
информация об описателях Win32 и объекте Graphics приведена далее в этой главе
в разделе «Выполнение операций с описателями».
Неявное
создание объекта Graphics
Объекты Bitmap
и Metafile поддерживают неявное создание объекта Graphics при помощи их метода
getGraphics. В следующем фрагменте кода метод getGraphics объекта Bitmap используется
для создания объекта Graphics, который применяют для отрисовки растрового изображения:
Bitmap bmp = new Bitmap(«
c:\\MyImage. bmp»);
Graphics gr =
bmp. getGraphics();
При первым
вызове getGraphics объект создает новый экземпляр объекта Graphics и возвращает
его. Последующие вызовы getGraphics для того же объекта приводят к возврату
объекта, созданного при первом вызове.
Кроме того,
когда методы рисования вызываются посредством объекта Graphics, созданного методом
getGraphics какого-то объекта, они применяются к объекту, посредством которого
они были созданы. Например, XY-координаты (0,0), заданные ранее в обращении
к drawText, измеряются относительно объекта «растр», а не относительно
элемента управления, на котором находитется» растр.
Внутри события
отрисовки (paint event) формы или элемента управления можно получить и использовать
экземпляр объекта Graphics. Обработчик этого события получает в качестве параметра
объект Paint-Event, который имеет открытый член graphics, являющийся экземпляр
объекта Graphics. Его вызывают следующим образом:
protected void onPaint(PaintEvent е)
{
е.graphics.drawString(«Hello, World», new Point(10, 10));
}
Подробности
о создании объекта Graphics вне события отрисовки см. в предыдущих разделах
«Явное создание объекта Graphics» и «Неявное создание объекта
Graphics».
Область
видимости объекта Graphics
Объект Graphics
имеет область видимости метода (method scope). Это означает, что при
возврате из метода, в котором использовался объект Graphics, автоматически вызывается
метод dispose этого объекта, освобождая все ресурсы, выделенные объекту. После
вызова dispose попытки использования объекта сгенерируют исключительную ситуацию
времени выполнения.
Если Вы объявили экземпляр объекта Graphics на уровне класса, то необходимо использовать метод createGraphics объекта Form для инициализации такого объекта в каждом методе, который его использует:
Public class
Forml extends Form{
Graphics g =
new Graphics();
Private void Form1_resize(0bject sender, Event e){
// Инициализировать экземпляр объекта,
g = this.createGraphics();
// dispose вызывается
автоматически...
}
private void Form1_click(0bject sender, Event e){
// Инициализировать экземпляр объекта, g = this.createGraphics();
// Метод dispose
вызывается автоматически...
}
}
Хотя метод
dispose вызывается автоматически, лучше вызывать его явно в конце процедур,
использующих объект Graphics. Это особенно важно на платформе Windows, потому что имеется системное ограничение на количество выделяемых контекстов устройств.
Управление
ограничивающим прямоугольником
Область окна,
в которой можно производить отрисовку, называется клиентской областью (client
area) окна. Внутри этой области ограничивающий прямоугольник (bounding
rectangle) определяет невидимую прямоугольную область, где объект Graphics производит
отрисовку и которая может включать в себя всю клиентскую область окна. Когда
окно теряет и затем снова получает фокус ввода, часть ограничивающего прямоугольника,
ранее покрытая другим объектом, не перерисовывает автоматически элементы, которые
были на ней. Чтобы гарантировать правильность отображения, нужно управлять перерисовкой
формы или элемента управления. Обработчик события отрисовки является тем самым
местом в коде класса Form, где обычно и размещается такое управление. Внутри
обработчика восстанавливается правильное состояние ограничивающего прямоугольника.
В следующем примере на уровне класса создается объект Bitmap, а затем он использует
обработчик события отрисовки для изменения вида объекта Bitmap. Каждый раз,
когда клиентская область формы становится недействительной, Windows вызывает
этот обработчик и изображение на форме перерисовывается:
Bitmap bmp =
new Bitmap(«c:\\MyImage.bmp»);
protected void
onPaint(PaintEvent e){
e.graphics.drawlmage(bmp,
new Point(0, 0)); }
Когда форма
отображается в первый раз, а также при каждом получении фокуса, обработчик события
отрисовки вызывается автоматически. Однако если форма поддерживает изменение
размеров, то смена размеров формы не вызывает автоматически перерисовку. Напротив,
нужно добавить в класс, производный от Form, обработчик события изменения размеров
и из этого обработчика вызывать метод invalidate объекта. Обращение к этому
методу запускает обработчик события отрисовки формы:
protected void onResize(Event e)
{
this. invalidate();
}
Выполнение
операций с описателями
Описатель
(handle) — это уникальный номер, по которому некий элемент операционной системы
идентифицируется в компьютере. Например, каждое окно на рабочем столе имеет
уникальный описатель, позволяющий компьютеру отличить его от других окон. Каждые
контекст устройства, перо, кисть и шрифт также имеют уникальный описатель. Чтобы
сохранить оптимальную совместимость с Win32 API, объекты Graphics, Pen, Brush
и Font поддерживают операции с описателями. Например, если Вы используете \Ут32-функцию
CreatePen для создания пера, эта функция вернет описатель. Затем Вы вправе передать
этот описатель в конструктор объекта Реп, и объект будет создан на основе характеристик
пера Win32.
Даже если
Вы не создаете объект Pen, Brush или Font на основе имеющегося описателя, Вы
можете получить описатель, на котором основан любой из этих объектов. Каждый
из этих объектов поддерживает методы copyHandle и getHandle; продублировав или
получив описатель объекта при их помощи, Вы вправе передать описатель в любую
функцию Win32, которая примет его в качестве параметра.
Далее следует
несколько важных правил, которые надо иметь в виду при выполнении действий с
описателями и объектами Graphics. • Если создается объект на основе описателя,
полученного при помощи метода Win32, то объект не владеет этим описателем. Например,
если используется метод GetDC из Win32 для получения описателя контекста устройства
(HDC) для формы, то затем следует создать объект Graphics на основе этого HDC,
чтобы владеть описателем. Это означает, что, когда вызывается метод dispose
объекта Graphics, описатель не освобождается. Вместо этого придется использовать
соответствующую процедуру Win32 для уничтожения описателя. Ниже проиллюстрировано,
как управлять описателем. В этом примере используется функция GetDC из Win32
для получения описателя из контекста устройства для формы, затем на основе этого
описателя создается объект Graphics. После применения объекта Graphics для отрисовки
линии на форме вызывается метод dispose объекта Graphics для уничтожения объекта
Graphics и вызывается процедура ReleaseDC из Win32 для освобождения описателя
контекста устройства, выделенного вызовом GetDC:
// импорт пакета
the com.ms.wfc.Win32.Windows, import com.ns.wfс.Win32.Windows;
int hDC = Windows.GetDC(this.getHandle());
Graphics g =
new Grapnics(hDC);
g.drawLine(new
Point(0.0), new Point(100, 0));
g.dispose();
Windows.ReleaseDC(hDC);
Заметьте,
здесь говорится об описателе контекста устройства, но используемые принципы
применимы и к перьям, кистям, шрифтам и растрам.
Системы
координат объекта Graphics
Множество
методов объекта Graphics зависит от числовых координат. Последние задаются в
объекте Rectangle, определяющем область выполнения операции, или в объекте Point,
который указывает координаты х (горизонтальную) и у (вертикальную) места выполнения
операции. Система координат (coordinate system) определяет, как координаты,
заданные на объекте, отображаются на дисплей или на устройство. Предположим,
к примеру, что Вы вызвали метод drawString объекта Graphics для вывода текста
в координатах 100, 100:
Graphics g =
this.createGraphics();
g.drawString(«Hello, WFC»
, new Point(100,
100));
Объект Point
здесь определяет координаты х и у места, где будет выведена строка.
Однако действительный результат операции зависит от системы координат, с которой
связан объект Graphics. Системы координат, с которыми может быть связан объект
Graphics, определены в классе CoordinateSystem. По умолчанию системой координат
для объекта Graphics является CoordinateSystem.TEXT, что означает, что при увеличении
значений х и у в объекте Point текст (или изображение или элемент управления)
смещается горизонтально вправо и вертикально вниз.
Чтобы привязать
систему координат к объекту Graphics, используйте метод setCoordinateSystem:
Graphics gr = this.createGraphics();
gr.setCoordinateSystem(CoordinateSysten.ANISOTROPIC);
В таблице
перечислены системы координат, которые можно связывать с объектом Graphics,
и описаны направления вывода при увеличении значений по осям х и у в объекте
Point.
Система координат |
Направление
х |
Направление
у |
||
CoordinateSystem.TEXT |
Вправо |
Вниз |
||
CoordinateSystem.LOMETRIC |
Вправо |
Вверх |
||
CoordinateSystem.HIMETRIC |
Вправо |
Вверх |
||
CoordinateSystem.LOENGLISH |
Вправо |
Вверх |
||
CoordinateSystem.HIENGLISH |
Вправо |
Вверх |
||
CoordinateSystem.TWIPS |
Вправо |
Вверх |
||
CoordinateSystem.ISOTRdPIC |
Определяется
пользователем |
Определяется
пользователем |
||
CoordinateSystem.ANISOTROPIC |
Определяется
пользователем |
Определяется
пользователем |
||
Начало координат
(coordinate origin) определяет место, от которого отсчитываются координаты.
Например,
если создается объект Graphics посредством основной формы приложения, системой
координат объекта является CoordinateSystem.TEXT и графические координаты отсчитываются
от верхнего левого угла формы.
Однако, если Вы работаете с системой координат, задаваемой пользователем, — CoordinateSystem.ISOTROPIC или CoordinateSystem.ANISOTROPIC, — то Вы вправе самостоятельно установить начало координат (и для страницы, и для устройства), используя метод setCoor-dinateOrigin метода Graphics. Предположим, к примеру, что Вы включили следующий код в обработчик события отрисовки:
private
void Form1_paint(0bject source, PaintEvent e)
{
// Задать систему
координат.
e.graphics.setCoordinate
System(CoordinateSystem.ANISOTROPIC);
e.graphics.setCoordinateOrigin(new Point(20, 20), new Point(20,20));
e.graphics.setCoordinateScale(new Point(1,1), new Point(1,1));
e.graphics.drawLine(new
Point(O.O), new Point(100,100));
}
Этот код
задает систему координат CoordinateSystem.ANISOTROPIC и затем
- точку отсчета 20,20 для страницы и для устройства.Вызов drawLine,
указанный далее и коде, отсчитывается от этой точки. Следовательно, линия закончится
в точке с координатами 100,100 от точки отсчета (20,20).
Отображение
логических координат на координаты устройства
Windows предоставляет
встроенную поддержку для отображения страничных координат на устройство, например
принтер или дисплей. Для большинства систем координат, определенных в Windows,
система сама выполняет преобразование. Например, если ассоциировать объект Graphics
с системой координат CoordinateSystem.HIMETRIC, то каждая логическая единица
на объекте будет преобразована в одну тысячную дюйма на устройстве.
Однако, когда
используются задаваемые пользователем системы координат ANISOTROPIC и ISOTROPIC,
нужно использовать метод setCoordinateSeale,
чтобы сообщить системе, как выполнять преобразование,
например:
Graphics g =
this.createGraphics();
g.setCoordinateSystem(CoordinateSystem.ANISOTROPIC);
g.setCoordinateSca!e(new
Point(1,1), new Point(2,2));
Вызов setCoordinateScale
здесь указывает системе на необходимость преобразования логической горизонтальной
и вертикальной единицы в две
горизонтальные и вертикальные единицы устройства.
Метод drawString
объекта Graphics поддерживает вывод текста на тот элемент управления, к которому
относится объект. Этот метод пишет текст в заданную позицию, как показано в
следующем примере: Graphics g = this.createGraphicsO; g.drawString(«Hello,
World», new Point(0, 0));
Визуальный
результат вызова зависит от нескольких факторов, включая текущий цвет текста
объекта Graphics, цвет фона, характеристики шрифта и системы координат.
Информацию
о том, как установить цвет текста, см. в следующем разделе «Установка
цвета текста». Подробнее о связывании шрифтов с объектом Graphics см.
в разделе «Использование объекта Font» далее в этой главе. Сведения
о системах координат приведены выше в этой главе в разделе «Системы координат
объекта Graphics».
Чтобы установить
цвет текста и цист фона для текста, вызовите методы setBackColor и setTextColor
объекта Graphics перед вызовом drawString:
// Установить белый цвет текста и черный фон.
g.setTextColor(new Color(0, 0, 0));
g.setBackColor(new Color(255, 255, 255));
// Вывести текст...
Метод setBackColor
влияет только на фон за текстом. Чтобы задать фон или цвет заполнения других
объектов, например многоугольников и линий, используйте соответственно методы
setBrush и setPen.
Шрифт
(font) — это набор знаков определенного рисунка. Основными элементами шрифта
являются гарнитура (typeface), стиль и кегль (размер).
В WFC шрифты
Windows инкапсулированы в объекте Font, который можно использовать в комбинации
с другими шрифтовыми объектами для определения шрифтов (число их не ограничено),
используемых для вывода в объекте Graphics. В таблице перечислены шрифтовые
классы, поддерживаемые WFC.
Класс |
Описание |
||
FontDescriptor | Предоставляет информацию о шрифте, на котором основан объект Font. | ||
FontFamily | Определяет группу констант, представляющих семейства шрифтов, к которым может принадлежать шрифт. | ||
FontMetrics | Определяет физические характеристики шрифта, отображенного в объект Graphics. | ||
FontPitch | Определяет разрядку шрифта. | ||
FontSize | Определяет группу констант, представляющих единицы, в которых может быть задан размер шрифта. | ||
FontType | Определяет группу констант, представляющих устройства, на которых будет использоваться шрифт. | ||
FontWeight | Определяет константы, представляющие различные веса, которые могут быть связаны со шрифтом. | ||
Создание
объекта Font бывает простым или сложным в зависимости от степени детализации
определения шрифта. Следующий фрагмент кода иллюстрирует один из простых подходов
к созданию объекта Font: Font font = new Font(«Times New Roman»,
26);
Здесь используется
конструктор объекта Font, которому требуется только два вида информации: имя
шрифта и его размер. При создании
объекта Font
можно также задан, семейство шрифта, его тип, вес, ориентацию, а также будет
ли он полужирным, курсивным, подчеркнутым или зачеркнутым. Однако изменить атрибуты
после создания объекта Font нельзя.
Установка
шрифта для объекта Graphics
Объект Graphics
поддерживает метод setFont, который связывает шрифт с объектом. После связывания
объекта Font с объектом Graphics весь текст, выводимый внутри ограничивающего
прямоугольника объекта Graphics, рисуется этим шрифтом.
Следующий
код иллюстрирует установку белого фона, черного текста и шрифта Times New Roman
размером 26 пунктов для объекта Graphics. Текст выводится в заданную позицию
экрана:
Graphics g =
this.createGraphics();
g.setFont(new Font(«Times New Roman», 26));
g.setBackColor(new Color(255, 255, 255));
g.setTextColor(new Color(0, 0, 0));
g.drawString(«Hello,
World», 0, 0);
В некоторых
случаях приложения перебирают все доступные шрифты, получая по каждому детальную
информацию, чтобы выбрать наиболее подходящий для конкретной операции.
Объект FontDescriptor
в WFC — описание шрифта, включающее его имя, высоту, ориентацию и т. д. Для
получения детального описания всех доступных в системе шрифтов используйте метод
getFontDesc-riptors объекта Graphics. Он возвращает массив объектов FontDescriptor,
каждый элемент которого описывает шрифт.
Ниже показано,
как использовать метод getFontDescriptors. В этом примере извлекается список
имеющихся шрифтов, а затем вставляется единый список имен шрифтов в окно списка:
Graphics g = this.createGraphics();
// Создать массив.
FontDescriptor
rgFonts[] = g.getFontDescriptors();
for(int i =
0; i < rgFonts.length; i++){
if(listBox1.findString(rgFonts[i].fullName
== -1){
listBoxl.addltem(rgFonts[i].fullName);
} }
Перо (реп)
— это графическое средство, которое приложения Microsoft Windows используют
для отрисовки линий и кривых. Приложения, предназначенные для рисования, позволят
Вам использовать перья для проведения «от руки» прямых и кривых
линий. В САПР-приложениях перья служат для изображения видимых и скрытых линий,
линий сечений, осей симметрии и т. п. В текстовых редакторах и настольных издательствах
перья применяются для вывода границ и линеек. В электронных таблицах — для обозначения
трендов на графиках и для вывода линейчатых и круговых диаграмм.
Каждое перо
имеет три атрибута: стиль, ширину и цвет. Тогда как на ширину и цвет не накладывается
никаких ограничений, стиль пера должен поддерживаться операционной системой.
Возможности
перьев из Win32 инкапсулированы в объектах Реп и Pen-Style из WFC. Следующий
фрагмент кода демонстрирует создание объекта Реn:
Реn р = new
Pen(PenStyle.DASH);
Константа,
передаваемая в конструктор объекта Реп, — это стиль пера (pen style).
Семь встроенных в Windows стилей пера представлены константами, определенными
в классе PenStyle. Последний — это класс перечисления (enumeration class), что
означает, что в нем определен метод (valid), который указывает, является ли
заданное значение членом класса PenStyle. В таблице перечислены константы из
класса PenStyle.
Константа |
Описание |
||
PenStyle.DASH | Тире | ||
PenStyle.DOT | Точки | ||
PenStyle.DASHDOT | Точка и тире | ||
PenStyle.DASHDOTDOT | Две точки и тире | ||
PenStyle.INSIDEFRAME | Перо рисует линию внутри замкнутых фигур, полученных функциями вывода объекта Graphics, в которых указан ограничивающий прямоугольник (например, drawRect, drawPie и drawChord) | ||
PenStyle.NULL | Пустое перо | ||
PenStyle.SOLID | Сплошное перо | ||
Кроме того,
объект Реп включает группу открытых переменных-членов, которые можно использовать,
чтобы задать тип создаваемого пера. Каждая из этих переменных сама является
объектом Реп и позволяет
Вам имитировать
различные собственные черты пользовательского интерфейса Windows.
Например,
в классе Реп определена переменная компонент WINDOWF-RAME. Линии, рисуемые пером
типа WINDOWFRAME, выглядят аналогично рамке активного окна:
Pen pen = Pen.WINDOWFRAME;
В таблице
перечислены объекты Реn, определенные как открытые переменные-члены класса Реn.
Объект |
Описание |
||
Реп.АСТР/ЕСАРТIONТЕХТ |
Создает перо
с цветом текста заголовка активного окна. |
||
Pen.CONTROLTEXT |
Перо с цветом
текста элемента управления |
||
Pen.GRAYTEXT |
Перо с цветом
заблокированного текста |
||
Pen.HIGHLIGHTTEXT |
Перо с цветом
выделения текста |
||
Pen.INACTIVECAPTIONTEXT |
Перо с цветом
текста заголовка неактивного окна |
||
Pen.INFOTEXT |
Перо с цветом
текста подсказки |
||
Pen.MENUTEXT |
Перо с цветом
текста меню |
||
Pen.NULL |
Пустое перо
(не действует) |
||
Pen.WINDOWFRAME |
Перо с цветом
рамки активного окна |
||
Pen.WINDOWTEXT |
Перо с цветом
текста активного окна |
||
Обратите
внимание, что, когда используется перо на основе системной константы, например
цвета текста активного окна, изменение системных настроек приводит к изменению
пера.
Установка
пера для объекта Graphics
Объект Реп
сам по себе не содержит возможностей окраски или отри-совки. Он только описывает
подмножество возможностей GDI. Прежде чем использовать перо для рисования, его
нужно связать с объектом Graphics, используя метод setPen:
Graphics g = this.createGraphics();
g.setPen(new
Pen(PenStyle.DASH));
После связывании
объекта Pen с объектом Graphics все линии внутри ограничивающего прямоугольника
объекта Graphics рисуются с использованием этого пера. Метод setPen можно вызывать
любое число раз для одного объекта Graphics.
В следующем
примере показано, как объект Реп используется объектом Graphics для рисования
линий. В этом примере стили пера, определенные
в объекте Реп, хранятся в целочисленном массиве. Внутри обработчика события
отрисовки класса находится цикл итерации по этому массиву, в котором рисуется
одна линия с использованием каждого стиля:
public class
Form"! extends Form {
int [] rgStyles
= { PenStyle.DASH, PenStyle.DASHDOT, PenStyle.DASHDOTDOT, PenStyle.DOT, PenStyle.INSIDEFRAME,
PenStyle.SOLID };
protected void
onPaint(PaintEvent e) {
Rectangle rc
= this.getClientRect();
re. у += 10;
for(int i =
0; i < rgStyles.length; i++){
e.graphics.setPen(new Pen(Color.BLACK, i));
e.graphics.drawLine(new
Point(0, rc.y),
new Point(re.width,
rc.y));
rc.y += 10;
} }
// Остальное
описание класса Forml...
Кисть
(brush) — это графическое средство, которое приложения Win32 используют
для заполнения внутренних областей многоугольников, эллипсов и произвольных
фигур (paths). Приложения, предназначенные для рисования, используют кисти для
заполнения фигур; текстовые редакторы — для заполнения линеек; САПР-приложения
— для заполнения внутреннего вида сечений; электронные таблицы — для заполнения
круговых и линейчатых диаграмм.
Есть два
типа кистей: логические и физические. Логическая — это та, которая определяется
в коде как идеальная комбинация цветов и/или узоров и которую приложение должно
использовать для рисования. Физическую кисть драйвер устройства создает на основе
определения логической кисти.
Когда приложение
вызывает функцию отрисовки для заполнения фигуры, Windows помещает кисть в начало
операции отрисовки и отображает пиксел в растре кисти на начало координат клиентской
области окна. (Начало координат окна (window origin) — это верхний левый угол
клиентской' области.) Координаты пиксела, отображаемого Windows, называются,
началом координат кисти (brush origin). По умолчанию начало координат кисти
помещается в верхнем левом углу растра кисти с координатами (0,0). Затем Windows
копирует кисть вдоль клиентской, области, формируя узор, который по высоте совпадает
с растром. Копирование — строка за строкой — продолжается, пока не заполнится
вся клиентская область. Однако узор кисти видим только внутри границ заданной
фигуры. (Здесь термин растр используется в его наиболее буквальном смысле —
как массив битов, а не относится исключительно к битам, хранимым в файле изображения.)
В некоторых случаях начало координат кисти по умолчанию не должно использоваться.
Например, приложению требуется отрисовать одной кистью фон его родительского
и дочернего окон и смешать фон дочернего окна с фоном родительского окна.
Логические
кисти бывают трех разновидностей: сплошная, растровая и шаблонная.
Сплошная
(solid) кисть состоит из цвета или узора, определенного для некоторого элемента
пользовательского интерфейса Windows (например, можно заполнить фигуру цветом,
которым в Windows отображаются запрещенные кнопки).
Шаблонная
(hatched) кисть состоит из комбинации цвета и одного из шести узоров, определенных
в Win32.
Растровая
(pattern) кисть состоит из растра, который используется как основа для узора,
заполняющего фигуру. Если область заполнения больше, чем растр, то растр размножается
горизонтально и вертикально. На основе растровых кистей Вы можете создавать
произвольные кисти, отображающие любой созданный Вами узор.
Возможности
кистей Win32 инкапсулированы в объектах Brush и BrushStyle из WFC, последние
совместно используются для создания сплошных, растровых и шаблонных кистей.
Объект Brush
определяет группу открытых конечных (public final) переменных-членов, каждая
из которых является объектом Brush, представляющим сплошную кисть. Класс BrushStyle
представляет штрихующие кисти в виде группы целочисленных констант, каждая из
которых отвечает определенному стилю кисти.
В таблице
перечислены константы объекта Brush, представляющие сплошные кисти.
Константа |
Описание |
||
Brush . ACTI
VEBORDER |
Объект Brush
цвета рамки активного окна |
||
Brush.ACTIVECAPTION |
Объект Brush
цвета заголовка активного окна |
||
Brush.APPWORKSPACE |
Объект Brush
цвета рабочего пространства окна приложения |
||
Brush. CONTROL |
Объект Brush
цвета элементов управления |
||
Brush.CONTROLDARK |
Объект Brush
цвета тени трехмерного элемента |
||
Brush.CONTROLDARKDARK |
Объект Brush
цвета самой темной части трехмерного элемента |
||
Brush.CONTROLLIGHT |
Объект Brush
цвета подсвеченной части трехмерного элемента |
||
Brush.CONTROLLIGHTLIGHT |
Объект Brush
цвета самой светлой части трехмерного элемента |
||
Brush.DESKTOP |
Объект Brush
текущего цвета рабочего стола |
||
Brush.HALFTONE |
Объект Brush
цвета стандартной полутоновой кисти |
||
Brush.HIGHLIGHT |
Объект Brush
цвета фона подсвеченных элементов |
||
Brush.HOLLOW |
Пустая кисть,
не действует |
||
Brush.HOTTRACK |
Объект Brush
цвета для индикации активного отслеживания » |
||
Brush.INACTIVEBORDER |
Объект Brush
цвета рамки неактивного окна |
||
Brush.INACTIVECAPTION |
Объект Brush
цвета заголовка неактивного окна |
||
Brush.INFO |
Объект Brush
цвета фона информационной подсказки |
||
Brush.MENU |
Объект Brush
цвета фона меню |
||
Brush.NULL |
Пустая кисть |
||
Brush.SCROLLBAR
Brush.WINDOW |
Объект Brush
цвета фона полосы прокрутки Объект Brush цвета фона окна |
||
Ниже перечислены
константы объекта BrushStyle, представляющие штрихующие кисти.
Константа |
Описание |
||
BrushStyle.
BACKWARDDIAGONAL |
Представляет
обратную диагональную кисть. Параллельные линии идут из левого нижнего
угла в правый верхний. |
||
BrushStyle.DIAGONALCROSS |
Представляет
кисть с перекрестной штриховкой. |
||
BrushStyle.FORWARDDIAGONAL |
Представляет
прямую диагональную кисть. Параллельные линии идут из правого нижнего
угла в левый верхний. |
||
BrushStyle.HOLLOW |
Представляет
пустую кисть. |
||
BrushStyle.HORIZONTAL |
Представляет
узор из равномерно распределенных горизонтальных линий. |
||
BrushStyle.PATTERN |
Представляет
растровую кисть. |
||
BrushStyle.
SOLID |
Представляет
сплошную кисть. |
||
BrushStyle.YERTICAL |
Представляет
узор из равномерно распределенных вертикальных линий. |
||
Объект Brush
создается в зависимости от типа необходимой кисти. Так как сплошные кисти являются
объектами Brush, то они создаются следующим образом:
Brush br = Brush.BLACK;
Шаблонная
кисть представляется объектом Brush как целая константа и
создается так:
Brush br = new
Brush(Color.BLACK, BrushStyle.FORWARDDIAGONAL);
В следующем
фрагменте кода демонстрируется способ создания кисти на
основе растра:
Brush bmpBrush
= new Brush(new Bitmap(«с:\\myBitmap. bmp»));
В этом примере
предполагается, что растр находится в файле на диске. Однако Вы также можете
использовать метод createBitmap объекта Bitmap для создания растра во время
выполнения — затем он будет положен в основу узора кисти.
Установка
кисти для объекта Graphics
Подобно объектам
Реп и Font, у объекта Brush нет возможностей окраски или отрисовки. Он отражает
подмножество возможностей GDI. Прежде чем использовать кисть для заполнения
поверхностей, ее надо связать с объектом Graphics посредством метода setBrush:
protected void
onPaint(PaintEvent e) {
// Создать прямо-диагональную кисть и связать ее с объектом.
Brush br = new Brush(Color.BLACK, BrushStyle.FORWARDDIAGONAL);
e.graphics.setBrush(br);
}
После привязки
объекта Brush к объекту Graphics все многоугольники, рисуемые с использованием
этого экземпляра объекта Graphics, будут заполнены с помощью этой кисти. Метод
setBrush можно вызывать сколь угодно часто для привязки к объекту Graphics новых
кистей.
Произвольная
кисть может быть основана на растре, который загружен из файла или создан в
памяти. В примере CustomBrush демонстрируется, как создать и использовать такие
кисти.
Приложение
CustomBrush состоит из двух панелей и двух кнопок. Первая панель (panelGrid)
состоит из 64 квадратов. Когда пользователь щелкает один из них, в приложении
регистрируется щелчок, квадрат закрашивается черным и выполняются битовые операции
над одним из членов массива коротких целых. Модифицируемое целое зависит от
квадрата, который щелкнули.
Когда пользователь
щелкает кнопку Test, в приложении CustomBrush создается растр на основе массива
коротких целых, затем — кисть на основе этого растра, и эта кисть используется
для рисования на панели (panelRect), которая появляется над кнопкой Test.
При запуске
приложения CustomBrush выполняются следующие действия.
public class
Form1 extends Form {
// Прямоугольники, на которые разделена панель.
Rectangle []
rgRects = new Rectangle[64];
// Состояния
прямоугольников.
boolean [] rgStates
= new boolean[64];
int [] bBrushBits
= new int[8];
public Form1()
{
// Установка
начального значения false для массива состояний.
for(int i =
0; i < rgStates.length; i++){ rgStates[i] = false;
}
// Инициализация
формы.
initForm();
// Разделить
панель на 64 прямоугольника и заполнить форму.
rgRects = getRects(panelGrid.getClientRect(), 8, 8);
this.invalidate();
}
/.*
* В этом методе
заданная прямоугольная область разделяется на заданное
* число прямоугольников
(вдоль и поперек), и возвращается массив,
* содержащий
прямоугольники. */
private Rectangle
[] getRects(Rectangle rcClient, int nAcross, int nDown){
int deltaX,
deltaY;
int x, y, right,
bottom;
int i;
Rectangle rgRects[] = new Rectangle[nAcross * nDown];
// Сохранить
правый и нижний прямоугольники.
right = rcClient.getRight();
bottom = rcCllent, get Bottom();
// Определить
высоту и ширину каждого прямоугольника.
deltaX = (right - rcClient.x) / nAcross;
deltaY = (bottom
- rcClient.y) / nDown;
// Инициализировать массив прямоугольных ячеек.
for(y = rcClient.y,
i = 0; у < bottom; у += deltaY){
for(x = rcClient.x;
x < (right - nAcross) && i < (nAcross * nDown);
x += deltaX,
i++){
rgRects[i] =
new Rectangle(x, y, deltaX, deltaY);
} }
return rgRects;
}
Когда вызывается
обработчик события отрисовки на панели с сеткой, для рисования сетки используются
размеры, хранимые в массиве объектов Rectangle (rgRects), и состояния, хранимые
в Булевом массиве (rgStates) уровня класса. Если Булево значение, соответствующее
заданному прямоугольнику, равно true, то внутренняя область прямоугольника окрашивается
в черный цвет. В противном случае она окрашивается при помощи пустой кисти.
Это позволяет пользователю определить внешний вид кисти, которая будет создана
на основе раскладки прямоугольников на панели:
private void
panelGrid_paint(Object source, PaintEyent e) {
e.graphics.setPen(new Pen(Color.BLACK, PenStyle.SOLID, 1));
// Нарисовать сетку, отражающую текущее состояние квадратов.
for(int i = 0; i < rgRects.length; i++){
if(rgStates[i]
== true){
// Если квадрат
ранее щелкнули, заполнить его.
e.graphics.setBrush(new
Brush(Color.BLACK)); }else{
e.graphics.setBrush(Brush.NULL);
}
e.g raphics.d
rawRect(rgRects[i]); }
}
При каждом
щелчке пользователя одного из прямоугольников панели i сеткой генерируется событие
щелчка. Внутри обработчика события оп ределяется, какой прямоугольник щелкнули,
соответствующее Булевс значение в массиве устанавливается в true и вызывается
panelGrid.inva lidate, чтобы вызвать перерисовку. Кроме того, выполняется битова;
операция над соответствующим членом массива битов, хранящимися i переменной
bBrushBits уровня класса:
private void
panelGrid_mouseDown(Object source, MouseEvent e) {
Graphics gr = this.createGraphics();
gr.setBrush(new Brush(Color.BLACK));
Integer nBit
= new Integer(O); // Определить ячейку, которую щелкнули.
for(int i =
0; i < 64; i++){
Rectangle rc
= new Rectangle(rgRects[i].x,
rgRects[i].y,
rgRects[i].height, rgRects[i].width);
if(rc.contains(new
Point(e.x, e.y))){
// Установить соответствующую Булеву переменную состояния.
rgStates[i] =
true;
// Выполнить
побитовую операцию NOT над соответствующим
// целым в массиве
коротких целых, на котором основан растр.
if(i % 8 ==
0)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x80; if(i HI 8 == 1)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x40; if(i % 8 == 2)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x20; if(i X 8 == 3)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x10; if(i X 8 == 4)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x08; if(i % 8 == 5)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x04; if(i X 8 == 6)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x02; if(i % 8 == 7)
bBrushBits[i/8]
= bBrushBits[i/8] ^ 0x01;
break;
} }
// Перерисовать
сетку. panelGrid. invalidate();
}
Наконец,
когда пользователь щелкает кнопку Test, обработчик события такого щелчка заставляет
перерисовать панель panelRect, появляющейся над кнопкой Test благодаря вызову
panelRect.invalidate:
private void btnTest_click(Object source, Event e)
{
panelRect.invalidate();
}
Внутри обработчика
события отрисовки панели panelRect приложение создает растр на основе массива
коротких целых (bBrushBits) и кисть на основе этого растра и далее этой кистью
раскрашивает панель panelRect, появляющаяся над кнопкой Test:
private void panelRect_paint(Object source, PaintEvent e)
{
short [] rgShorts
= new short[8];
for(int i =
0; i < bBrushBits.length; i++){
rgShorts[i]
= (short) bBrushBits[i]; }
e.graphics.setBrush(new Brush(new Bitmap(8,8,1,1,rgShorts)));
e. graphics.
fill(panelRect. getClientRect());
}
Растр
(bitmap) — это поверхность для рисования. Ее используют для вывода перьев,
кистей или изображений, включая растры и метафайлы Windows, а также файлы форматов
.gif и .jpg.
Объект Bitmap
поддерживает создание и загрузку растров. Его можно применять для загрузки растровых
изображений из файлов, потоков данных или ресурсов или для создания таких изображений
в памяти. Кроме того, объект Bitmap поддерживает определение прозрачных цветов
внутри растра.
После создания
объекта Bitmap для вывода его на дисплей используется метод drawlmage объекта
Graphics.
В следующем
фрагменте кода создается новый объект Bitmap, а затем для создания объекта Graphics,
рисующего изображение, используется метод createGraphics класса Form:
Bitmap bmp = new Bitmap(«c:\\MyImage.bmp»);
Graphics g =
this.createGraphics();
g.drawlmage(bmp,
new Point(10, 10));
Сжатие
и растяжение изображений
Все объекты-изображения,
поддерживаемые WFC (Metafile, Icon, Bitmap и Cursor), имеют методы drawStretchTo
и drawTo. Любой вывод изображений посредством объекта Graphics выполняется с
помощью этих методов. Когда вызывается метод drawlmage объекта Graphics, последний
определяет, какой из методов — drawStretchTo или drawTo -надо вызывать
для переданного объекта.
Метод drawStretchTo
расширяет или сжимает изображение, чтобы оно уместилось в заданную прямоугольную
область. Метод drawTo также выводит изображение в заданную область, но обрезает
его, если оно слишком велико. Кроме того, оба метода поддерживают вывод разделов
изображения в заданный раздел ограничивающего прямоугольника объекта Graphics.
Методы drawStretchTo
или drawTo нельзя вызывать напрямую: в классах изображений в WFC они всегда
объявляются защищенными (protected). Чтобы определить, какой из этих методов
будет вызван, исполь-
зуется версия
метода drawlmage, имеющая Булев параметр scale. Вот один из таких методов,
определенный в объекте Graphics: public final void drawlmage(lmage i, Rectangle
r, Boolean scale) Если параметр scale равен true,
то изображение будет растянуто или сжато до размеров отсекающего прямоугольника;
в противном случае изображение будет обрезано.
Прозрачная
визуализация изображений
Объект Bitmap
поддерживает прозрачную визуализацию одного или нескольких цветов изображения.
Если нужно
сделать прозрачным один цвет, используются методы set-TransparentColor и setTransparent.
Метод setTransparentColor получает в качестве параметра объект Color, определяющий
цвет, который будет прозрачным. Метод setTransparent принимает Булево значение,
которое определяет, должен ли выводится заданный прозрачный цвет или нет. Например,
в следующем фрагменте кода черный цвет определен как прозрачный. Когда для отрисовки
изображения вызывается метод draw-Image объекта Graphics, черные пикселы не
выводятся:
protected void
onPaint(PaintEvent e) {
Bitmap bmp = new Bitmap(«c:\\MyImage.bmp»);
Bmp.setTransparentColor(Color.BLACK); Bmp.setTransparent(false);
e.graphics.drawlmage(bmp,
new Point(0,0));
}
Прозрачность
достигается и путем создания объекта Bitmap на основе двух битовых масок — одной
цветной и одной монохромной. В цветной маске каждая часть растра, которая выводится
прозрачной, должна быть черного цвета. В монохромной маске каждая часть, которая
выводится прозрачной, должна быть белого цвета.
Растровая
операция предполагает логическое действие над отображением базисного элемента
GDI — пера, кисти, растра или фигуры -с целью получения визуального эффекта.
Растровые операции, выполняемые с использованием объекта Graphics, определены
в объекте Graphics. Просмотрев методы, поддерживаемые объектом Graphics, Вы
увидете, что для каждой базовой операции — проведения линии или вывода изображения
— есть метод, получающий RasterOp в качестве параметра.
В своих простейших
воплощениях методы отрисовки объекта Graphics поддерживают только запись или
копирование пикселов в некоторую область дисплея, заменяя текущее изображение.
Добавьте в это уравнение растровые операции, и такая замена усложнится. Предположим,
что надо нарисовать черный прямоугольник в области экрана, занятой в данный
момент изображением, но желательно логически скомбинировать черные пикселы с
соответствующими им пикселами на целевом изображении и вывести результаты на
дисплей. Растровые операции делают такую комбинацию возможной.. Вариантов логики,
поддерживаемых объектом RasterOps, слишком много, чтобы рассмотреть их все в
этом документе. В следующих операторах демонстрируется типовой синтаксис вызова
с использованием объекта RasterOps — устанавливается фоновый цвет формы и затем
рисуется линия одетом, являющимся инверсией фонового цвета:
protected void
onPaint(PaintEvent e)
{
this.setBackColor(new
Color(255, 255, 255);
e.graphics.drawLine(new
Point(10, 10), new Point(100, 10),
RasterOp.TARGET. invert());
}
Объект Graphics
поддерживает вывод линий, прямоугольников, сегментов, дуг, секторов и сплайнов
Безье.
Линия
— это набор подсвеченных пикселов на дисплее, идентифицируемый двумя точками:
начальной и конечной. В Windows пиксел, находящийся в начальной точке, всегда
включается в линию, а пиксел, расположенный в конечной точке, всегда исключается
(такие линии иногда называются inclusive-exclusive).
Приложение
может нарисовать одну линию, вызвав метод drawLine объекта Graphics. Этот метод
получает два параметра типа Point, которые задают начало и конец линии:
protected void
onPaint(PaintEvent e){
Rectangle rcClient
= this.getClientRect();
// Нарисовать
линии, которые делят экран на четыре одинаковых квадрата.
e.graphics.drawLine(new
Point(rcClient.x, rcClient.height / 2),
new Point(rcClient.width,
rcClient.height / 2));
e.graphics.drawl_ine(new
Point(rcClient.width / 2, rcClient.y),
new Point(rcClient.width
/ 2, rcClient,height)); }
Приложения,
написанные для Microsoft Windows, используют прямоугольники, чтобы задать прямоугольные
области на экране или в окне. Прямоугольники описывают клиентскую область окна,
области на экране, которые нужно перерисовать, и области для вывода форматированного
текста. Приложения могут также применять прямоугольники для заполнения, ограничения
или инвертирования части клиентской области с использованием данной кисти и
для получения координат окна или его клиентской области.
Размеры прямоугольных
областей описываются объектом Rectangle из WFC. Этот объект содержит целые х,
у, height и width, которые определяют его местонахождение и размеры
на экране. Кроме того, для получения положения правой и нижней сторон можно
использовать методы getRight и getBottom.
Подробности
см. в разделах «Операции с прямоугольниками» и «Пример прямоугольника»
далее в этой главе.
Операции
с прямоугольниками
Объект Rectangle
предоставляет ряд методов для работы с прямоугольниками. Метод equals определяет,
идентичны ли два объекта Rectangle, т. е. одинаковы ли их координаты.
Метод inflateRect
увеличивает или уменьшает ширину, высоту прямоугольника или оба параметра вместе.
Его средствами можно изменить размеры с обеих сторон прямоугольника, а также
снизу и сверху. Замещаемый метод contains позволяет определить, находится ли
область, описываемая одним прямоугольником, внутри другого, и узнать, находится
ли заданная точка внутри прямоугольника. Методы intersects и intersectsWith
определяют, пересекаются ли два объекта Rectangle.
Пример
прямоугольника
Пример в
этом разделе показывает, как разделить части клиентской области приложения на
подобласти и как работать внутри этих областей. При запуске приложение делит
клиентскую область основной формы на прямоугольные подобласти в количестве 16
на 16 и в каждой из них отображает оттенок заданного цвета. Чтобы изменить число
прямоугольников, отображаемых по высоте и ширине дисплея, выберите команду меню
Dimensions для вывода диалогового окна, в котором можно задать число прямоугольников.
Метод деления
экрана на объекты Rectangle приведен в следующем примере. У этого метода getRects
есть три параметра: прямоугольник, определяющий разделяемую область, и два целых
числа, которые задают число ячеек, рисуемых по высоте и ширине. Метод возвращает
массив прямоугольников с соответствующими координатами:
private Rectangle[]
getRects(Rectangle rcClient, int nDown, int nAcross){
int deltaX,
deltaY; // Ширина и высота каждой ячейки, int x, у;
int i;
Rectangle rgRects[] = new Rectangle[nDown * nAcross];
// Определить
ширину и высоту каждого прямоугольника.
deltaX = (rcClient.getRight() - rcClient.x) / nAcross;
deltaY = (rcClient.getBottom()
- rcClient.y) / nDown;
// Создать и инициализировать массив прямоугольников.
for(y = rcClient.у, i = 0; у < rcClient.getBottom();
у += deltaY){
for(x = rcClient.x; x < (rcClient.getRight() - nAcross) && i <
(nAcross * nDown); x += deltaX, i++){
rgRects[i] =
new Rectangle(x, y, deltaX, deltaY); } }
// Возвратить
инициализированный массив.
return rgRects;
}
При запуске
приложения его конструктор класса Form инициализирует значением 16 две целых
переменных уровня класса — nAcross и nDown, а также вызывает описанный
выше метод getRects:
public Form1(){
initForm();
nAcross = 16; nDown = 16;
// Инициализировать
массив уровня класса.
rgRects = getRects(this.getClientRect(),
nAcross, nDown);
}
После выполнения
конструктора класса автоматически вызывается обработчик события отрисовки этого
класса. Этот обработчик события проходит по массиву rgRects уровня класса,
использует метод setBrush объекта Graphics для установки нового цвета и затем
вызывает метод drawRcct для отрисовки каждого прямоугольника из массива:
protected void
onPaint(PaintEvent e){
for(int i =
0; i < rgRects.length; i++){
e.graphics.setBrush(new
Brush(new Color(0,0,i)));
e.graphics.drawRect(rgRects[i]);
} }
Наконец,
обработчик события resize класса Form заново инициализирует массив и вызывает
перерисовку клиентской области формы:
protected void
onflesize(Event e){
Rectangle rcClient = this.getClientRect();
rgRects = getRects(rcClient,
nDown, nAcross); this. invalidate(); }
Сегмент
(chord) — это область, ограниченная частью эллипса и линией, называемой
секущей (secant). Сегмент рисуется с использованием текущего пера и заполняется
с использованием текущей кисти. Часть эллипса по другую сторону секущей удаляется.
Чтобы нарисовать
сегмент, используйте метод drawChord объекта Graphics, который имеет следующий
синтаксис: drawChord( Rectangle p1, Point p2, Point
p3)
Параметр
Rectangle метода drawChord обозначает область, в которой будет нарисован эллипс.
Два параметра Point обозначают точки, в которых секущая пересекает эллипс.
В следующем
примере метод drawChord вызывается дважды. При первом вызове сегмент рисуется
в нижнем левом углу дисплея, а при втором — в правом верхнем. Перед каждым вызовом
drawChord с объектом Graphics связываются разные кисти, чтобы сегменты, вместе
образующие круг, были нарисованы соответственно черным и белым цветом:
protected void
onPaint(PaintEvent e){
Rectangle rcClient
= this.getClientRect();
// Связать с
объектом черную кисть и нарисовать сегмент.
e.graphics.setBrush(new Brush(new Color(0,0,0)));
e.graphics.drawChord(rcClient,
new Point(rcClient.x, rcClient.y), new Point(rcClient.getRight(), rcClient.getBottom());
// Связать с
объектом белую кисть и нарисовать сегмент.
e.graphics.setBrush(new Brush(new Color(255,255, 255)));
e.graphics.drawChord(rcClient,
new Point(rcClient.getRight(), rcClient.getBottomO), new Point(rcClient.x, rcClient.y));
}
Приложение
может нарисовать эллипс или часть эллипса путем вызова метода drawArc. Этот
метод рисует кривую внутри периметра невидимого прямоугольника, называемого
ограничивающим прямоугольником. Размер эллипса задается двумя невидимыми радиусами
— от центра прямоугольника к его сторонам.
При вызове
метода drawArc приложение задает координаты ограничивающего прямоугольника и
радиусы.
В следующем
примере рисуется дуга, которая заполняет клиентскую область формы, а затем используется
метод drawLine объекта Graphics для проведения линии от верха дуги к ее радиусу
и затем от радиуса к правой части эллипса:
protected void
onPaint(PaintEvent e){
Rectangle rcClient
= this.getClientRect();
e.graphics.drawArc(rcClient,
new Point(rcClient.width /2, rcClient.y),
new Point(rcClient.width, rcClient.height / 2));
e.graphics.drawLine(new
Point(rcClient.width / 2, rcClient.y),
new Point(rcClient.width / 2, rcClient.height / 2));
e.graphics.drawLine(new
Point(rcClient.width, rcClient.height / 2),
new Point(rcClient.width
/ 2, rcClient.height / 2)); }
Угловая дуга
(arc angle) подобна обычной. Основное различие в том, что при рисовании дуги
с использованием drawArc задаются значения х и у радиусов дуги. При отрисовке
угловой дуги используется метод drawArcAngle и задается угол; метод сам определяет
координаты начала и конца.
Метод drawArcAngle
имеет следующий синтаксис:
public final
void drawArcAngle(Point center, int radius, float startAngle,
float endAngle)
Параметр
типа Point задает место на экране, от которого отсчитывается радиус, определяемый
параметром radius. Параметр start Angle задает угол в градусах,
с которого начинается дуга, а параметр endAngle определяет, какой угол
в градусах составляет рисуемая дуга. В следующем примере показано, как использовать
этот метод. Здесь рисуется угловая дуга, startAngle который равен 30°, a
endAngle равен 300°:
protected void
onPaint(PaintEvent e){
Rectangle rcClient
= this.getClientRect();
int x = rcClient.width
/ 2;
int у = rcClient.height
/ 2;
int radius =
100;
float startAngle
= 30;
float endAngle
= 300;
e.graphics.drawAngleArc(new
Point(x.y), radius, startAngle, endAngle); }
Безье-сплайны
(Bezier spline) определяются четырьмя точками — двумя концевыми и двумя контрольными.
Вместе эти точки определяют кривую. Две концевые точки определяют начало и конец
кривой. Контрольные точки служат для «оттягивания» кривой от отрезка
прямой, образованной начальной и конечной точками.
Для рисования
Безье-сплайнов используйте метод drawBezier. Этот метод получает в качестве
параметра массив объектов Point. Первые четыре элемента массива задают начальную
точку, две контрольных и конечную точку.
Для рисования
нескольких сплайнов подключают три элемента массива следующего сплайна к последней
точке предыдущего. Конечная точка первого сплайна служит начальной точкой следующего,
а три элемента массива определяют его контрольные точки и конечную точку. В
следующем коде метод drawBezier используется для вывода кривой при каждом изменении
размера окна:
protected void
onPaint(PaintEvent e) {
Point [] pt
= new Point[4];
Rectangle re
= this.getClientRect();
int right =
rc.getRight();
int bottom =
rc.getBottom();
pt[0] = new
Point(right / 4, bottom / 2);
pt[1] = new Point(right / 2, bottom / 4);
pt[2] = new Point(right / 2, 3 * bottom / 4);
pt[3] = new
Point(3 * right / 4, bottom / 2);
e.graphics.drawBezier(pt);
}
protected void
onResi2e(Event e)
{
this.invalidate();
}
Релятивисты и позитивисты утверждают, что "мысленный эксперимент" весьма полезный интрумент для проверки теорий (также возникающих в нашем уме) на непротиворечивость. В этом они обманывают людей, так как любая проверка может осуществляться только независимым от объекта проверки источником. Сам заявитель гипотезы не может быть проверкой своего же заявления, так как причина самого этого заявления есть отсутствие видимых для заявителя противоречий в заявлении.
Это мы видим на примере СТО и ОТО, превратившихся в своеобразный вид религии, управляющей наукой и общественным мнением. Никакое количество фактов, противоречащих им, не может преодолеть формулу Эйнштейна: "Если факт не соответствует теории - измените факт" (В другом варианте " - Факт не соответствует теории? - Тем хуже для факта").
Максимально, на что может претендовать "мысленный эксперимент" - это только на внутреннюю непротиворечивость гипотезы в рамках собственной, часто отнюдь не истинной логики заявителя. Соответсвие практике это не проверяет. Настоящая проверка может состояться только в действительном физическом эксперименте.
Эксперимент на то и эксперимент, что он есть не изощрение мысли, а проверка мысли. Непротиворечивая внутри себя мысль не может сама себя проверить. Это доказано Куртом Гёделем.
Понятие "мысленный эксперимент" придумано специально спекулянтами - релятивистами для шулерской подмены реальной проверки мысли на практике (эксперимента) своим "честным словом". Подробнее читайте в FAQ по эфирной физике.