« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга



ПнВтСрЧтПтСбВс
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
    Популярное
Remix 2008: запись репортажа с доклада об Silverlight 2

Создание пользовательских классов

Афоризмы программирования

Постраничный вывод на PHP

Использование Internet-функций Win32 API

Функция AccessResource

Алгоритмы, меняющие последовательность

Создание шрифтов формата BMP для использования в играх! Также постейший фильтр изображений

Глава 13. PHP: Способы передачи данных между отдельными страницами

Неполное спаривание




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 172
Пользователей: 0

Статьи:: WxWidgets :: Разработка собственных компонентов - Оптимизация отрисовки графики



отправить ссылку другу версия для печати  Обсудить на форуме

Разработка собственных компонентов - Оптимизация отрисовки графики

Разработка собственных компонентов - Оптимизация отрисовки графики

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



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

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

Представим себе ситуацию, что мы решили создать свой компонент и уже определились с его функционалом (у нас это будут аналоговые часы). Прежде чем начинать работу над компонентом, неплохо было бы создать небольшое тестовое приложение, которое позволило бы проверить его работоспособность. Ничего сложного мы делать не будем, и создадим обычное GUI-приложение с одной формой:

PaintingTestMainFrame.h
#ifndef _PAINTING_TEST_MAINFRAME_H
#define _PAINTING_TEST_MAINFRAME_H

#include 
#include "wxPaintingTestCtrl.h"

class PaintingTestMainFrame : public wxFrame
{
	void CreateControls();
public:
	PaintingTestMainFrame(wxWindow * parent, wxWindowID id = wxID_ANY,
		const wxString & title = _("Painting Optimization Test"));
	bool Create(wxWindow * parent, wxWindowID id = wxID_ANY,
		const wxString & title = wxEmptyString,
		const wxPoint & pos = wxDefaultPosition,
		const wxSize & size = wxDefaultSize,
		long style = wxCAPTION|wxSYSTEM_MENU|
					 wxMINIMIZE_BOX|wxMAXIMIZE_BOX|wxCLOSE_BOX|
					 wxRAISED_BORDER|wxRESIZE_BORDER);
};

#endif

 

PaintingTestMainFrame.cpp
#include "PaintingTestMainFrame.h"


PaintingTestMainFrame::PaintingTestMainFrame(wxWindow * parent, wxWindowID id, const wxString & title)
{
	Create(parent, id, title);
}

bool PaintingTestMainFrame::Create(wxWindow * parent, wxWindowID id, const wxString & title,
	const wxPoint & pos, const wxSize & size, long style)
{
	bool res = wxFrame::Create(parent, id, title, pos, size, style);
	if(res)
	{
		SetMinSize(wxSize(450, 300));
		CreateControls();
	}
	return res;
}

void PaintingTestMainFrame::CreateControls()
{	
}

 

PaintingTestApp.h
#ifndef _PAINTING_TEST_APP_H
#define _PAINTING_TEST_APP_H

#include 

class PaintingTestApp : public wxApp
{
public:
	virtual bool OnInit();
};

#endif

PaintingTestApp.cpp

#include "PaintingTestApp.h"
#include "PaintingTestMainFrame.h"
#include 

IMPLEMENT_APP(PaintingTestApp);

bool PaintingTestApp::OnInit()
{
	wxImage::AddHandler(new wxPNGHandler);
	PaintingTestMainFrame * frame = new PaintingTestMainFrame(NULL);
	SetTopWindow(frame);
	frame->Centre();
	frame->Show();	
	return true;
}

 

Теперь можно приступать к написанию класса компонента:

wxPaintingTestCtrl.h
#ifndef _WX_PAINTING_TEST_CTRL_H
#define _WX_PAINTING_TEST_CTRL_H

#include 

#ifndef wxPaintingTestCtrlName 
#define wxPaintingTestCtrlName wxT("wxPaintingTestCtrl")
#endif

class wxPaintingTestCtrl : public wxControl
{
protected:
	wxBitmap m_BackgroundBitmap;
	wxBitmap m_CenterBitmap;
	virtual wxSize DoGetBestSize() const;
	void DoDraw(wxDC & dc);
public:
	wxPaintingTestCtrl(wxWindow * parent, wxWindowID id = wxID_ANY,
		const wxBitmap & bitmap = wxNullBitmap,
		const wxPoint & pos = wxDefaultPosition,
		const wxSize & size = wxDefaultSize,
		long style = wxSIMPLE_BORDER,
		const wxString name = wxPaintingTestCtrlName);
	~wxPaintingTestCtrl();
	bool Create(wxWindow * parent, wxWindowID id = wxID_ANY,
		const wxBitmap & bitmap = wxNullBitmap,
		const wxPoint & pos = wxDefaultPosition,
		const wxSize & size = wxDefaultSize,
		long style = wxSIMPLE_BORDER,
		const wxString name = wxPaintingTestCtrlName);

	void SetBackgroundBitmap(wxBitmap & bitmap);
	const wxBitmap & GetBackgroundBitmap();

	void SetCenterBitmap(wxBitmap & bitmap);
	const wxBitmap & GetCenterBitmap();

	DECLARE_EVENT_TABLE()
	void OnPaint(wxPaintEvent & event);
};

 

Класс компонента содержит два объекта класса wxBitmap – первый хранит себе фоновое изображение (m_BackgroundBitmap), а второй – изображение циферблата (m_CenterBitmap).

Метод DoGetBestSize() позволяет переопределить размер компонента по умолчанию (у нас это будет wxSize(100,100), см. ниже)

Get/SetBackgroundBitmap и Get/SetCenterBitmap – это, соответственно, aceessor-методы для фонового изображения и для изображения циферблата

OnPaint – Обработчик события wxEVT_PAINT (отвечает за отрисовку графики)

wxPaintingTestCtrl.cpp
#include "wxPaintingTestCtrl.h"
#include 
#include 
#include 

using namespace std;

BEGIN_EVENT_TABLE(wxPaintingTestCtrl, wxControl)
EVT_PAINT(wxPaintingTestCtrl::OnPaint)
END_EVENT_TABLE()

wxPaintingTestCtrl::wxPaintingTestCtrl(wxWindow * parent, wxWindowID id, const wxBitmap & bitmap,
	const wxPoint & pos, const wxSize & size, long style, const wxString name)
{
	Create(parent, id, bitmap, pos, size, style, name);
}

wxPaintingTestCtrl::~wxPaintingTestCtrl()
{
	
}

bool wxPaintingTestCtrl::Create(wxWindow * parent, wxWindowID id, const wxBitmap & bitmap,
	const wxPoint & pos, const wxSize & size, long style, const wxString name)
{
	bool res = wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name);
	if(res)
	{
		m_BackgroundBitmap = bitmap;		
	}
	return res;
}

wxSize wxPaintingTestCtrl::DoGetBestSize() const
{
	if(m_CenterBitmap.Ok())
	{
		return wxSize(m_CenterBitmap.GetWidth(), m_CenterBitmap.GetHeight());
	}
	return wxSize(100,100);
}

void wxPaintingTestCtrl::SetBackgroundBitmap(wxBitmap & bitmap)
{
	m_BackgroundBitmap = bitmap;
}

const wxBitmap & wxPaintingTestCtrl::GetBackgroundBitmap()
{
	return m_BackgroundBitmap;
}

void wxPaintingTestCtrl::SetCenterBitmap(wxBitmap & bitmap)
{
	m_CenterBitmap = bitmap;
}

const wxBitmap & wxPaintingTestCtrl::GetCenterBitmap()
{
	return m_CenterBitmap;
}

void wxPaintingTestCtrl::OnPaint(wxPaintEvent & event)
{
	wxPaintDC dc(this);
	DoDraw(dc);
}

void wxPaintingTestCtrl::DoDraw(wxDC & dc)
{	
	int x, y, w, h, i;
	double angle;
	GetClientSize(&w, &h);	
	int cx(w/2), cy(h/2), radius(min(cx,cy)-10);	
	if(m_BackgroundBitmap.Ok())
	{		
		for(y = 0; y < h; y += m_BackgroundBitmap.GetHeight())
		{
			for(x = 0; x < w; x += m_BackgroundBitmap.GetWidth())
			{
				dc.DrawBitmap(m_BackgroundBitmap, x, y, true);
			}
		}
	}
	else
	{
		dc.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID));
		dc.Clear();
	}	
	if(m_CenterBitmap.Ok())
	{
		radius = (m_CenterBitmap.GetWidth()/2) * 5.0 / 6.0;
		dc.DrawBitmap(m_CenterBitmap, cx-m_CenterBitmap.GetWidth()/2, 
			cy-m_CenterBitmap.GetHeight()/2, true);
	}
	wxPen linePen(*wxBLACK, 2, wxSOLID);
	dc.SetPen(linePen);
	for(i = 0; i < 12; i++)
	{
		angle = 2.0*3.1415926/12.0*(double)i;
		dc.DrawLine(cx+radius*cos(angle), cy+radius*sin(angle),
			cx+(radius/5.0*4.0)*cos(angle), cy+(radius/5.0*4.0)*sin(angle));
	}
	wxDateTime now = wxDateTime::Now();
	linePen.SetColour(*wxRED);
	linePen.SetWidth(3);
	dc.SetPen(linePen);
	angle = 2.0*3.1415926/12.0*(double)now.GetHour()-3.1415926/2;
	dc.DrawLine(cx, cy, cx+radius*cos(angle), cy+radius*sin(angle));
	linePen.SetWidth(2);
	dc.SetPen(linePen);
	angle = 2.0*3.1415926/60.0*(double)now.GetMinute()-3.1415926/2;
	dc.DrawLine(cx, cy, cx+radius*cos(angle), cy+radius*sin(angle));
	linePen.SetColour(wxColour(0,0,127));
	linePen.SetWidth(1);
	dc.SetPen(linePen);
	angle = 2.0*3.1415926/60.0*(double)now.GetSecond()-3.1415926/2;
	dc.DrawLine(cx, cy, cx+radius*cos(angle), cy+radius*sin(angle));
}

 

Теперь нам нужно добавить наш компонент на форму

PaintingTestMainFrame.h
...
class PaintingTestMainFrame : public wxFrame
{
	wxPaintingTestCtrl * m_TestCtrl1;
	...
public:
	...	
};
...

PaintingTestMainFrame.cpp

...
void PaintingTestMainFrame::CreateControls()
{
	wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
	SetSizer(sizer);	
	wxBitmap background(wxT("background.png"), wxBITMAP_TYPE_PNG);
	wxBitmap center(wxT("center.png"), wxBITMAP_TYPE_PNG);	
	m_TestCtrl1 = new wxPaintingTestCtrl(this, ID_TEST_CTRL1, background);
	m_TestCtrl1->SetCenterBitmap(center);

	sizer->Add(m_TestCtrl1, 1, wxGROW|wxALL, 5);	
}
...

 

Запускаем наше приложение и смотрим
При изменении размеров формы наблюдаем артефакты отрисовки

Для того чтобы убрать эти артефакты, нам необходимо переопределить обработчик события изменения размеров нашего компонента

wxPaintingTestCtrl.h
...
class wxPaintingTestCtrl : public wxControl
{
...
	DECLARE_EVENT_TABLE()
	...	
	void OnSize(wxSizeEvent & event);
};
...

 

wxPaintingTestCtrl.cpp
...
BEGIN_EVENT_TABLE(wxPaintingTestCtrl, wxControl)
...
EVT_SIZE(wxPaintingTestCtrl::OnSize)
END_EVENT_TABLE()
...
void wxPaintingTestCtrl::OnSize(wxSizeEvent & event)
{	
	Refresh();
}
...

 

Отлично. Собираем наше приложение, запускаем. И что мы видим: сильное мерцание при изменении размеров. Но с этой проблемой мы тоже можем довольно легко справиться, сделав небольшие изменения в исходном коде

wxPaintingTestCtrl.h
...
class wxPaintingTestCtrl : public wxControl
{
...
	DECLARE_EVENT_TABLE()
	...	
	void OnEraseBackground(wxEraseEvent & event);
};
...

 

wxPaintingTestCtrl.cpp
...
#include 

BEGIN_EVENT_TABLE(wxPaintingTestCtrl, wxControl)
...
EVT_ERASE_BACKGROUND(wxPaintingTestCtrl::OnEraseBackground)
...
END_EVENT_TABLE()
...
void wxPaintingTestCtrl::OnPaint(wxPaintEvent & event)
{
	wxBufferedPaintDC dc(this);
	DoDraw(dc);
}
...

 

Класс wxBufferedPaintDC обеспечивает doublebuffering при отрисовке, что позволяет избавиться от мерцания.
Пустой обработчик события wxEVT_ERASE_BACKGROUND также позволяет немного ускорить отрисовку.

Собираем приложение, запускаем…. отлично, мерцание исчезло. Но стрелки наших аналоговых часов изменяют положение только при перерисовке содержимого компонента. Это значит, что нам не обходимо добавить таймер, который будет инициировать отрисовку через определенный промежуток времени

wxPaintingTestCtrl.h
...
class wxPaintingTestCtrl : public wxControl
{
protected:
	...
	wxTimer * m_Timer;
	...
	DECLARE_EVENT_TABLE()
	void OnRefreshTimer(wxTimerEvent & event);
};
...

 

wxPaintingTestCtrl.cpp
...

enum
{
	ID_PAINTING_TEST_CTRL_TIMER = 10001
};
...

BEGIN_EVENT_TABLE(wxPaintingTestCtrl, wxControl)
...
EVT_TIMER(ID_PAINTING_TEST_CTRL_TIMER, wxPaintingTestCtrl::OnRefreshTimer)
END_EVENT_TABLE()
...
void wxPaintingTestCtrl::OnRefreshTimer(wxTimerEvent & event)
{
	Refresh();
}

 

Собираем, запускаем.
Отлично. Видно что часы идут. Но на этом работа не заканчивается. Разворачиваем окно программы на весь экран, запускаем Task Manager и начинаем перемещать окно Task Manager над компонентом

В результате получаем загрузку процессора на 100%. Это происходит потому что при каждой перерисовке объект класса wxBufferedPaintDC создает изображение размером с наш компонент, отрисовка производится на это изображение в памяти, а потом это изображение отрисовывается на компонент.
Попробуем сделать так, чтобы наш компонент работал быстрее и не потреблял такое огромное количество ресурсов. Для этого мы попробуем реализовать doublebuffering вручную.
Добавим новуые переменные в класс компонента

wxPaintingTestCtrl.h
...
class wxPaintingTestCtrl : public wxControl
{
protected:
	wxBitmap m_DoubleBuffer;
	wxMemoryDC m_DoubleBufferDC;
	...
};
...

 

wxPaintingTestCtrl.cpp
...
void wxPaintingTestCtrl::OnPaint(wxPaintEvent & event)
{
	wxPaintDC dc(this);
	dc.Blit(0,0, dc.GetSize().GetWidth(), dc.GetSize().GetHeight(), &m_DoubleBufferDC, 0, 0); 
}
...
void wxPaintingTestCtrl::OnSize(wxSizeEvent & event)
{	
	m_DoubleBufferDC.SelectObject(wxNullBitmap);
	m_DoubleBuffer = wxBitmap(event.GetSize().GetWidth(), event.GetSize().GetHeight());
	m_DoubleBufferDC.SelectObject(m_DoubleBuffer);
	DoDraw(m_DoubleBufferDC);
	Refresh();
}

void wxPaintingTestCtrl::OnRefreshTimer(wxTimerEvent & event)
{
	DoDraw(m_DoubleBufferDC);
	Refresh();
}

 

Как видно, при изменении размеров мы пересоздаем изображение, используемое для doublebuffering’а, ассоциируем с ним контекст устройства m_DoubleBuffer и производим отрисовку на изображение в памяти. А в обработчике OnPaint производим копирование из контекста устройства изображения на контекст устройства компонента. В результате загрузка процессора значительно снизилась

Ну и результатом всей нашей работы будет вот такой компонент – аналоговые часы

Хотелось бы заметить, что реализация doublebuffering'а вручную не всегда является самым удачным выбором. Для компонентов, которые будут иметь небольшой размер на форме, можно использовать wxBufferedPaintDC (или даже wxPaintDC если не требуется отрисовка большого количества графических объектов)

Проект для VisualStudio 2005 и wxDev-CPP можно скачать на странице автора статьи.

Источник: http://wxwidgets.info/ Автор: T-Rex




Рубрика: WxWidgets




Подгрузка через AJAX HTML-кода, содержащег....

AJAX

При разработке CMS S.Builder наша команда активно использовала AJAX. Теперь вот решили поделиться накопленным опытом. Начнем с этого хабратопика. Не буду здесь затрагивать различные фреймворки и библиотеки. Свой код всегда роднее. Для работы с AJAX-ом в S.Builder написана библиотека sbAJAX. Можете качать и пользоваться :). В этом файле есть функция sbEvalJS. Для тех, кто не знает, объясню. При подгрузке через AJAX и вставке на страницу HTML-кода, содержащего JavaScript, JavaScript выполняться не будет или полезут баги. Эта функция как раз решает поставленную задачу.


Подробнее... | Рубрика: AJAX | Добавлено: 19.11.2008

Обзор нового релиза самой мощной Ajax библ....

AJAX

Хотя наш обзор немного запоздал, оригинальный Dojo 1.2 вышел в релизной версии ещё 6-го октября, но сейчас мы наверстаем упущенное. И так, Dojo Toolkit — это самая мощная и гибкая ajax-библиотека из всех, что есть на рынке, она активно развивается и имеет большое комьюнити. Кстати, это самое комьюнити, совместно с компанией Sitepen, имеет ещё несколько проектов, среди которых и Cometd и некоторые другие, не менее интересные, о которых мы скоро вам расскажем. Сегодня же все внимание на флагманский продукт — Dojo 1.2.


Подробнее... | Рубрика: AJAX | Добавлено: 19.11.2008

Firebug 1.3 и 1.4 alpha — что нового и инт....

Вебмастеру

Если вы профессиональный веб-разработчик и постоянно имеете дело с разработкой и отладкой сложных AJAX приложений, то наверняка знаете и используете Firebug — плагин для браузера Firefox, предназначенный для отладки и исследования веб-приложений. Текущая его версия, 1.2х достаточно стабильная и функциональна, чтобы помочь в 99% проблем, которые могут возникнуть при разработке. Но и этот инструмент не лишён если не недостатков, то некоторых фич, которые могли бы облегчить работу. И даже идеальный инструмент можно сделать ещё более идеальным, как бы это не звучало.


Подробнее... | Рубрика: Вебмастеру | Добавлено: 19.11.2008

Остальные статьи:

Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...
День программиста — набор стерeотипов
Индусские програмисты
Вышел Django 1.0
Портативная версия Google Chrome Portable
Исходные коды .Net Frameword 3.5 SP1 для о...
Пишем правильный online WYSIWYG-редактор


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия