|
Виды примитивов, система координат, единицы измерений
На этом занятии
рассмотрим основные графические примитивы в wxPython. И прежде чем
что-либо изображать, нужно знать как направлена система координат контекста
устройства. По умолчанию она выглядит так:
То есть, если мы
рисуем линию и указываем координаты:
(10,
100), (50,
200)
то получим
следующий отрезок:
И так для всех
точек и всех графических примитивов. Рассмотрим их подробнее. С двумя из них мы
уже немного познакомились на предыдущем занятии – это:
-
линия – метод DrawLine(self, x1, y1, x2, y2);
-
прямоугольник – метод DrawRectangle(self, x, y, width, height).
И реализуются
они следующим образом:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent, title=title, pos=(0, 0), size=(700, 400))
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, e):
dc = wx.PaintDC(self)
dc.DrawLine(10, 100, 50, 200)
dc.DrawRectangle(50, 10, 200, 100)
app = wx.App()
frame = MyFrame(None, 'wxPython')
frame.Show()
app.MainLoop()
В обработчике
события EVT_PAINT выполняется
прорисовка графических элементов окна в клиентской области.
Помимо этих двух
примитивов, часто используются следующие:
-
DrawArc – дуга;
-
DrawBitmap – картинка;
-
DrawCircle – круг;
-
DrawEllipse – эллипс;
-
DrawPoint – точка;
-
DrawPolygon – полигон
(набор точек, соединенных линиями);
-
DrawSpline
– сплайн;
-
DrawText
– текст.
Полный их список,
а также синтаксис, можно посмотреть на странице:
https://docs.wxpython.org/wx.DC.html
Они достаточно
просты в использовании:
Все это,
например, можно реализовать так:
def OnPaint(self, e):
dc = wx.PaintDC(self)
dc.DrawLine(10, 100, 50, 200)
dc.DrawRectangle(50, 10, 200, 100)
dc.SetFont(wx.Font( wx.FontInfo(16) ))
dc.DrawArc(300, 10, 350, 50, 325, 25); dc.DrawText("Arc", 370, 20)
dc.DrawCircle(320, 150, 50); dc.DrawText("Circle", 300, 140)
dc.DrawEllipse(400, 120, 120, 70); dc.DrawText("Ellipse", 420, 140)
dc.DrawBitmap(wx.Bitmap("brush2.jpg"), 300, 250)
dc.DrawPolygon(((130, 240), (180, 270), (280, 240), (320, 210), (140, 200)))
dc.DrawText("Polygon", 150, 220)
dc.DrawSpline(((440, 270), (480, 270), (485, 210), (525, 210)))
dc.SetPen(wx.Pen('GREEN'))
w, h = self.GetSize()
for i in range(1000):
x = random.randint(1, w - 1)
y = random.randint(1, h - 1)
dc.DrawPoint(x, y)
Вначале рисуем
линию и прямоугольник. Для линии задаем начальные и конечные координаты, а у
прямоугольника координату верхнего левого угла, ширину и высоту. Далее,
устанавливаем размер шрифта для контекста dc в 16 пунктов.
Методом DrawArc рисуем дугу:
указываем начальную, конечную координаты и центр дуги. Затем, вызываем метод DrawText для отображения
текста с начальными координатами (370, 20). Следующий метод DrawCircle рисует круг с
центром (320, 150) и радиусом 50 пикселей. Затем, DrawEllipse отображает эллипс,
вписанный в прямоугольник с координатами (400, 120) и (120, 70). Метод DrawBitmap рисует
изображение brush2.jpg в координатах (300,
250). После этого, рисуем полигон (DrawPolygon) с набором
точек, указанных в кортеже. Последняя и первая точка автоматически замыкаются
линией. Следующий метод DrawSpline рисует ломаную в виде сплайна,
проходящего через указанные координаты. Ну и, наконец, метод DrawPoint рисует
1000 точек со случайными координатами в пределах клиентской области окна. В
результате получаем такие графические элементы:
Положение начала координат
Во всех наших
примерах мы полагали, что начало координат находится в левом верхнем углу.
Однако, при необходимости, мы можем его переместить и расположить в любой
другой точке, например, в центре:
Это делается с
помощью метода:
DC.SetDeviceOrigin(self, x, y)
где x, y – новое
положение начала системы координат. Давайте в качестве примера расположим ее в
центре клиентской области окна и нарисуем линии, исходящие из этого центра по
кругу:
def OnPaint(self, e):
dc = wx.PaintDC(self)
size_x, size_y = self.GetClientSize()
dc.SetDeviceOrigin(size_x // 2, size_y // 2)
radius = math.hypot(size_x / 2, size_y / 2)
angle = 0
while (angle < 2 * math.pi):
x = round(radius * math.cos(angle))
y = round(radius * math.sin(angle))
dc.DrawLine((0, 0), (x, y))
angle = angle + 2 * math.pi / 360
В результате,
получим такое изображение:
Видите, все
линии теперь исходят из центра окна, с начальной координатой всех линий (0, 0).
Это как раз и показывает, что начало координат находится в центре.
Единицы измерения координат
По умолчанию
единицами измерения координат являются пикселы, то есть, наборы точек, которые
и составляют изображение на устройстве. Однако, их количество зависит от
разрешения устройства отображения, например:
-
HD
– 1280 x 720 точек;
-
Full
HD – 1920 x 1080 точек.
Это значит, что
линия в 100 пикселей на разном разрешении будет выглядеть с разным масштабом:
чем более высокое разрешение, тем меньше будет ее визуальная длина. Но, мы
можем это обойти и использовать другие единицы измерений, например, миллиметры.
Для этого нужно вызвать метод:
DC. SetMapMode(mode)
и указать режим
отображения:
-
wx.MM_TEXT
– пикселы;
-
wx.MM_METRIC
– миллиметры;
-
wx.MM_LOMETRIC
– 1/10
миллиметра;
-
wx.MM_POINTS
– пункт (1/72
дюйма);
-
wx.MM_TWIPS – 1/20 пункта
(или 1/1440 дюйма).
Например,
изобразим линию в 10 см в нашем окне. Для этого воспользуемся режимом wx.MM_METRIC
и запишем обработчик OnPaint следующим
образом:
def OnPaint(self, e):
dc = wx.PaintDC(self)
dc.SetMapMode(wx.MM_METRIC)
dc.DrawLine(20, 10, 120, 10)
dc.SetMapMode(wx.MM_TEXT)
dc.DrawBitmap(wx.Bitmap("ruler.jpg"), 30, 40)
Смотрите, здесь
линия по горизонтали составляет 100 единиц, то есть, 100 мм, что равно 10 см.
Ниже отображается линейка в реальном масштабе и, т.к. это просто изображение,
то перед ее рисованием возвращаем режим в пикселы (wx.MM_TEXT). В итоге
получим следующую картину:
Смотрите, наша
линия действительно составляет 10 см. Здесь есть небольшая погрешность,
во-первых, из-за дискретизации изображения по точкам, поэтому абсолютно точно
10 см получено быть не может. И, во-вторых, само изображение линейки тоже имеет
небольшую погрешность. Но, в целом, все очень близко. Причем, длина линии будет
оставаться неизменной при разных разрешениях устройства отображения графической
информации.
Вот так в wxPython выполняется
рисование графических примитивов.
|