Sl-Alex домашняя лаборатория

Руководство по WxWidgets: 10. Контексты устройств

Просмотров: 2252Комментарии: 0
Статьи
Руководство по WxWidgets: 10. Контексты устройств

GDI (интерфейс графических устройств) - это интерфейс для работы с графикой. Он используется для взаимодействия с графическими устройствами, такими как монитор, принтер или файл. GDI позволяет программистам выводить данные на экран или принтер, не беспокоясь о деталях конкретного устройства. GDI изолирует программиста от железа.

Рисунок 10.1: Структура GDI

Рисунок 10.1: Структура GDI

С точки зрения программиста, GDI - это группа классов и методов для работы с графикой. GDI содержит двухмерную векторную графику, шрифты и изображения.

Для начала, мы должны создать объект контекста устройства (DC, Device Context). В wxWidgets контекст устройства называется wxDC. Документация определяет wxDC как контекст устройства, на которое возможен вывод графики и текста. Он представляет номер устройства в общем виде. Одна и та же часть кода может быть написана для различных видов устройств. Будь то экран или принтер. wxDC не предназначен для прямого использования. Вместо этого программист должен выбрать один из производных классов. Каждый такой класс предназначен для использования в конкретных условиях.

Производные классы wxDC:

  • wxBufferedDC (Буферизированный)
  • wxBufferedPaintDC (Буферизированная краска)
  • wxPostScriptDC (ПостСкрипт)
  • wxMemoryDC (Память)
  • wxPrinterDC (Принтер)
  • wxScreenDC (Экран)
  • wxClientDC (Клиент)
  • wxPaintDC (Краска)
  • wxWindowDC (Окно)

wxScreenDC используется для рисования на экране. wxWindowDC используется если нам нужно нарисовать целое окно (только для Windows), включая декорации. wxClientDC используется для прорисовки клиентской области окна. Клиентская область - это часть окна без декораций (заголовок, окантовка). wxPaintDC используется только для wxPaintEvent. wxClientDC напротив никогда не используется для wxPaintEvent. wxMemoryDC используется для рисования графики в растровый рисунок. wxPostScriptDC используется для записи в PostScript файлы на любых платформах. wxPrinterDC используется для получение доступа к принтеру (только в Windows).

Простая линия

Начнём с рисования линии.

line.h
#include <wx/wx.h>
class Line : public wxFrame
{
public:
	Line(const wxString& title);
	void OnPaint(wxPaintEvent& event);
};
line.cpp
#include "line.h"
Line::Line(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(280, 180))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Line::OnPaint));
	this->Centre();
}
void Line::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
  
	wxCoord x1 = 50, y1 = 60;
	wxCoord x2 = 190, y2 = 60;
	dc.DrawLine(x1, y1, x2, y2);
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "line.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Line *line = new Line(wxT("Line"));
	line->Show(true);
	return true;
}

В нашем примере мы нарисовали простую линию в клиентской области окна. Если мы изменяем размеры окна, то рисунок перерисовывается. Генерируется wxPaintEvent и линия перерисовывается снова.

void OnPaint(wxPaintEvent& event);

Здесь мы определяем обработчик события OnPaint().

this->Connect(wxEVT_PAINT, wxPaintEventHandler(Line::OnPaint));

Мы соединили событие paint с методом OnPaint(). Всё рисование происходит в обработчике OnPaint().

wxPaintDC dc(this);

Мы определили контекст устройства wxPaintDC. Этот контекст используется для обращения к окну внутри wxPaintEvent.

wxCoord x1 = 50, y1 = 60;
wxCoord x2 = 190, y2 = 60;

Мы определили четыре координаты.

dc.DrawLine(x1, y1, x2, y2);

Мы рисуем простую линию вызывая метод DrawLine().

Рисунок 10.2: Простая линия

Рисунок 10.2: Простая линия

Рисование текста

Нарисовать текст в окне просто.

text.h
#include <wx/wx.h>
class Text : public wxFrame
{
public:
	Text(const wxString & title);
	void OnPaint(wxPaintEvent & event);
};
text.cpp
#include "text.h"
Text::Text(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 150))
{
	Connect(wxEVT_PAINT, wxPaintEventHandler(Text::OnPaint));
	Centre();
}
void Text::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
	dc.DrawText(wxT("Лев Николaевич Толстoй"), 40, 60);
	dc.DrawText(wxT("Анна Каренина"), 70, 80);
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "text.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Text *text = new Text(wxT("Text"));
	text->Show(true);
	return true;
}

В нашем примере мы рисуем текст Lev Nikolayevich Tolstoy, Anna Karenina русскими буквами в окне.

dc.DrawText(wxT("Лев Николaевич Толстoй"), 40, 60);
dc.DrawText(wxT("Анна Каренина"), 70, 80);

Метод DrawText() рисует текст в окне. Он рисует текстовую строку в указанной точке, используя заданный шрифт, цвет и фон. Благодаря макросу wxT() мы можем использовать русский алфавит прямо в коде. Этот макрос идентичен макросу _T(). Он позволяет использовать строчные литералы из юникода. Когда юникод задействован, он добавляет L к строке литералов делая их расширенными символьными строковыми константами.

Рисунок 10.3: Рисуем текст

Рисунок 10.3: Рисуем текст

Точка

Простейшим графическим объектом является точка. Это просто маленькое кругленькое пятнышко в окне.

DrawPoint(int x, int y)

Этот метод рисует точку с координатами x, y.

point.h
#include <wx/wx.h>
class Points : public wxFrame
{
public:
	Points(const wxString & title);
	void OnPaint(wxPaintEvent & event);
};
points.cpp
#include "points.h"
#include <stdlib.h>
#include <time.h>
Points::Points(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(280, 180))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Points::OnPaint));
	srand(time(NULL));
	this->Centre();
}
void Points::OnPaint(wxPaintEvent & event)
{
	wxPaintDC dc(this);
  
	wxCoord x = 0;
	wxCoord y = 0;
	wxSize size = this->GetSize();
	for (int i = 0; i<1000; i++) {
		x = rand() % size.x + 1;
		y = rand() % size.y + 1;
		dc.DrawPoint(x, y);
	}
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "points.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
    Points *points = new Points(wxT("Points"));
    points->Show(true);
    return true;
}

Одну точку не так то легко увидеть. Поэтому мы создадим 1000 точек. Каждый раз, когда размеры окна будут меняться, мы будет рисовать 1000 точек в клиентской части окна.

wxSize size = this->GetSize();

Здесь мы получили размер окна.

x = rand() % size.x + 1;

Здесь мы получаем случайное число в диапазоне от 1 до size.x.

Рисунок 10.4: Точки

Рисунок 10.4: Точки

Перо

Перо - это элементарный графический объект. Он используется для рисования различных линий и контуров прямоугольников, эллипсов, многоугольников и других форм.

wxPen(const wxColour& colour, int width = 1, int style = wxSOLID)

Конструктор wxPen имеет три параметра. Цвет (colour), ширина (width) и стиль (style). Допустимые стили:

  • wxSOLID (сплошной)
  • wxDOT (пунктир)
  • wxLONG_DASH (длинное тире)
  • wxSHORT_DASH (короткое тире)
  • wxDOT_DASH (точка тире)
  • wxTRANSPARENT (прозрачный)
pen.h
#include <wx/wx.h>
class Pen : public wxFrame
{
public:
	Pen(const wxString& title);
	void OnPaint(wxPaintEvent& event);
};
pen.cpp
#include "pen.h"
Pen::Pen(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(360, 180))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Pen::OnPaint));
	this->Centre();
}
void Pen::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
	wxColour col1, col2;
	col1.Set(wxT("#0c0c0c"));
	col2.Set(wxT("#000000"));
	wxBrush brush(wxColour(255, 255, 255), wxTRANSPARENT);
	dc.SetBrush(brush);
	dc.SetPen(wxPen(col1, 1, wxSOLID));
	dc.DrawRectangle(10, 15, 90, 60);
	dc.SetPen(wxPen(col1, 1, wxDOT));
	dc.DrawRectangle(130, 15, 90, 60);
	dc.SetPen(wxPen(col1, 1, wxLONG_DASH));
	dc.DrawRectangle(250, 15, 90, 60);
	dc.SetPen(wxPen(col1, 1, wxSHORT_DASH));
	dc.DrawRectangle(10, 105, 90, 60);
	dc.SetPen(wxPen(col1, 1, wxDOT_DASH));
	dc.DrawRectangle(130, 105, 90, 60);
	dc.SetPen(wxPen(col1, 1, wxTRANSPARENT));
	dc.DrawRectangle(250, 105, 90, 60);
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "pen.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Pen *pen = new Pen(wxT("Pen"));
	pen->Show(true);
	return true;
}

В нашем примере мы нарисуем 6 прямоугольников перьями различных стилей. Последний прозрачный - его не видно.

dc.SetPen(wxPen(col1, 1, wxSOLID));
dc.DrawRectangle(10, 15, 90, 60);

Здесь мы определили перо для первого прямоугольника. Мы установили цвет col1(#ocococ), ширину в 1 пиксель, стиль - solid. Метод DrawRectangle() рисует прямоугольник.

Рисунок 10.5: Перо

Рисунок 10.5: Перо

Области

Области могут комбинироваться для создания более сложных форм. Существует четыре способа их комбинации: Объединение (Union), Перекрытие (Intersect), Вычитание (Substract) и Исключение (Xor). В следующем примере мы проиллюстрируем все четыре способа.

Regions.h
#include <wx/wx.h>
class Regions : public wxFrame
{
public:
	Regions(const wxString & title);
	void OnPaint(wxPaintEvent & event);
};
Regions.cpp
#include "Regions.h"
Regions::Regions(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 220))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Regions::OnPaint));
	this->Centre();
}
void Regions::OnPaint(wxPaintEvent & event)
{
	wxPaintDC dc(this);
	wxColour gray, white, red, blue;
	wxColour orange, green, brown;
	gray.Set(wxT("#d4d4d4"));
	white.Set(wxT("#ffffff"));
	red.Set(wxT("#ff0000"));
	orange.Set(wxT("#fa8e00"));
	green.Set(wxT("#619e1b"));
	brown.Set(wxT("#715b33"));
	blue.Set(wxT("#0d0060"));
 
	dc.SetPen(wxPen(gray));
	dc.DrawRectangle(20, 20, 50, 50);
	dc.DrawRectangle(30, 40, 50, 50);
	dc.SetBrush(wxBrush(white));
	dc.DrawRectangle(100, 20, 50, 50);
	dc.DrawRectangle(110, 40, 50, 50); 
	wxRegion region1(100, 20, 50, 50);
	wxRegion region2(110, 40, 50, 50);
	region1.Intersect(region2);
	wxRect rect1 = region1.GetBox();
	dc.SetClippingRegion(region1);
	dc.SetBrush(wxBrush(red));
	dc.DrawRectangle(rect1);
	dc.DestroyClippingRegion();
	dc.SetBrush(wxBrush(white));
	dc.DrawRectangle(180, 20, 50, 50);
	dc.DrawRectangle(190, 40, 50, 50);
	wxRegion region3(180, 20, 50, 50);
	wxRegion region4(190, 40, 50, 50);
	region3.Union(region4);
	dc.SetClippingRegion(region3);
	wxRect rect2 = region3.GetBox();
	dc.SetBrush(wxBrush(orange));
	dc.DrawRectangle(rect2);
	dc.DestroyClippingRegion();
	dc.SetBrush(wxBrush(white));
	dc.DrawRectangle(20, 120, 50, 50);
	dc.DrawRectangle(30, 140, 50, 50);
	wxRegion region5(20, 120, 50, 50);
	wxRegion region6(30, 140, 50, 50);
	region5.Xor(region6);
	wxRect rect3 = region5.GetBox();
	dc.SetClippingRegion(region5);
	dc.SetBrush(wxBrush(green));
	dc.DrawRectangle(rect3);
	dc.DestroyClippingRegion();
	dc.SetBrush(wxBrush(white));
	dc.DrawRectangle(100, 120, 50, 50);
	dc.DrawRectangle(110, 140, 50, 50);
	wxRegion region7(100, 120, 50, 50);
	wxRegion region8(110, 140, 50, 50);
	region7.Subtract(region8);
	wxRect rect4 = region7.GetBox();
	dc.SetClippingRegion(region7);
	dc.SetBrush(wxBrush(brown));
	dc.DrawRectangle(rect4);
	dc.DestroyClippingRegion();
	dc.SetBrush(white);
	dc.DrawRectangle(180, 120, 50, 50);
	dc.DrawRectangle(190, 140, 50, 50);
	wxRegion region9(180, 120, 50, 50);
	wxRegion region10(190, 140, 50, 50);
	region10.Subtract(region9);
	wxRect rect5 = region10.GetBox();
	dc.SetClippingRegion(region10);
	dc.SetBrush(wxBrush(blue));
	dc.DrawRectangle(rect5);
	dc.DestroyClippingRegion(); 
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "Regions.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Regions *regions = new Regions(wxT("Regions"));
	regions->Show(true);
	return true;
}

Рисунок 10.6: Области

Рисунок 10.6: Области

Градиент

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

void GradientFillLinear(const wxRect& rect, const wxColour& initialColour, 
	const wxColour& destColour, wxDirection nDirection = wxEAST)

Этот метод заливает область, определённую с помощью rect, линейным градиентом, начиная с initialColour и заканчивая destColour. Параметр nDirection определяет направление изменения цвета, по-умолчанию установлено значение wxEAST.

gradient.h
#include <wx/wx.h>
class Gradient : public wxFrame
{
public:
	Gradient(const wxString& title);
	void OnPaint(wxPaintEvent& event);
};
gradient.cpp
#include "gradient.h"
Gradient::Gradient(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(220, 260))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Gradient::OnPaint));
	this->Centre();
}
void Gradient::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
	wxColour col1, col2;
	col1.Set(wxT("#e12223"));
	col2.Set(wxT("#000000"));
	dc.GradientFillLinear(wxRect(20, 20, 180, 40), col1, col2, wxNORTH);
	dc.GradientFillLinear(wxRect(20, 80, 180, 40), col1, col2, wxSOUTH);
	dc.GradientFillLinear(wxRect(20, 140, 180, 40), col1, col2, wxEAST);
	dc.GradientFillLinear(wxRect(20, 200, 180, 40), col1, col2, wxWEST);  
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "gradient.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Gradient *grad = new Gradient(wxT("Gradient"));
	grad->Show(true);
	return true;
}

Рисунок 10.7: Градиент

Рисунок 10.7: Градиент

Формы

Формы - более сложные геометрические объекты. Мы нарисуем различные геометрические формы в следующем примере.

shapes.h
#include <wx/wx.h>
class Shapes : public wxFrame
{
public:
	Shapes(const wxString & title);
	void OnPaint(wxPaintEvent & event);
};
shapes.cpp
#include "shapes.h"
Shapes::Shapes(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(350, 300))
{
	this->Connect(wxEVT_PAINT, wxPaintEventHandler(Shapes::OnPaint));
	this->Centre();
}
void Shapes::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
 
	wxPoint lines[] = { wxPoint(20, 260), wxPoint(100, 260), 
		wxPoint(20, 210), wxPoint(100, 210) };
	wxPoint polygon[] = { wxPoint(130, 140), wxPoint(180, 170), 
		wxPoint(180, 140), wxPoint(220, 110), wxPoint(140, 100) };
	wxPoint splines[] = { wxPoint(240, 170), wxPoint(280, 170), 
		wxPoint(285, 110), wxPoint(325, 110) };
  
	dc.DrawEllipse(20, 20, 90, 60);
	dc.DrawRoundedRectangle(130, 20, 90, 60, 10);
	dc.DrawArc(240, 40, 340, 40, 290, 20);
	dc.DrawPolygon(4, polygon);
	dc.DrawRectangle(20, 120, 80, 50);
	dc.DrawSpline(4, splines);
	dc.DrawLines(4, lines);
	dc.DrawCircle(170, 230, 35);
	dc.DrawRectangle(250, 200, 60, 60);
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "shapes.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Shapes *shapes = new Shapes(wxT("Shapes"));
	shapes->Show(true);
	return true;
}

Рисунок 10.8: Формы

Рисунок 10.8: Формы

Остальные материалы курса:

Вступление

1. Вспомогательные классы

2. Первые программы

3. Меню и панели инструментов

4. Управление компоновкой

5. События

6. Диалоги

7. Виджеты часть 1

8. Виджеты часть 2

9. Перетаскивание

10. Контексты устройств

11. Самодельные виджеты

12. Тетрис в wxWidgets

Примечание

Оригинал руководства расположен здесь. Автор оригинала - Jan Bodnar.

Перевод (без разметки и картинок) был выполнен пользователем ber113 с сайта translated.by. К сожалению, сайт сейчас не работает.

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