<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cross-Platform Programming with wxWidgets &#187; Books</title>
	<atom:link href="http://wxwidgets.info/category/books/feed/" rel="self" type="application/rss+xml" />
	<link>http://wxwidgets.info</link>
	<description>Just Make It Cross-Platform</description>
	<lastBuildDate>Tue, 09 Mar 2010 20:50:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава IX &#8211; Написание собственных диалогов &#8211; Часть III</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-iii/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-iii/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 13:57:01 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=514</guid>
		<description><![CDATA[Читать вторую часть главы &#8220;Написание собственных диалогов&#8221;. Дополнительные заметки о дизайне диалогов Несколько советов, которые помогут вашим диалогам выглядеть профессионально выглядящими. Навигация с помощью клавиатуры Указывайте мнемоники для меток со статическим текстом и для других элементов управления с метками. Для этого необходимо поставить перед необходимым символом амперсанд (&#038;). На некоторых платформах (особенно Windows и GTK+) [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-ii/">Читать вторую часть главы &#8220;Написание собственных диалогов&#8221;</a>.</p>
<h4>Дополнительные заметки о дизайне диалогов</h4>
<p>Несколько советов, которые помогут вашим диалогам выглядеть профессионально выглядящими.</p>
<h4>Навигация с помощью клавиатуры</h4>
<p>Указывайте мнемоники для меток со статическим текстом и для других элементов управления с метками. Для этого необходимо поставить перед необходимым символом амперсанд (&#038;). На некоторых платформах (особенно Windows и GTK+) мнемоники помогают пользователю быстро передвигаться между элементами управления.<br />
<span id="more-514"></span><br />
Всегда предоставляйте пользователю возможность закрыть диалог без записи, предпочтительно при помощи нажатия клавиши клавиатуры Escape. Если диалог имеет кнопку с идентификатором <code>wxID_CANCEL</code>, то ее обработчик будет автоматически вызван, если пользователь нажмет клавишу Esc. Поэтому, если у вас на диалоге есть кнопка Close (Закрыть), то разумно дать ей идентификатор <code>wxID_CANCEL</code>.</p>
<p>Указывайте кнопку по умолчанию (обычно &#8220;OK&#8221;), используя метод <code>wxButton::SetDefault</code>. Команда для этой кнопки вызовется, если пользователь нажмет клавишу Enter.</p>
<h4>Отделение интерфейса от данных</h4>
<p>В целях упрощения примера все используемые <code>PersonalRecordDialog</code> данные мы храним внутри диалога. Однако более правильным будет создание отдельного класса данных, который будет отделен от класса диалога. С помощью конструктора копирования и оператора присваивания вы можете передать копию данных в диалог и получить модифицированную копию данных из диалога только если пользователь подтвердил изменения. Это же правило применимо и для некоторых стандартных диалогов. В качестве упражнения вы можете переписать <code>PersonalRecordDialog</code>, чтобы он использовал класс <code>PersonalRecordData</code>. При такой реализации конструктор диалога должен получать ссылку на <code>PersonalRecordData</code>. В диалоге также желательно создать функцию <code>GetData</code>, которую может вызывать приложение, чтобы получить данные из диалога.</p>
<p>Обычно лучше всегда таким образом отделять пользовательский интерфейс от неинтерфейсной функциональности. Результатом будет являться код, который более компактный и легкий для понимания и отладки. Не бойтесь вводить новые классы, чтобы сделать свой код более элегантным. Использование конструктора копирования и оператора присваивания облегчит копирование и присваивание объектов, избавив от повторения больших кусков низкоуровневого кода.</p>
<p>Если в вашем диалоге нет кнопки &#8220;Apply&#8221; (Применить), которая сохраняет ваши изменения, то нажатие на &#8220;Cancel&#8221; должно оставлять данные данные приложения в том же состоянии, как они были до открытия диалога. Использование отдельного класса данных очень легко решает эту задачу, так как диалог редактирует не &#8220;настоящие&#8221; данные, а только их копию.</p>
<h4>Макет</h4>
<p>Если диалог выглядит излишне компактным или сжатым, то можно добавить в него немного пространства. Попробуйте увеличить пространство около границы диалога, используя дополнительные сайзеры (как это сделано в <code>PersonalRecordDialog</code>) и добавив пространство между группами элементов. Рекомендуется использовать <code>wxStaticBoxSizer</code> и <code>wxStaticLine</code>, чтобы логически сгруппировать или разделить элементы управления. Сайзеры <code>wxGridSizer</code> и <code>wxFlexGridSizer</code> позволяют выравнять элементы и их метки так, чтобы у них не появлялся случайный отступ. Для выравнивания групп элементов очень часто используют расширяющиеся спейсеры. Например, кнопки &#8220;OK&#8221;, &#8220;Cancel&#8221; и &#8220;Help&#8221; обычно помещают в отдельную группу, которую выравнивают по правой границе диалога. Этого можно достичь поместив спейсер и кнопки в горизонтальный <code>wxBoxSizer</code> и установив у спейсера расширение по горизонтали (задав положительный коэффициент расширения).</p>
<p>Если это возможно и допустимо &#8211; делайте ваши диалоги с изменяемым размером. Традиционно диалоги в Windows очень редко позволяют изменять свой размер пользователю, однако не существует причины почему это надо запрещать, так как маленькие элементы управления на большом экране могут быть очень неудобными. wxWidgets упрощает создание таких диалогов с помощью сайзеров, поэтому необходимо использовать их везде, что позволит диалогу учитывать текущий шрифт и размер элементов, а также упростит поддержку различных языке. Внимательно выбирайте какие из элементов управления могут расти; например, многострочный элемент редактирования является хорошим кандидатом и при увеличении размера даст пользователю дополнительное место для редактирования. Расширяющиеся спейсеры можно использовать, чтобы реализовать выравнивание в изменяющемся диалоге. Заметим, что не нужно самостоятельно изменять размер элементов управления увеличивая или уменьшая текст в нем, просто давайте больше или меньше пространства элементу управления. Обратитесь к Главе 7 за дополнительной информацией.</p>
<p>Если ваш диалог получается слишком большим &#8211; разбейте его на панели и используйте <code>wxNotebook</code>, <code>wxListbook</code> или <code>wxChoicebook</code>, чтобы можно было работать только с одной из этих панелей. Использование множества независимых диалогов раздражает пользователя и перегружает меню, поэтому использование нескольких панелей более предпочтительно. Вы должны избегать прокручивающихся панелей, пока не появится реальная причина в их использовании. Возможность прокручивания элементов управления поддерживается не на всех платформах, поэтому может оказаться, что диалог выглядит не так как планировалось. Если у вас есть множество свойств для редактирования, то возможно стоит использовать редактор свойств на основе <code>wxGrid</code> или сторонних классов (например, класс <code>wxPropertyGrid</code>, который указан в Приложении E &#8220;Сторонние инструменты для wxWidgets&#8221;).</p>
<h4>Эстетика</h4>
<p>Используйте очень умеренное число меток, записанные заглавными буквами. Не увлекайтесь использованием нестандартных шрифтов и цветов в ваших диалогах, иначе диалог будет выглядеть чужеродным вне текущей темы оформления и сильно отличаться от других диалогов приложения. Для лучшей переносимости между платформами не изменяйте шрифты и цвета диалогов &#8211; пусть оформлением занимается wxWidgets. Если вам необходимо настроить отображение некоторой части диалога, то это лучше сделать через использование wxStaticBitmap.</p>
<h4>Альтернатива диалогам</h4>
<p>Наконец, можно создать независимый диалог, который будет немодальным, такой как вкладка в главном окне приложения. Основная часть принципов построения и реализации диалогов применима к немодальным диалогам и панелям, но появляются дополнительные особенности с размерами (окно имеет меньше контроля над своими размерами) и синхронизацией (окно больше эксклюзивно не владеет данными, которые отображает).</p>
<h4>Использование ресурсных файлов wxWidgets</h4>
<p>Вы можете загружать определения диалогов, фреймов, меню, панелей инструментов и так далее из специальных XML-файлов с расширением xrc, вместо того, чтобы создавать все эти элементы непосредственно с помощью C++. Это позволяет гораздо элегантнее разделить код и пользовательский интерфейс, а также дает возможность поменять дизайн диалогов приложения во время выполнения программы. Файлы XRC могут быть экспортированы во множество инструментов по редактированию пользовательского интерфейса, включая такие как wxDesigner, DialogBlocks, XRCed и wxGlade.</p>
<h4>Загрузка ресурсов</h4>
<p>Чтобы использовать XRC-файлы в вашем приложении вам необходимо включить файл <code>wx/xrc/xmlres.h</code> в код вашего приложения.</p>
<p>Если вы преобразуете свои XRC-файлы в бинарные XRS-файлы (как это сделать будет показано далее), то вам также необходимо включить поддержку файловой системы zip, поместив соответствующий вызов <code>AddHandler</code> в вашу функцию <code>OnInit</code>:</p>
<pre class="brush: cpp;">
#include &quot;wx/filesys.h&quot;
#include &quot;wx/fs_zip.h&quot;

wxFileSystem::AddHandler(new wxZipFSHandler);
</pre>
<p>Далее инициализируем поддержку XRC, добавив следующую строку в <code>OnInit</code>:</p>
<pre class="brush: cpp;">
wxXmlResource::Get()-&gt;InitAllHandlers();
</pre>
<p>XRC-файлы загружаются с помощью следующего кода:</p>
<pre class="brush: cpp;">
wxXmlResource::Get()-&gt;Load(wxT(&quot;resources.xrc&quot;));
</pre>
<p>Данная команда позволит wxWidgets брать ресурсы из этого файла. Для того, чтобы создать реальные элементы управления вам необходимо вызвать другие функции. Например, следующий фрагмент когда создает диалог, чье имя в ресурсах <code>dialog1</code>:</p>
<pre class="brush: cpp;">
MyDialog dlg;
wxXmlResource::Get()-&gt;LoadDialog(&amp;dlg, parent, wxT(&quot;dialog1&quot;));
dlg.ShowModal();
</pre>
<p>Следующий код показывает как загрузить панель меню, пункты<br />
меню, панель инструментов, изображения, иконки и панели из ресурсов:</p>
<pre class="brush: cpp;">
MyFrame::MyFrame(const wxString&amp; title): wxFrame(NULL, -1, title)
{
    SetMenuBar(wxXmlResource::Get()-&gt;LoadMenuBar(wxT(&quot;mainmenu&quot;)));
    SetToolBar(wxXmlResource::Get()-&gt;LoadToolBar(this,
                                                  wxT(&quot;toolbar&quot;)));

    wxMenu* menu = wxXmlResource::Get()-&gt;LoadMenu(wxT(&quot;popupmenu&quot;));

    wxIcon icon = wxXmlResource::Get()-&gt;LoadIcon(wxT(&quot;appicon&quot;));
    SetIcon(icon);

    wxBitmap bitmap = wxXmlResource::Get()-&gt;LoadBitmap(wxT(&quot;bmp1&quot;));

    // Заканчиваем создание panelA и создаем ее экземпляр
    MyPanel* panelA = new MyPanel;
    panelA = wxXmlResource::Get()-&gt;LoadPanel(panelA, this,
                                                       wxT(&quot;panelA&quot;));

    // Второй метод: срузу из XRC создаем и загружаем panelB
    wxPanel* panelB = wxXmlResource::Get()-&gt;LoadPanel(this,
                                                       wxT(&quot;panelB&quot;));
}
</pre>
<p>wxWidgets содержит один глобальный объект <code>wxXmlResource</code>, который вы можете использовать, но также можете самостоятельно создать объект <code>wxXmlResource</code>, загрузить ресурсы, а после уничтожить его. Вы также можете вызвать <code>wxXmlResource::Set</code>, чтобы установить новый глобальный объект, уничтожив старый.</p>
<p>Чтобы определить таблицу сообщений для окна, загруженного из ресурсного файла, вы не можете использовать целочисленные идентификаторы, так как ресурсы имеют строковое представление. Вместо этого вы должны использовать макрос XRCID, который принимает в качестве параметра имя ресурса и возвращает целочисленный идентификатор, ассоциированный с этим именем. XRCID является просто синонимом функции <code>wxXmlResource::GetXRCID</code>. Вот пример использования XRCID:</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(XRCID(&quot;menu_quit&quot;),  MyFrame::OnQuit)
    EVT_MENU(XRCID(&quot;menu_about&quot;), MyFrame::OnAbout)
END_EVENT_TABLE()
</pre>
<h4>Использование бинарных и встраиваемых ресурсных файлов</h4>
<p>Очень часто удобнее скомбинировать несколько ресурсных файлов в один бинарный файл (с расширением xrs). Чтобы скомпилировать XRC-файлы в один zip-файл из которого можно загружать ресурсы используйте утилиту wxrc, расположенную в каталоге utils/wxrc вашего дистрибутива wxWidgets:</p>
<pre class="brush: cpp;">
wxrc resource1.xrc resource2.xrc -o resource.xrs
</pre>
<p>Метод <code>wxXmlResource::Load</code> позволяет загрузить бинарный файл, абсолютно также как и в случае с обычными ресурсами.</p>
<p>Совет: вместо создания отдельного zip-файла с вашими ресурсными файлами, вы можете включить их в один zip-файл, который включает другие файлы, необходимые вашему приложению, такие как HTML-файлы, изображения и так далее. <code>wxXmlResource::Load</code> принимает спецификатор виртуальной файловой системы, как будет описано в Главе 14 &#8220;Файлы и потоки&#8221;, поэтому вы можете написать:</p>
<pre class="brush: cpp;">
wxXmlResource::Get()-&gt;Load(wxT(&quot;resources.bin#zip:dialogs.xrc&quot;));
</pre>
<p>Также можно скомпилировать ваши XRC-файлы в C++ код, который можно встроить в ваше приложение, чтобы исключить возможность переноса ресурсных файлов в неправильное место. Для этого надо сделать следующее:</p>
<pre class="brush: cpp;">
wxrc resource1.xrc resource2.xrc c -o resource.cpp
</pre>
<p>Далее скомпилируйте этот файл как обычный C++ файл и прилинкуйте к вашему приложению. Файл включает функцию <code>InitXmlResource</code>, которую вам необходимо вызвать. Например,</p>
<pre class="brush: cpp;">
extern void InitXmlResource(); // определена в сгенерированом файле
wxXmlResource::Get()-&gt;InitAllHandlers();
InitXmlResource();
</pre>
<p>Таблица содержит аргументы и опции командной строки для программы wxrc.</p>
<ul>
<li>-h (&#8211;help) &#8211; Показывает помощь.</li>
<li>-v (&#8211;verbose) &#8211; Включает подробную информацию о работе.</li>
<li>-c (&#8211;cpp-code) &#8211; Генерирует исходники C++, вместо XRS-файла.</li>
<li>-p (&#8211;python-code) &#8211; Генерирует исходники Python, вместо XRS-файла.</li>
<li>-e (&#8211;extra-cpp-code) &#8211; Если используется совместно с командой -c, генерирует заголовочный файл C++, содержащий определение для окон, содержащихся в XRC-файле.</li>
<li>-u (&#8211;uncompressed) &#8211; Не сжимать XML файлы (только для C++).</li>
<li>-g (&#8211;gettext) &#8211; Выводит все строки с подчеркиваниями, чтобы poEdit или gettext смогли их просканировать. Вывод производится в stdout или файл, если задан ключ -o.</li>
<li>-n (&#8211;function <имя>) &#8211; Определяет функцию инициализации для C++ (используется совместно с -c)</li>
<li>-o <имя_файла> (&#8211;output <имя_файла>) &#8211; Определяет файл вывода, такой как resource.xrs или resource.cpp.</li>
<li>-l <имя_файла> (&#8211;list-of-handlers <имя_файла>) &#8211; Выводит список обработчиков ресурсов, необходимых для заданных файлов.</li>
</ul>
<h4>Перевод ресурсов</h4>
<p>Если объект <code>wxXmlResource</code> создан с флагом <code>wxXRC_USE_LOCALE</code> (это поведение по умолчанию), то все отображаемые строки являются объектами перевода, как это описано в Главе 16 &#8220;Написание многоязыковых приложений&#8221;. Однако poEdit не может просканировать XRC-файлы, чтобы выбрать строки для перевода, как это можно сделать с программой на C++ , поэтому вам необходимо создать файл, содержащий такие строки, используя опцию -g. Например:</p>
<pre class="brush: cpp;">
wxrc -g resources.xrc -o resource_strings.cpp
</pre>
<p>Теперь вы можете запустить poEdit, чтобы найти все строки в этом и других файлах.</p>
<h4>Формат XRC-файлов</h4>
<p>Так как формат книги не позволяет подробно рассмотреть формат XRC-файлов, то дальше просто приводится пример маленького диалога с сайзерами:</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;resource version=&quot;2.3.0.1&quot;&gt;
&lt;object class=&quot;wxDialog&quot; name=&quot;simpledlg&quot;&gt;
    &lt;title&gt;A simple dialog&lt;/title&gt;
    &lt;object class=&quot;wxBoxSizer&quot;&gt;
      &lt;orient&gt;wxVERTICAL&lt;/orient&gt;
      &lt;object class=&quot;sizeritem&quot;&gt;
        &lt;object class=&quot;wxTextCtrl&quot;&gt;
          &lt;size&gt;200,200d&lt;/size&gt;
          &lt;style&gt;wxTE_MULTILINE|wxSUNKEN_BORDER&lt;/style&gt;
          &lt;value&gt;Hello, this is an ordinary multilinen textctrl....&lt;/value&gt;
        &lt;/object&gt;
        &lt;option&gt;1&lt;/option&gt;
        &lt;flag&gt;wxEXPAND|wxALL&lt;/flag&gt;
        &lt;border&gt;10&lt;/border&gt;
      &lt;/object&gt;
      &lt;object class=&quot;sizeritem&quot;&gt;
        &lt;object class=&quot;wxBoxSizer&quot;&gt;
          &lt;object class=&quot;sizeritem&quot;&gt;
            &lt;object class=&quot;wxButton&quot; name=&quot;wxID_OK&quot;&gt;
              &lt;label&gt;Ok&lt;/label&gt;
              &lt;default&gt;1&lt;/default&gt;
            &lt;/object&gt;
          &lt;/object&gt;
          &lt;object class=&quot;sizeritem&quot;&gt;
            &lt;object class=&quot;wxButton&quot; name=&quot;wxID_CANCEL&quot;&gt;
              &lt;label&gt;Cancel&lt;/label&gt;
            &lt;/object&gt;
            &lt;border&gt;10&lt;/border&gt;
            &lt;flag&gt;wxLEFT&lt;/flag&gt;
          &lt;/object&gt;
        &lt;/object&gt;
        &lt;flag&gt;wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_RIGHT&lt;/flag&gt;
        &lt;border&gt;10&lt;/border&gt;
      &lt;/object&gt;
    &lt;/object&gt;
  &lt;/object&gt;
&lt;/resource&gt;
</pre>
<p>Детальную спецификация формата XRC можно найти в технических замечаниях в файле <code>docs/tech/tn0014.txt</code> вашего дистрибутива wxWidgets. Если вы используете какой-нибудь редактор для пользовательского интерфейса, то вам не нужно знать о формате XRC.</p>
<p>Вам может быть интересно как можно использовать текстовые XRC-файлы, чтобы поместить в них изображения и иконки. Эти ресурсы необходимо определить как URL, а механизм виртуальных файловых систем извлечет их из необходимого источника, такого как zip-файл. Например:</p>
<pre class="brush: xml;">
&lt;object class=&quot;wxBitmapButton&quot; name=&quot;wxID_OK&quot;&gt;
  &lt;bitmap&gt;resources.bin#zip:okimage.png&lt;/bitmap&gt;
&lt;/object&gt;
</pre>
<p>Обратитесь к Главе 10 &#8220;Работа с изображениями&#8221; и Главе 14 &#8220;Файлы и потоки&#8221; за детальной информацией об использовании виртуальных файловых систем для загрузки ресурсов, таких как изображения.</p>
<h4>Определение обработчика ресурсов</h4>
<p>Система XRC использует обработчики ресурсов, чтобы опознать определения XML для каждого типа ресурсов. Если вы напишите ваш собственный элемент управления, то вы возможно захотите написать такой обработчик, чтобы иметь возможность загружать ваш элемент управления из XRC.</p>
<p>Для иллюстрации посмотрим как реализован обработчик ресурсов для стандартного класса <code>wxButton</code>:</p>
<pre class="brush: cpp;">
#include &quot;wx/xrc/xmlres.h&quot;

class wxButtonXmlHandler : public wxXmlResourceHandler
{
DECLARE_DYNAMIC_CLASS(wxButtonXmlHandler)
public:
    wxButtonXmlHandler();
    virtual wxObject *DoCreateResource();
    virtual bool CanHandle(wxXmlNode *node);
};
</pre>
<p>Реализация обработчика достаточно простая. В конструкторе обработчика вы, используя макрос <code>XRC_ADD_STYLE</code>, добавляете стили, которые должна поддерживать кнопка, а в конце вызываете <code>AddWindowStyles</code>, чтобы добавить стандартные стили для окон. В методе <code>DoCreateResource</code> объект-кнопка создается в два шага, используя <code>XRC_MAKE_INSTANCE</code> и <code>Create</code>, извлекая параметры, такие как метка, положение и размер. И, наконец, <code>CanHandle</code> проверяет может ли обработчик обработать узел, который ему передали. Последняя возможность позволяет в одном обработчике реализовать обработку нескольких типов ресурсов.</p>
<pre class="brush: cpp;">
IMPLEMENT_DYNAMIC_CLASS(wxButtonXmlHandler, wxXmlResourceHandler)

wxButtonXmlHandler::wxButtonXmlHandler()
: wxXmlResourceHandler()
{
    XRC_ADD_STYLE(wxBU_LEFT);
    XRC_ADD_STYLE(wxBU_RIGHT);
    XRC_ADD_STYLE(wxBU_TOP);
    XRC_ADD_STYLE(wxBU_BOTTOM);
    XRC_ADD_STYLE(wxBU_EXACTFIT);
    AddWindowStyles();
}

wxObject *wxButtonXmlHandler::DoCreateResource()
{
   XRC_MAKE_INSTANCE(button, wxButton)

   button-&gt;Create(m_parentAsWindow,
                    GetID(),
                    GetText(wxT(&quot;label&quot;)),
                    GetPosition(), GetSize(),
                    GetStyle(),
                    wxDefaultValidator,
                    GetName());

    if (GetBool(wxT(&quot;default&quot;), 0))
        button-&gt;SetDefault();
    SetupWindow(button);

    return button;
}

bool wxButtonXmlHandler::CanHandle(wxXmlNode *node)
{
    return IsOfClass(node, wxT(&quot;wxButton&quot;));
}
</pre>
<p>Чтобы использовать обработчик приложение должно включить заголовочный файл и зарегистрировать обработчик, как показано ниже:</p>
<pre class="brush: cpp;">
#include &quot;wx/xrc/xh_bttn.h&quot;
wxXmlResource::AddHandler(new wxBitmapXmlHandler);
</pre>
<h4>Сторонние элементы управления</h4>
<p>XRC-файл может определить сторонние, или &#8220;неизвестные&#8221; элементы управления, указав <code>class="unknown"</code> в определении объекта. Вы можете использовать такую возможность для элементов управления, которые создаются с помощью кода C++, после того как их родительское окно будет загружено из XRC. После того, как XRC загрузит сторонний объект создается окно, которое помещается на место данного объекта. Далее приложение вызывает <code>AttachUnknownControl</code> для помещения реального окна в окно, созданное на прошлом шаге с правильными размерами и расположением. Например,</p>
<pre class="brush: cpp;">
wxDialog dlg;

// Загружаем диалог
wxXmlResource::Get()-&gt;LoadDialog(&amp;dlg, this, wxT(&quot;mydialog&quot;));

// Создаем экземпляр нашего элемента управления
MyCtrl* myCtrl = new MyCtrl(&amp;dlg, wxID_ANY);

// Добавляем его к диалогу
wxXmlResource::Get()-&gt;AttachUnknownControl(wxT(&quot;custctrl&quot;), myCtrl);

// Показываем диалог
dlg.ShowModal();
</pre>
<p>Определение стороннего элемента управления может выглядеть следующим образом:</p>
<pre class="brush: cpp;">
&lt;object class=&quot;unknown&quot; name=&quot;custctrl&quot;&gt;
  &lt;size&gt;100,100&lt;/size&gt;
&lt;/object&gt;
</pre>
<p>Используя данную технологию вы можете поместить элемент в утилиту редактирования интерфейса, которая ничего не знает про ваш элемент управления, а также избежите необходимости писать свой обработчик ресурсов.</p>
<h4>Итоги</h4>
<p>В этой главе мы изучили основные принципы проектирования и реализации диалогов, включая краткое описание сайзеров, валидаторов и преимущества использования событий об обновлении интерфейса. Примеры создания диалогов смотрите в каталоге samples/dialogs вашего дистрибутива wxWidgets. Также в каталоге samples/validate есть пример использования валидаторов. В следующей главе будет рассказано о работе с изображениями.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-iii/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава IX &#8211; Написание собственных диалогов &#8211; Часть II</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-ii/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-ii/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 13:09:38 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=510</guid>
		<description><![CDATA[Читать первую часть главы &#8220;Написание собственных диалогов&#8221;. Добавление помощи Существует по крайней мере три пути как можно реализовать помощь для вашего диалога: Всплывающие подсказки Контекстная помощь Справочная система Кроме того у нас уже есть некоторый текст на самой панели диалога. Возможно вы захотите также использовать другие технологии, явно не поддерживаемые в wxWidgets. Например, для более [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-i/">Читать первую часть главы &#8220;Написание собственных диалогов&#8221;</a>.</p>
<h4>Добавление помощи</h4>
<p>Существует по крайней мере три пути как можно реализовать помощь для вашего диалога:</p>
<ul>
<li> Всплывающие подсказки</li>
<li> Контекстная помощь</li>
<li> Справочная система</li>
</ul>
<p>Кроме того у нас уже есть некоторый текст на самой панели диалога. Возможно вы захотите также использовать другие технологии, явно не поддерживаемые в wxWidgets. Например, для более сложных диалогов вы можете создать <code>wxHtmlWindow</code> вместо <code>wxStaticText</code> и загрузить в него HTML-файл, содержащий необходимое описание. В качестве альтернативы вы можете поместить маленькую кнопку помощи справа от каждого элемента управления, при нажатии на которую выводился бы некоторый текст с описанием.<br />
<span id="more-510"></span><br />
Три основных типа помощи, поддерживаемые в wxWidgets, описаны далее.</p>
<h4>Всплывающие подсказки</h4>
<p>Всплывающие подсказки &#8211; это маленькие окна, содержащие короткое описание данного элемента управления, которые всплывают, когда указатель находится над элементом управления некоторое время. С помощью <code>SetToolTip</code> можно установить подсказку для элемента управления. Так как эти окна могут раздражать продвинутых пользователей, то в приложении должна быть возможность отключить их (для этого не нужно вызывать <code>SetToolTip</code> при создании или показе диалога).</p>
<h4>Контекстная помощь</h4>
<p>Контекстная помощь выглядит как небольшое выскакивающее описание, похожее на всплывающие подсказки. Пользователю необходимо сначала нажать на специальную кнопку, а после на элемент управления о котором он хочет узнать или нажать F1, чтобы узнать информацию об элементе на котором в данный момент находится фокус (последнее работает только в системе Windows). В Windows вы можете также определить специальный стиль окна <code>wxDIALOG_EX_CONTEXTHELP</code>, чтобы создать маленькую иконку со знаком вопроса в заголовке окна. На других платформах вы можете создать <code>wxContextHelpButton</code> в диалоге (обычно ее располагают рядом с кнопками &#8220;OK&#8221; и &#8220;Cancel&#8221;). В вашем приложении вы должны написать:</p>
<pre class="brush: cpp;">
#include &quot;wx/cshelp.h&quot;
...
    wxHelpProvider::Set(new wxSimpleHelpProvider);
...
</pre>
<p>Этот фрагмент кода указывает библиотеке, что необходимо предоставлять строки для поддержки контекстной помощи. Вы можете вызвать <code>SetHelpText</code>, чтобы установить текста помощи для элемента. Напишем функцию, которая настраивает контекстную помощь и всплывающие подсказки в нашем диалоге: </p>
<pre class="brush: cpp;">
// Устанавливаем текст помощи для элементов диалога
void PersonalRecordDialog::SetDialogHelp()
{
    wxString nameHelp = wxT(&quot;Enter your full name.&quot;);
    wxString ageHelp = wxT(&quot;Specify your age.&quot;);
    wxString sexHelp = wxT(&quot;Specify your gender, male or female.&quot;);
    wxString voteHelp = wxT(&quot;Check this if you wish to vote.&quot;);

    FindWindow(ID_NAME)-&gt;SetHelpText(nameHelp);
    FindWindow(ID_NAME)-&gt;SetToolTip(nameHelp);

    FindWindow(ID_AGE)-&gt;SetHelpText(ageHelp);
    FindWindow(ID_AGE)-&gt;SetToolTip(ageHelp);

    FindWindow(ID_SEX)-&gt;SetHelpText(sexHelp);
    FindWindow(ID_SEX)-&gt;SetToolTip(sexHelp);

    FindWindow(ID_VOTE)-&gt;SetHelpText(voteHelp);
    FindWindow(ID_VOTE)-&gt;SetToolTip(voteHelp);
}
</pre>
<p>Если вы хотите реализовать контекстную помощь самостоятельно, позволив диалогу или <code>wxContextHelpButton</code> перехватывать соответствующие запросы, то можно просто написать в обработчике событий:</p>
<pre class="brush: cpp;">
wxContextHelp contextHelp(window);
</pre>
<p>Данная команда добавляет дополнительный цикл, который обнаруживает нажатие левой клавиши мыши на элементе управления, после чего посылает сообщение <code>wxEVT_HELP</code> элементу, чтобы инициировать показ контекстной помощи для данного элемента.</p>
<p>Однако вы не обязаны ограничивать себя только возможностями, заложенными в wxWidgets для хранения и показа текста помощи. Вы можете создать свой собственный класс-наследник от <code>wxHelpProvider</code> и реализовать методы <code>GetHelp</code>, <code>SetHelp</code>, <code>AddHelp</code>, <code>RemoveHelp</code> и <code>ShowHelp</code>.</p>
<h4>Справочная система</h4>
<p>Большая часть приложений поставляется с файлом помощи, в котором находятся детальные инструкции по использованию программы. В wxWidgets для этого есть элементы управления нескольких типов, которые являются наследниками от <code>wxHelpControllerBase</code>. Обратитесь к Главе 20 &#8220;Усовершенствование ваших приложений&#8221;, за более детальной информацией о том, как реализовать такого вида помощь.</p>
<p>В нашем примере мы просто используем <code>wxMessageBox</code>, чтобы вывести некоторое сообщение, когда пользователь нажмет на кнопку &#8220;Help&#8221; (Помощь).</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE( PersonalRecordDialog, wxDialog )
    ...
    EVT_BUTTON( wxID_HELP, PersonalRecordDialog::OnHelpClick )
    ...
END_EVENT_TABLE()

void PersonalRecordDialog::OnHelpClick( wxCommandEvent&amp; event )
{
    // В нормальном приложении мы должны вывести соответствующий раздел помощи
    /*
    wxGetApp().GetHelpController().DisplaySection(wxT(&quot;Personal record dialog&quot;));
    */

    // В нашем примере мы просто выводим окно с сообщением
    wxString helpText =
      wxT(&quot;Please enter your full name, age and gender.\n&quot;)
      wxT(&quot;Also indicate your willingness to vote in general elections.\n\n&quot;)
      wxT(&quot;No non-alphabetical characters are allowed in the name field.\n&quot;)
      wxT(&quot;Try to be honest about your age.&quot;);

    wxMessageBox(helpText,
        wxT(&quot;Personal Record Dialog Help&quot;),
        wxOK|wxICON_INFORMATION, this);
}
</pre>
<h4>Полная реализация класса</h4>
<p>Полная реализация класса приводится в приложении J &#8220;Исходники&#8221;, а также в каталоге examples/chap09 на нашем CD-ROM.</p>
<h4>Вызов диалога</h4>
<p>Теперь, когда диалог поностью закончен, мы можем его вызвать:</p>
<pre class="brush: cpp;">
PersonalRecordDialog dialog(NULL, ID_PERSONAL_RECORD,
    wxT(&quot;Personal Record&quot;));
dialog.SetName(wxEmptyString);
dialog.SetAge(30);
dialog.SetSex(0);
dialog.SetVote(true);
if (dialog.ShowModal() == wxID_OK)
{
    wxString name = dialog.GetName();
    int age = dialog.GetAge();
    bool sex = dialog.GetSex();
    bool vote = dialog.GetVote();
}
</pre>
<h4>Адаптация диалогов для портативных устройств</h4>
<p>wxWidgets можно использовать для мобильных и других встраиваемых устройств, используя для этого порты GTK+, X11 и Windows CE (или иные в будущем). Самым важной особенностью таких устройств является ограниченный размер экрана, который для некоторых смартфонов может быть не больше 176&#215;220 пикселей.</p>
<p>Многие диалоги нуждаются в альтернативном (адаптированном для маленьких экранов) размещении элементов, а некоторые элементы управления могут быть объеденены или удалены, особенно в связи с тем, что мобильные версии более ограниченны по сравнению с их десктопными версиями. С помощью метода <code>wxSystemSettings::GetScreenType</code> можно получить полный размер экрана. Например:</p>
<pre class="brush: cpp;">
#include &quot;wx/settings.h&quot;
bool isPda = (wxSystemSettings::GetScreenType() &lt;= wxSYS_SCREEN_PDA);
</pre>
<p><code>GetScreenType</code> возвращает одно из значений, указанных в таблице. Так как целочисленное значение типа растет вместе с величиной экрана, то вы можете использовать оператор целочисленного сравнения, чтобы ограничить работоспособность программы на некоторых платформах, как это сделано, например, в нашем прошлом примере.</p>
<ul>
<li><code>wxSYS_SCREEN_NONE</code> &#8211; Неизвестный тип экрана</li>
<li><code>wxSYS_SCREEN_TINY</code> &#8211; Миниатюрный экран, менее 320&#215;240</li>
<li><code>wxSYS_SCREEN_PDA</code> &#8211; Экран наладонника, 320&#215;240 или больше, но менее 640&#215;480</li>
<li><code>wxSYS_SCREEN_SMALL</code> &#8211; Маленький экран, 640&#215;480 или больше, но менее 800&#215;600</li>
<li><code>wxSYS_SCREEN_DESKTOP</code> &#8211; Обычный экран, 800&#215;600 или больше</li>
</ul>
<p>Если вам необходимо получить точный размер экрана, то существует три способа получить его:</p>
<ul>
<li>Использовать функцию wxSystemSettings::GetMetric[i], передав ей [i]wxSYS_SCREEN_X или wxSYS_SCREEN_Y.</li>
<li>Вызвать wxGetDisplaySize, которая возвратит объект типа wxSize.</li>
<li>Создать объект wxDisplay и вызвать метод GetGeometry, который возвратит wxRect, содержащий координаты прямоугольника для дисплея.</li>
</ul>
<p>Теперь, когда вы умеете получать размер экрана, как можно использовать эту информацию? Вот несколько стратегий, которые можно использовать:</p>
<ul>
<li>Заменить весь макет диалога с помощью его загрузки из другого XRC-файла или выполнения другой процедуры создания. Если у элементов не изменится тип, то вам даже не понадобится менять обработчик событий.</li>
<li>Уменьшить число элементов управления и расстоянием между ними.</li>
<li>Изменить тип некоторых элементов управления, чтобы они занимали на экране меньше места (например, с wxListBox в wxComboBox). Это потребует некоторой модификации кода обработчиков событий.</li>
<li>Изменить ориентацию одного или нескольких сайзеров. Некоторые портативные устройства имеют гораздо больше пространства в одном направлении, чем в другом.</li>
</ul>
<p>Кроме того вам необходимо использовать расширения API для некоторых платформ. Смартфоны Microsoft имею две специальные кнопки, которым можно присвоить некоторые метки, такие как &#8220;OK&#8221; и &#8220;Cancel&#8221;. На таких платформах вместо создания двух объектов типа wxButton вы должны вызвать <code>wxDialog::SetLeftMenu</code> и <code>wxDialog::SetRightMenu</code> с соответствующим идентификатором, меткой и, возможно, меню. Так как эти функции имеются только в портах для смартфонов, то необходимо добавить операторы включения в ваш код. Например:</p>
<pre class="brush: cpp;">
#ifdef __SMARTPHONE__
    SetLeftMenu(wxID_OK, wxT(&quot;OK&quot;));
    SetRightMenu(wxID_OK, wxT(&quot;Cancel&quot;));
#else
    wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
    GetTopSizer()-&gt;Add(buttonSizer, 0, wxALL|wxGROW, 0);
    buttonSizer-&gt;Add(new wxButton(this, wxID_OK), 0, wxALL, 5);
    buttonSizer-&gt;Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 5);
#endif
</pre>
<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-iii/">Читать третью часть главы &#8220;Написание собственных диалогов&#8221;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-ii/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава IX &#8211; Написание собственных диалогов &#8211; Часть I</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-i/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-i/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 12:47:37 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=508</guid>
		<description><![CDATA[Скачать PDF-версию (342 КБ) Рано или поздно вам понадобится создать собственный диалог, будь то простой диалог, состоящий из текста и нескольких кнопок, или сложный диалог с вкладками, множеством панелей, собственными элементами управления, контекстной помощью и т.п. В этой главе мы рассмотрим основные принципы создания диалогов, а также передачу данных между переменными C++ и элементами управления. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://depositfiles.com/files/rp8jf72lt" title="Скачать PDF: Перевод книги Julian’а Smart’а - Глава IX - Написание собственных диалогов">Скачать PDF-версию (342 КБ)</a></p>
<p>Рано или поздно вам понадобится создать собственный диалог, будь то простой диалог, состоящий из текста и нескольких кнопок, или сложный диалог с вкладками, множеством панелей, собственными элементами управления, контекстной помощью и т.п. В этой главе мы рассмотрим основные принципы создания диалогов, а также передачу данных между переменными C++ и элементами управления. Также будет рассказано об использовании ресурсов, которые позволяют загружать диалоги и другие элементы интерфейса из XML-файлов.<br />
<span id="more-508"></span></p>
<h4>Шаги для создания собственных диалогов</h4>
<p>Самое интересное программирование начинается, когда вы начнете создавать свои собственные диалоги. Вот список шагов, которые необходимо для этого сделать:</p>
<ol type="1">
<li> Создать наследника от <code>wxDialog</code>.</li>
<li> Решить, где будут храниться данные диалога и как приложение получит к ним доступ.</li>
<li> Написать код создания и размещения элементов управления.</li>
<li> Добавить код, отвечающий за пересылку данных между данными диалога и элементами управления.</li>
<li> Написать обработчики событий от элементов управления.</li>
<li> Добавить обработку обновления пользовательского интерфейса, чтобы элементы управления всегда были в правильном состоянии.</li>
<li> Добавить помощь, в частности всплывающие подсказки, контекстную помощь (данная возможность не реализована в Mac OS X) и справочную систему.</li>
<li> Вызвать диалог из подходящего места вашего приложения.</li>
</ol>
<p>Проиллюстрируем указанные шаги на конкретном примере.</p>
<h4>Пример: PersonalRecordDialog</h4>
<p>Как вы знаете из прошлой главы диалоги бывают двух видов: модальные и не модальные. Мы будем делать модальный диалог, так как это более распространенный и менее сложный в реализации тип. Приложение вызывает диалог с помощью <code>ShowModal</code>, а далее получает из диалога выбор пользователя. До того как <code>ShowModal</code> возвратит результат все взаимодействие с пользователем заключено в маленький мир внутри вашего диалога (и любых других модальных диалогов, которые ваш диалог может вызвать).</p>
<p>Многие шаги по созданию собственного диалога можно очень легко выполнить с использованием редакторов диалогов, таких как wxDesigner или DialogBlocks. С их помощью, в зависимости от сложности диалога, можно в автоматическом режиме выполнить очень большой объем работы по написанию кода. В этой главе исключительно для демонстрации базовых принципов мы все будем все делать вручную. Однако в реальной работе рекомендуется использовать такого рода инструменты для экономии кучи часов повторяющейся работы.</p>
<p>Мы проиллюстрируем шаги, необходимые для создания диалога с помощью диалога в котором пользователь вводит свое имя, возраст, пол и хочет ли он проголосовать. Диалог называется <code>PersonalRecordDialog</code> и показан на рисунке.</p>
<p><рисунок пропущен></p>
<p>Кнопка &#8220;Reset&#8221; (Сброс) устанавливает значение всех элементов управления в их начальные значения. Кнопка &#8220;OK&#8221; закрывает диалог и возвращает <code>wxID_OK</code> из <code>ShowModal</code>. Кнопка &#8220;Cancel&#8221; возвращает <code>wxID_CANCEL</code> и не обновляет содержимое переменных диалога. Кнопка &#8220;Help&#8221; (Помощь) выводит несколько строк с описанием диалога, (хотя в реальном приложении эта кнопка должна вызывать полноценную страницу помощи в справочной системе).</p>
<p>Хороший пользовательский интерфейс не должен позволять пользователю вводить данные, которые не имеют значения в текущей ситуации. Например, пользователь не должен иметь возможность использовать элемент управления &#8220;Vote&#8221; (Голосовать), если его возраст меньше чем допустимый для голосования возраст (18 лет для США или Великобритании). Поэтому необходимо убедиться, что при возрасте менее 18 лет чек-бокс Vote заблокирован для ввода.</p>
<p>Создаем новый класс-наследник</p>
<p>Далее приведено объявление нашего <code>PersonalRecordDialog</code>. Информация времени выполнения о типе вводится с помощью макроса <code>DECLARE_CLASS</code>, а добавление таблицы событий &#8211; с помощью <code>DECLARE_EVENT_TABLE</code>.</p>
<pre class="brush: cpp;">
/*!
* Объявление класса PersonalRecordDialog
*/

class PersonalRecordDialog: public wxDialog
{
    DECLARE_CLASS( PersonalRecordDialog )
    DECLARE_EVENT_TABLE()

public:
    // Конструкторы
    PersonalRecordDialog( );
    PersonalRecordDialog( wxWindow* parent,
      wxWindowID id = wxID_ANY,
      const wxString&amp; caption = wxT(&quot;Personal Record&quot;),
      const wxPoint&amp; pos = wxDefaultPosition,
      const wxSize&amp; size = wxDefaultSize,
      long style = wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU );

    // Инициализация наших переменных
    void Init();

    // Создание
    bool Create( wxWindow* parent,
      wxWindowID id = wxID_ANY,
      const wxString&amp; caption = wxT(&quot;Personal Record&quot;),
      const wxPoint&amp; pos = wxDefaultPosition,
      const wxSize&amp; size = wxDefaultSize,
      long style = wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU );

    // Создание элементов управления и сайзеров
    void CreateControls();
};
</pre>
<p>Заметим, что следуя принятому в wxWidgets соглашению позволять одно- и двушаговое конструирование мы предоставляем конструктор по умолчанию и функцию <code>Create</code>, а также расширенный конструктор.</p>
<p>Проектируем хранение данных</p>
<p>У нас есть четыре части данных, которые нужно хранить: имя (строка), возраст (целое), пол (логическое) и предпочтения по голосованию (логическое). Чтобы упростить использование элемента управления <code>wxChoice</code> мы будем использовать целочисленный тип для хранения логического типа для пола, но интерфейс класса будет представлять его как логическое значение: <code>true</code> для женского пола и <code>false</code> для мужского. Давайте добавим эти данные и методы для работы с ними в класс <code>PersonalRecordDialog</code>:</p>
<pre class="brush: cpp;">
// Данные
wxString    m_name;
int         m_age;
int         m_sex;
bool        m_vote;

// Доступ к имени
void SetName(const wxString&amp; name) { m_name = name; }
wxString GetName() const { return m_name; }

// Доступ к возрасту
void SetAge(int age) { m_age = age; }
int GetAge() const { return m_age; }

// Доступ к полу (мужской = false, женский = true)
void SetSex(bool sex) { sex ? m_sex = 1 : m_sex = 0; }
bool GetSex() const { return m_sex == 1; }

// Будет ли пользователь голосовать?
void SetVote(bool vote) { m_vote = vote; }
bool GetVote() const { return m_vote; }
</pre>
<p>Создание элементов управления и их размещение</p>
<p>Теперь добавим функцию <code>CreateControls</code>, которая будет вызываться из <code>Create</code>. <code>CreateControls</code> добавляет несколько элементов управления типа <code>wxStaticText</code>, <code>wxButton</code>, <code>wxSpinCtrl</code>, <code>wxTextCtrl</code>, <code>wxChoice</code> и <code>wxCheckBox</code>. Обратитесь к рисунку 9-1, чтобы посмотреть результирующий диалог.</p>
<p>Мы используем основанный на сайзерах макет для этого диалога, из-за чего код выглядит достаточно сложно для такого небольшого числа элементов управления (мы уже коротко описывали сайзеры в Главе 7 &#8220;Размещение элементов с помощью сайзеров&#8221;, где рассказывали, что они позволяются создавать диалоги, которые нормально выглядят на множестве платформ и которые легко адаптировать для перевода и изменения размера). Вы можете использовать и другие методы, такие как загрузка диалога из ресурсов wxWidgets (XRC-файлов).</p>
<p>Основной принцип основанного на сайзерах размещения &#8211; поместить управляющие элементы во вложенные боксы (сайзеры), которые распределят место между элементами управления или растянуться, чтобы стать достаточными для их размещения. Сайзеры не являются окнами, они формируют отдельную иерархию и поэтому элементы управления остаются детьми своих родителей, независимо от сложности иерархии сайзеров. Вы можете освежить свою память и посмотреть на схематический вид размещения сайзеров, который показан на рисунке 7-2 в Главе 7.</p>
<p>В CreateControls мы используем вертикальный сайзер (<code>boxSizer</code>), вложенный в другой вертикальный сайзер (topSizer), чтобы получить достаточный отступ между элементам управления и границами диалога. Один горизонтальный сайзер используется для размещения <code>wxSpinCtrl</code>, <code>wxChoice</code> и <code>wxCheckBox</code>, а другой (<code>okCancelSizer</code>) &#8211; для кнопок Reset, OK, Cancel и Help.</p>
<pre class="brush: cpp;">
/*!
* Control creation for PersonalRecordDialog
*/
void PersonalRecordDialog::CreateControls()
{
    // Сайзер верхнего уровня

    wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
    this-&gt;SetSizer(topSizer);

    // Второй сайзер, чтобы получить больше пространства вокруг элементов

    wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
    topSizer-&gt;Add(boxSizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // Некоторый текст

    wxStaticText* descr = new wxStaticText( this, wxID_STATIC,
        wxT(&quot;Please enter your name, age and sex, and specify whether\
        you wish to\nvote in a general election.&quot;),
        wxDefaultPosition, wxDefaultSize, 0 );
    boxSizer-&gt;Add(descr, 0, wxALIGN_LEFT|wxALL, 5);

    // Отступ

    boxSizer-&gt;Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // Метка для текстового элемента

    wxStaticText* nameLabel = new wxStaticText ( this, wxID_STATIC,
        wxT(&quot;&amp;Name:&quot;), wxDefaultPosition, wxDefaultSize, 0 );
    boxSizer-&gt;Add(nameLabel, 0, wxALIGN_LEFT|wxALL, 5);

    // Тестовый элемент для получения имени пользователя

    wxTextCtrl* nameCtrl = new wxTextCtrl ( this, ID_NAME, wxT(&quot;Emma&quot;),
        wxDefaultPosition, wxDefaultSize, 0 );
    boxSizer-&gt;Add(nameCtrl, 0, wxGROW|wxALL, 5);

    // Горизонтальный сайзер, содержащий возраст, пол и флаг голосования

    wxBoxSizer* ageSexVoteBox = new wxBoxSizer(wxHORIZONTAL);
    boxSizer-&gt;Add(ageSexVoteBox, 0, wxGROW|wxALL, 5);

    // Метка для возраста

    wxStaticText* ageLabel = new wxStaticText ( this, wxID_STATIC,
        wxT(&quot;&amp;Age:&quot;), wxDefaultPosition, wxDefaultSize, 0 );
    ageSexVoteBox-&gt;Add(ageLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Спиновый элемент для получения возраста

    wxSpinCtrl* ageSpin = new wxSpinCtrl ( this, ID_AGE,
        wxEmptyString, wxDefaultPosition, wxSize(60, -1),
        wxSP_ARROW_KEYS, 0, 120, 25 );
    ageSexVoteBox-&gt;Add(ageSpin, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Метка для пола

    wxStaticText* sexLabel = new wxStaticText ( this, wxID_STATIC,
        wxT(&quot;&amp;Sex:&quot;), wxDefaultPosition, wxDefaultSize, 0 );
    ageSexVoteBox-&gt;Add(sexLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Создаем выпадающий список для выбора пола
    wxString sexStrings[] = {
        wxT(&quot;Male&quot;),
        wxT(&quot;Female&quot;)
    };

    wxChoice* sexChoice = new wxChoice ( this, ID_SEX,
        wxDefaultPosition, wxSize(80, -1), WXSIZEOF(sexStrings),
            sexStrings, 0 );
    sexChoice-&gt;SetStringSelection(wxT(&quot;Female&quot;));
    ageSexVoteBox-&gt;Add(sexChoice, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Добавляем растяжимый отступ, который перемещает элемент для
    // голосования направо

    ageSexVoteBox-&gt;Add(5, 5, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxCheckBox* voteCheckBox = new wxCheckBox( this, ID_VOTE,
       wxT(&quot;&amp;Vote&quot;), wxDefaultPosition, wxDefaultSize, 0 );
    voteCheckBox -&gt;SetValue(true);
    ageSexVoteBox-&gt;Add(voteCheckBox, 0,
        wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Создаем разделяющую черту перед кнопками OK и Cancel

    wxStaticLine* line = new wxStaticLine ( this, wxID_STATIC,
        wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    boxSizer-&gt;Add(line, 0, wxGROW|wxALL, 5);

    // Горизонтальный сайзер содержит кнопки Reset, OK, Cancel и Help

    wxBoxSizer* okCancelBox = new wxBoxSizer(wxHORIZONTAL);
    boxSizer-&gt;Add(okCancelBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // Кнопка Reset

    wxButton* reset = new wxButton( this, ID_RESET, wxT(&quot;&amp;Reset&quot;),
        wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox-&gt;Add(reset, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Кнопка OK

    wxButton* ok = new wxButton ( this, wxID_OK, wxT(&quot;&amp;OK&quot;),
        wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox-&gt;Add(ok, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Кнопка Cancel

    wxButton* cancel = new wxButton ( this, wxID_CANCEL,
        wxT(&quot;&amp;Cancel&quot;), wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox-&gt;Add(cancel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // Кнопка Help

    wxButton* help = new wxButton( this, wxID_HELP, wxT(&quot;&amp;Help&quot;),
        wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox-&gt;Add(help, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
}
</pre>
<h4>Пересылка данных и их проверка</h4>
<p>Теперь у нас в диалоге есть несколько элементов управления, но они пока не соеденены с переменными из диалога. Как можно реализовать такую связь?</p>
<p>Когда диалог показывается в первый раз wxWidgets вызывает <code>InitDialog</code>, который в свою очередь генерирует событие <code>wxEVT_INIT_DIALOG</code>. Обработчик по умолчанию для данного события вызывает <code>TransferDataToWindow</code> для диалога. Чтобы переслать информацию из элементов управления обратно в переменные вы должны вызвать <code>TransferDataFromWindow</code>, когда пользователь подтвердит свой выбор. Тоже самое делает wxWidgets в обработчике по умолчанию для управляющего события <code>wxID_OK</code>, который вызывает <code>TransferDataFromWindow</code> перед вызовом метода <code>EndModal</code> (который непосредственно закрывает диалог).</p>
<p>Поэтому вы можете переопределить <code>TransferDataToWindow</code> и <code>TransferDataFromWindow</code> для пересылки ваших данных. Для нашего диалога код может выглядеть следующим образом:</p>
<pre class="brush: cpp;">
/*!
* Посылаем данные в окно
*/

bool PersonalRecordDialog::TransferDataToWindow()
{
    wxTextCtrl* nameCtrl = (wxTextCtrl*) FindWindow(ID_NAME);
    wxSpinCtrl* ageCtrl = (wxSpinCtrl*) FindWindow(ID_SAGE);
    wxChoice* sexCtrl = (wxChoice*) FindWindow(ID_SEX);
    wxCheckBox* voteCtrl = (wxCheckBox*) FindWindow(ID_VOTE);

    nameCtrl-&gt;SetValue(m_name);
    ageCtrl-&gt;SetValue(m_age);
    sexCtrl-&gt;SetSelection(m_sex);
    voteCtrl-&gt;SetValue(m_vote);

    return true;
}

/*!
* Получаем данные из окна
*/

bool PersonalRecordDialog::TransferDataFromWindow()
{
    wxTextCtrl* nameCtrl = (wxTextCtrl*) FindWindow(ID_NAME);
    wxSpinCtrl* ageCtrl = (wxSpinCtrl*) FindWindow(ID_SAGE);
    wxChoice* sexCtrl = (wxChoice*) FindWindow(ID_SEX);
    wxCheckBox* voteCtrl = (wxCheckBox*) FindWindow(ID_VOTE);

    m_name = nameCtrl-&gt;GetValue();
    m_age = ageCtrl-&gt;GetValue();
    m_sex = sexCtrl-&gt;GetSelection();
    m_vote = voteCtrl-&gt;GetValue();

    return true;
}
</pre>
<p>Однако существует более простой путь пересылки данных. wxWidgets поддерживает вылидаторы, которые служат для создания связи между переменными и соответствующими элементами управления. Хотя эта технология применима не всегда, но использование валидаторов может сэкономить вам кучу времени и избавит от написания функций <code>TransferDataToWindow</code> и <code>TransferDataFromWindow</code>. Для нашего примера вы можете написать слудующий код вместо предыдущих двух функций:</p>
<pre class="brush: cpp;">
FindWindow(ID_NAME)-&gt;SetValidator(
      wxTextValidator(wxFILTER_ALPHA, &amp;m_name));
FindWindow(ID_AGE)-&gt;SetValidator(
      wxGenericValidator(&amp; m_age));
FindWindow(ID_SEX)-&gt;SetValidator(
      wxGenericValidator(&amp; m_sex);
FindWindow(ID_VOTE)-&gt;SetValidator(
      wxGenericValidator(&amp; m_vote);
</pre>
<p>Эти несколько строк в конце <code>CreateControls</code> заменяют две переопределенные функции. В качестве бонуса пользователю будет запрещено использовать цифры в строке с именем.</p>
<p>Валидаторы могут выполнять две работы. Кроме передачи данных они также могут проверять данные и показывать сообщение об ошибке, если данные не удовлетворяют заданным критериям. В нашем примере кроме небольшой проверки имени не делается других проверок. <code>wxGenericValidator</code> относительно простой класс предназначенный только для передачи данных. Однако он может работать с множеством стандартных базовых элементов управления. Другие валидаторы (например <code>wxTextValidator</code>) имеют более сложное поведение и могут даже перехватывать нажатия на клавиши, чтобы запретить ввод недопустимых символов. Для нашего примера мы используем стандартный стиль <code>wxFILTER_ALPHA</code>, но можно также явно определить какие символы должны или не должны считаться допустимыми с помощью методов <code>SetIncludes</code> и <code>SetExcludes</code>.</p>
<p>Изучим подробнее каким образом wxWidgets обрабатывает валидаторы. Как было упомянуто ранее стандартный обработчик <code>OnOK</code> вызывает <code>TransferDataToWindow</code>, но до этого он вызывает <code>Validate</code>, запрещая вызов <code>TransferDataToWindow</code> и <code>EndModal</code>, если вызов закончится неудачно. Вот стандартная реализация <code>OnOK</code>:</p>
<pre class="brush: cpp;">
void wxDialog::OnOK(wxCommandEvent&amp; event)
{
    if ( Validate() &amp;&amp; TransferDataFromWindow() )
    {
        if ( IsModal() )
            EndModal(wxID_OK); // Если диалог модальный
        else
        {
            SetReturnCode(wxID_OK);
            this-&gt;Show(false); // Если диалог не модальный
        }
    }
}
</pre>
<p>Обычная реализация <code>Validate</code> перебирает всех детей диалога (и их детей, если определен дополнительный стиль окна <code>wxWS_EX_VALIDATE_RECURSIVELY</code>) и вызывает <code>Validate</code> для каждого <code>wxValidator</code> элементов управления. Если любой из этих вызовов возвратит ошибку, то проверка диалога закончится неудачно и диалог не будет закрыт. Ожидается, что сообщение об ошибке будет вызвано снаружи функции <code>Validate</code>, если процедура проверки закончится неудачей.</p>
<p>Похожим образом будут автоматически вызваны <code>TransferDataToWindow</code> и <code>TransferDataFromWindow</code> для валидаторов элементов управления диалога. Валидатор обязан переслать данные, но процедура проверки является необязательной.</p>
<p>Валидаторы являются обработчиками событий и механизм обработки событий сначала перенаправляет приходящие события в валидатор, если он существует, перед тем как послать его элементу управления. Это позволяет валидаторам, например, перехватывать пользовательский ввод и блокировать символы, которые недопустимы для элемента управления. Такого рода блокировки обычно сопровождаются коротким гудком, который извещает пользователя, что клавиша, которую он нажал, не принята.</p>
<p>Так как двух представленных выше классов-валидаторов может быть не достаточно для ваших нужд (особенно если вы пишете свои собственные элементы управления), то у вас есть возможность унаследовать свой класс от <code>wxValidator</code>. Этот класс должен иметь конструктор копирования и функцию Clone, которая возвращает копию объекта-валидатора, а также реализацию для передачи данных и проверки. Валидатор обычно также хранит указатель на переменную языка C++. В файлах <code>include/wx/valtext.h</code> и <code>src/common/valtext.cpp</code> дистрибутива wxWidgets можно посмотреть как реализовать валидатор. Также обратитесь к разделу &#8220;Написание собственных элементов управления&#8221; в Главе 12 &#8220;Продвинутые классы окон&#8221;.</p>
<h4>Обработка событий</h4>
<p>Для нашего примера нам не потребуется писать обработчики для кнопок OK и Cancel, так как мы можем использовать стандартные обработчики. Для этого достаточно использовать стандартные идентификаторы <code>wxID_OK и wxID_CANCEL</code> для этих кнопок.</p>
<p>Однако, для нетривиальных диалогов вам возможно потребуется перехватывать и обрабатывать события от элементов управления. В нашем примере у нас есть кнопка Reset, которую можно нажать в любой момент, чтобы сбросить значения в диалоге в их начальные значения. Мы добавим обработчик <code>OnResetClick</code> и соответствующую запись в таблицу обработчиков событий. Реализация <code>OnResetClick</code> будет очень простой: вначале мы сбрасываем значение переменных, вызвав функцию <code>Init</code> (которую введена, чтобы сделать единую точку инициализации переменных), а далее вызываем <code>TransferDataToWindow</code>, чтобы отобразить эти данные.</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE( PersonalRecordDialog, wxDialog )
    ...
    EVT_BUTTON( ID_RESET, PersonalRecordDialog::OnResetClick)
    ...
END_EVENT_TABLE()

void PersonalRecordDialog::OnResetClick( wxCommandEvent&amp; event )
{
    Init();
    TransferDataToWindow();
}
</pre>
<h4>Обработка обновлений интерфейса</h4>
<p>Одна из задач с которой обычно сталкивается программист &#8211; это быть уверенным, что пользователь не может выбрать элемент управления или пункт меню, который в данный момент не применим. Ленивые программисты обычно делают выскакивающую надпись &#8220;Эта опция в данный момент недоступна&#8221;. Но если опция недоступна, то она должна выглядеть недоступной, и при нажатии на соответствующий элемент ничего не должно происходить. Для этого программе необходимо обновлять элементы интерфейса, чтобы они отражали правильное состояние в каждый момент времени.</p>
<p>В нашем примере мы должны отключить чек-бокс &#8220;Vote&#8221; когда возраст пользователя меньше 18 лет, так как в этом случае пользователь не может принимать решение об этом. Вашей первой мыслью, наверное, будет добавить обработчик событий от спина Age, который будет включать и выключать элемент Vote в соответствии со своим значением в спине. Хотя данное решение может хорошо работать для простых пользовательских интерфейсов, но представьте что будет, если состояние элемента зависит от множества факторов. Существуют более плохие ситуации, когда вы не можете перехватывать изменения некоторого параметра. Например, вам необходимо включать пункт меню &#8220;Вставить&#8221; в зависимости от доступности данных в буфере обмена. Перехват этого события очень сложен, так как данные могут поступать и из другого окна.</p>
<p>Чтобы решить такую проблему в wxWidgets существует специальный класс событий wxUpdateUIEvent, который посылается все окнам, когда программа простаивает, что происходит когда петля событий закончила обработку всех остальных событий. Вы можете добавить обработчик <code>EVT_UPDATE_UI</code> в ваш диалог, по одному для каждого элемента управления, состояние которых вы хотите контролировать. Соответствующий обработчик вычисляет текущее состояние и вызывает функции объекта-события (а не для элемента управления) для включения, выключения, установки или снятия галочки. Эта технология позволяет перенести логику обновления состояния элемента в одно место, вызывая обновления даже в то время, когда в приложение не приходят реальные события. И это хорошо, так как не может возникнуть ситуация, когда вы забудете обновить состояние элементов управления.</p>
<p>Далее приведен обработчик события об обновлении интерфейса для элемента &#8220;Vote&#8221;. Заметим, что мы не можем использовать переменную m_age, так как перенос данных из элементов управления в переменные происходит только после того, как пользователь нажмет кнопку &#8220;OK&#8221;.</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE( PersonalRecordDialog, wxDialog )
    ...
    EVT_UPDATE_UI( ID_VOTE, PersonalRecordDialog::OnVoteUpdate )
    ...
END_EVENT_TABLE()

void PersonalRecordDialog::OnVoteUpdate( wxUpdateUIEvent&amp; event )
{
    wxSpinCtrl* ageCtrl = (wxSpinCtrl*) FindWindow(ID_AGE);
    if (ageCtrl-&gt;GetValue() &lt; 18)
    {
        event.Enable(false);
        event.Check(false);
    }
    else
        event.Enable(true);
}
</pre>
<p>Не волнуйтесь слишком сильно об эффективности такого решения, так как оно занимает не очень много циклов работы процессора. Однако, если у вас достаточно сложное приложение и вы столкнулись с проблемами производительности по вине обновления интерфейса, то посмотрите документацию по классу <code>wxUpdateUIEvent</code> о функциях <code>SetMode</code> и <code>SetUpdateInterval</code>, которые можно использовать, чтобы уменьшить время, которое wxWidgets тратит на обработку таких событий.</p>
<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-ii">Читать вторую часть главы &#8220;Написание собственных диалогов&#8221;</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-ix-napisanie-sobstvennyx-dialogov-chast-i/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian&#8217;а Smart&#8217;а &#8211; Глава VI &#8211; Обработка данных с устройств ввода</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-vi-obrabotka-dannyx-s-ustrojstv-vvoda/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-vi-obrabotka-dannyx-s-ustrojstv-vvoda/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 20:49:58 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=502</guid>
		<description><![CDATA[Скачать PDF-версию (223 КБ) Перевод сделан Грубниковым А.Г. Все GUI-приложения должны каким-либо образом реагировать на данные, поступающие от устройства ввода. Эта глава покажет как можно взаимодействовать с мышью, клавиатурой и джойстиком. 6.1 Получение данных от мыши Упрощенно говоря, приложение получает от мыши два вида событий: основные события мыши, посылаемые с помощью класса wxMouseEvent, и &#8220;сырые&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://depositfiles.com/files/6imqbjw0o" title="Скачать PDF: Julian'а Smart'а - Глава VI - Обработка данных с устройств ввода">Скачать PDF-версию (223 КБ)</a></p>
<p>Перевод сделан Грубниковым А.Г.</p>
<p>Все GUI-приложения должны каким-либо образом реагировать на данные, поступающие от устройства ввода. Эта глава покажет как можно взаимодействовать с мышью, клавиатурой и джойстиком.</p>
<h4>6.1 Получение данных от мыши</h4>
<p>Упрощенно говоря, приложение получает от мыши два вида событий: основные события мыши, посылаемые с помощью класса <code>wxMouseEvent</code>, и &#8220;сырые&#8221; события, передаваемые вашей функции-обработчику неинтерпретированными. При этом действия, связанные с элементами управления (такими как, например, кнопка), часто являются результатом интерпретации событий от мыши (или других устройств) как отдельных команд.<br />
Например, когда вы добавляете макрос <code>EVT_BUTTON</code> в таблицу событий, то вы перехватываете событие <code>wxCommandEvent</code>, которое было сгенерировано классом <code>wxButton</code>.<br />
<span id="more-502"></span><br />
Это, в свою очередь, происходит следующим образом: кнопка перехватывает событие от мыши <code>EVT_LEFT_DOWN</code> и порождает управляющее событие. Конечно, на большинстве платформ, класс <code>wxButton</code> реализован как &#8220;родной&#8221; и не использует низкоуровневую обработку событий wxWidgets, но так будет происходить для несуществующих на платформе классов.</p>
<p>Так как примеры обработки управляющих событий были уже показаны, то мы сосредоточимся на основных событиях, генерируемых мышью.</p>
<p>Вы можете перехватить события отпускания (key up), нажатия (key down) и двойного клика левой, средней или правой кнопками мыши. Можно также перехватить движения мыши, как с нажатой кнопкой, так и без. Вы можете перехватить события, говорящие о входе курсора в область окна и о выходе из этой области. Наконец, возможно перехватить события от колесика прокрутки, если на мыши таковое присутствует.</p>
<p>После получения событий от мыши, вы можете проверить состояние ее кнопок, а также клавиш-модификаторов (Shift, Alt, Control и Meta). Также доступна информация о текущем положении указателя мыши относительно верхнего левого угла клиентской области окна.</p>
<p>Таблица 6.1 содержит макросы таблицы событий, которые вы можете использовать. Класс <code>wxMouseEvent</code> не передается по цепочке родителям окна, поэтому для обработки таких событий вы должны унаследовать свой класс от класса окна или от<code> wxEvtHandler</code>, а потом модифицировать обработчик событий для необходимых подокон с помощью функций <code>SetEventHandler</code> или <code>PushEventHandler</code>. Или же, вы можете выполнить динамическую привязку с помощью функции <code>Connect</code>.</p>
<ul>
<li><code>EVT_LEFT_DOWN(func)</code> &#8211; Обрабатывает событие <code>wxEVT_LEFT_DOWN</code>, генерируемое при смене состояния левой кнопки на &#8220;нажата&#8221;.</li>
<li> <code>EVT_LEFT_UP(func)</code> &#8211; Обрабатывает событие <code>wxEVT_LEFT_UP</code>, генерируемое при смене состояния левой кнопки на &#8220;отпущена&#8221;.</li>
<li><code>EVT_LEFT_DCLICK(func)</code> &#8211; Обрабатывает событие <code>wxEVT_LEFT_DCLICK</code>, генерируемое при двойном клике левой кнопкой.</li>
<li><code>EVT_MIDDLE_DOWN(func)</code> &#8211; Обрабатывает событие <code>wxEVT_MIDDLE_DOWN</code>, генерируемое при смене состояния средней кнопки на &#8220;нажата&#8221;.</li>
<li><code>EVT_MIDDLE_UP(func)</code> &#8211; Обрабатывает событие <code>wxEVT_MIDDLE_UP</code>, генерируемое при смене состояния средней кнопки на &#8220;отпущена&#8221;.</li>
<li><code>EVT_MIDDLE_DCLICK(func)</code> &#8211; Обрабатывает событие <code>wxEVT_MIDDLE_DCLICK</code>, генерируемое при двойном клике средней кнопкой.</li>
<li><code>EVT_RIGHT_DOWN(func)</code> &#8211; Обрабатывает событие <code>wxEVT_RIGHT_DOWN</code>, генерируемое при смене состояния правой кнопки на &#8220;нажата&#8221;.</li>
<li><code>EVT_RIGHT_UP(func)</code> &#8211; Обрабатывает событие <code>wxEVT_RIGHT_UP</code>, генерируемое при смене состояния правой кнопки на &#8220;отпущена&#8221;.</li>
<li><code>EVT_RIGHT_DCLICK(func)</code> &#8211; Обрабатывает событие <code>wxEVT_RIGHT_DCLICK</code>, генерируемое при двойном клике правой кнопкой.</li>
<li><code>EVT_MOTION(func)</code> &#8211; Обрабативает событие <code>wxEVT_MOTION</code>, генерируемое при движении указателя мыши.</li>
<li><code>EVT_ENTER_WINDOW(func)</code> &#8211; Обрабатывает событие <code>wxEVT_ENTER_WINDOW</code>, генерируемое при входе указателя в область окна.</li>
<li><code>EVT_LEAVE_WINDOW(func)</code> &#8211; Обрабатывает событие <code>wxEVT_LEAVE_WINDOW</code>, генерируемое при выходе указателя из области окна.</li>
<li><code>EVT_MOUSEWHEEL(func)</code> &#8211; Обрабатывает событие <code>wxEVT_MOUSEWHEEL</code>, генерируемое при движении колесика прокрутки у мыши.</li>
<li><code>EVT_MOUSE_EVENTS(func)</code> &#8211; Обрабатывает все события, производимые мышью.</li>
</ul>
<h4>6.1.1 Обработка событий о движении мыши и нажатии кнопок</h4>
<p>Ниже представлены главные функции событий мыши, которые вы можете использовать для обработки событий о передвижениях мыши и нажатиях на ее кнопки.</p>
<p>Для проверки, нажаты ли клавиши-модификаторы во время перехвата события, используйте функции <code>AltDown</code>, <code>MetaDown</code>, <code>ControlDown</code> или <code>ShiftDown</code>. Функция <code>CmdDown</code> используется для проверки, нажата ли клавиша Meta (на Mac OS X) или клавиша Control (на других платформах). Дополнительную информацию можно найти далее в этой главе в разделе &#8220;Разновидности клавиш-модификаторов&#8221;.</p>
<p>Для определения, какая кнопка мыши нажата в данный момент, используйте функции <code>LeftIsDown</code>, <code>MiddleIsDown</code> и <code>RightIsDown</code>. Также можно проверить, нажата ли какая-либо кнопка, послав событие <code>wxMOUSE_BTN_LEFT</code>, <code>wxMOUSE_BTN_MIDDLE</code>, <code>wxMOUSE_BTN_RIGHT</code> или <code>wxMOUSE_BTN_ANY</code> объекту wxButton. Обратите внимание, что это проверка на нажатие какой-либо кнопки на момент совершения события, а не при смене его состояния.</p>
<p>В Mac OS X клавиша Command означает клавишу Meta, а клавиша Alt — Option. Так как часто на Mac-комьютерах мышь имеет только одну кнопку мыши, то пользователь должен удерживать Control во время клика, чтобы получить событие клика правой кнопкой. Это означает, что в Mac OS невозможно сделать правый клик одновременно с Control, если у вас нет обычной мыши с двумя или тремя кнопками.</p>
<p>Вы можете выяснить тип произошедшего события с помощью функций <code>Dragging</code> (движение курсора с удерживаемой кнопкой), <code>Moving</code> (без нее), <code>Entering</code>, <code>Leaving</code>, <code>ButtonDown</code>, <code>ButtonUp</code>, <code>ButtonDClick</code>, <code>LeftClick</code>, <code>LeftDClick</code>, <code>LeftUp</code>, <code>RightClick</code>, <code>RightDClick</code>, <code>RightUp</code>, <code>ButtonUp</code> и <code>IsButton</code>.</p>
<p>Чтобы получить позицию курсора в пикселях монитора (относительно верхнего левого угла клиентской области окна) используйте функции <code>GetPosition</code> или <code>GetX</code> и <code>GetY</code>. Также возможно получить позицию в логических координатах, передав контекст устройства функции <code>GetLogicalPosition</code>.</p>
<p>Вот пример обработки событий мыши в простом демонстрационном приложении:</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE(DoodleCanvas, wxWindow)
EVT_MOUSE_EVENTS(DoodleCanvas::OnMouseEvent)
END_EVENT_TABLE()

void DoodleCanvas::OnMouseEvent(wxMouseEvent&amp; event)
{
    static DoodleSegment *s_currentSegment = NULL;
    wxPoint pt(event.GetPosition());
    if (s_currentSegment &amp;&amp; event.LeftUp())
    {
        // Заканчиваем сегмент, если пользователь отпустил левую кнопку
        if (s_currentSegment-&gt;GetLines().GetCount() == 0)
        {
            // Если сегмент пустой, то удаляем его
            delete s_currentSegment;
            s_currentSegment = (DoodleSegment *) NULL;
        }
        else
        {
            // Сохраняем сегмент
            DrawingDocument *doc = GetDocument();
            doc-&gt;GetCommandProcessor()-&gt;Submit(
            new DrawingCommand(wxT(&quot;Add Segment&quot;), DOODLE_ADD, doc, s_currentSegment));
            doc-&gt;Modify(true);
            s_currentSegment = NULL;
        }
    }
    else if (m_lastX &gt; -1 &amp;&amp; m_lastY &gt; -1 &amp;&amp; event.Dragging())
    {
        // При движении мыши с нажатой кнопкой, добавляем линию в текущий сегмент
        if (!s_currentSegment)
            s_currentSegment = new DoodleSegment;
        DoodleLine *newLine = new DoodleLine(m_lastX, m_lastY, pt.x, pt.y);
        s_currentSegment-&gt;GetLines().Append(newLine);
        wxClientDC dc(this);
        DoPrepareDC(dc);
        dc.SetPen(*wxBLACK_PEN);
        dc.DrawLine( m_lastX, m_lastY, pt.x, pt.y);
    }
    m_lastX = pt.x;
    m_lastY = pt.y;
}
</pre>
<p>В этом приложении сегменты линий хранятся в документе. Пока пользователь, удерживая левую кнопку, двигает мышь, функция добавляет линии к текущему сегменту и одновременно рисует их. Как только пользователь отпускает левую кнопку мыши, текущий сегмент передается в документ, используя управляющий процессор (часть архитектуры Документ/Вид), который отвечает за реализацию операций &#8220;отменить&#8221; и &#8220;повторить&#8221;. В обработчике <code>OnPaint</code> этого приложения (не приводится) рисуются все сегменты линий документа. За полной реализацией действий &#8220;отменить&#8221; и &#8220;повторить&#8221;, обратитесь к Главе 19 &#8220;Работа с архитектурой Документ/Вид&#8221;. Более полное приложение захватывало бы мышь по нажатию левой кнопки и освобождала ее после отпускания кнопки, чтобы при выходе курсора за пределы окна, оно бы по-прежнему получало события.</p>
<h4>6.1.2 Обработка событий от колесика мыши</h4>
<p>При обработке событий от колесика мыши, вы можете получить положительную или отрицательную величину вращения, используя функцию GetWheelRotation. Деление данного значения на величину, возвращаемую функцией GetWheelDelta, даст количество строк на которое произошла прокрутка. Большинство устройств порождают одно событие на изменение положения колесика, но некоторые могут делать это чаще, поэтому может понадобиться суммировать значения поворота и совершать<br />
необходимые действия, когда сумма достигнет величины одной строки. Не исключено, что вы захотите проматывать и на не целую часть строки. В любом случае следует использовать значение, возвращаемое функцией <code>GetLinesPerAction</code>, так как оно устанавливается пользователем в &#8220;Панели управления&#8221;, и умножать него полученный результат, чтобы проматывать на необходимое количество строк.</p>
<p>В некоторых ситуациях мышь может быть настроена проматывать страницу за раз. В этом случае вам нужно вызвать <code>IsPageScroll</code> и если она вернет значение <code>true</code>, то проматывать страницу.</p>
<p>Ниже показана реализация обработки колесика прокрутки в классе <code>wxScrolledWindow</code>. В переменной <code>m_wheelRotation</code> суммируется вращение, и действие происходит только если количество строк ненулевое.</p>
<pre class="brush: cpp;">
void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent&amp; event)
{
    m_wheelRotation += event.GetWheelRotation();
    int lines = m_wheelRotation / event.GetWheelDelta();
    m_wheelRotation -= lines * event.GetWheelDelta();
    if (lines != 0)
    {
        wxScrollWinEvent newEvent;
        newEvent.SetPosition(0);
        newEvent.SetOrientation(wxVERTICAL);
        newEvent.m_eventObject = m_win;
        if (event.IsPageScroll())
        {
            if (lines &gt; 0)
                newEvent.m_eventType = wxEVT_SCROLLWIN_PAGEUP;
            else
                newEvent.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN;
            m_win-&gt;GetEventHandler()-&gt;ProcessEvent(newEvent);
        }
        else
        {
            lines *= event.GetLinesPerAction();
            if (lines &gt; 0)
                newEvent.m_eventType = wxEVT_SCROLLWIN_LINEUP;
            else
                newEvent.m_eventType = wxEVT_SCROLLWIN_LINEDOWN;
            int times = abs(lines);
            for (; times &gt; 0; times)
                m_win-&gt;GetEventHandler()-&gt;ProcessEvent(newEvent);
        }
    }
}
</pre>
<h4>6.2 Обработка событий от клавиатуры</h4>
<p>События от клавиатуры представлены классом <code>wxKeyEvent</code>. В библиотеке wxWidgets существуют три типа сообщений: нажатие клавиши (key down), отпускание клавиши и набор символа. Нажатие и отпускание &#8211; не преобразуемые события, в то время как набор символа — преобразуемое. </p>
<p>Если нажать на клавишу то, как правило, будет производиться много событий нажатия и лишь одно — отпускания, так что неверно полагать что каждому событию нажатия соответствует одно событие<br />
отпускания.</p>
<p>Чтобы получать события от клавиатуры ваше окно должно находиться в текстовом фокусе, который вы можете принудительно получить, вызвав метод <code>wxWindow::SetFocus</code>, например, по нажатию мыши.</p>
<p>Таблица 6.2 содержит три макроса для обработки событий от клавиатуры.</p>
<ul>
<li><code>EVT_KEY_DOWN(func)</code> &#8211; Обрабатывает событие <code>wxEVT_KEY_DOWN</code><br />
(не преобразуемое нажатие клавиши).</li>
<li><code>EVT_KEY_UP(func)</code> &#8211; Обрабатывает событие <code>wxEVT_KEY_UP</code> (не<br />
преобразуемое отпускание клавиши).</li>
<li><code>EVT_CHAR(func)</code> &#8211; Обрабатывает событие <code>wxEVT_CHAR</code> (преобразуемый набор символа).</li>
</ul>
<p>Ниже представлены главные функции класса <code>wxKeyEvent</code>, которые вы можете использовать в вашей функции-обработчике событий клавиатуры.</p>
<p>Для получения кода клавиши вызывайте функцию <code>GetKeyCode</code> (в Unicode-сборках, можно использовать GetUnicodeKeyCode). Все действительные коды клавиш указаны в таблице 6.3.</p>
<table>
<tr>
<td>WXK_BACK</td>
<td>WXK_RIGHT</td>
</tr>
<tr>
<td>WXK_TAB</td>
<td>WXK_DOWN</td>
</tr>
<tr>
<td>WXK_RETURN</td>
<td>WXK_SELECT</td>
</tr>
<tr>
<td>WXK_ESCAPE</td>
<td>WXK_PRINT</td>
</tr>
<tr>
<td>WXK_SPACE</td>
<td>WXK_EXECUTE</td>
</tr>
<tr>
<td>WXK_DELETE</td>
<td>WXK_SNAPSHOT</td>
</tr>
<tr>
<td>WXK_INSERT</td>
<td></td>
</tr>
<tr>
<td>WXK_START</td>
<td>WXK_HELP</td>
</tr>
<tr>
<td>WXK_LBUTTON</td>
<td></td>
</tr>
<tr>
<td>WXK_RBUTTON</td>
<td>WXK_NUMPAD0</td>
</tr>
<tr>
<td>WXK_CANCEL</td>
<td>WXK_NUMPAD1</td>
</tr>
<tr>
<td>WXK_MBUTTON</td>
<td>WXK_NUMPAD2</td>
</tr>
<tr>
<td>WXK_CLEAR</td>
<td>WXK_NUMPAD3</td>
</tr>
<tr>
<td>WXK_SHIFT</td>
<td>WXK_NUMPAD4</td>
</tr>
<tr>
<td>WXK_CONTROL</td>
<td>WXK_NUMPAD5</td>
</tr>
<tr>
<td>WXK_MENU</td>
<td>WXK_NUMPAD6</td>
</tr>
<tr>
<td>WXK_PAUSE</td>
<td>WXK_NUMPAD7</td>
</tr>
<tr>
<td>WXK_CAPITAL</td>
<td>WXK_NUMPAD8</td>
</tr>
<tr>
<td>WXK_PRIOR</td>
<td>WXK_NUMPAD9</td>
</tr>
<tr>
<td>WXK_NEXT</td>
<td></td>
</tr>
<tr>
<td>WXK_END</td>
<td>WXK_MULTIPLY</td>
</tr>
<tr>
<td>WXK_HOME</td>
<td>WXK_ADD</td>
</tr>
<tr>
<td>WXK_LEFT</td>
<td>WXK_SEPARATOR</td>
</tr>
<tr>
<td>WXK_UP</td>
<td>WXK_SUBTRACT</td>
</tr>
<tr>
<td>WXK_NUMPAD_DECIMAL</td>
<td>WXK_PAGEDOWN</td>
</tr>
<tr>
<td>WXK_NUMPAD_DIVIDE</td>
<td></td>
</tr>
<tr>
<td>WXK_NUMPAD_SPACE</td>
<td></td>
</tr>
<tr>
<td>WXK_F1</td>
<td>WXK_NUMPAD_TAB</td>
</tr>
<tr>
<td>WXK_F2</td>
<td>WXK_NUMPAD_ENTER</td>
</tr>
<tr>
<td>WXK_F3</td>
<td>WXK_NUMPAD_F1</td>
</tr>
<tr>
<td>WXK_F4</td>
<td>WXK_NUMPAD_F2</td>
</tr>
<tr>
<td>WXK_F5</td>
<td>WXK_NUMPAD_F3</td>
</tr>
<tr>
<td>WXK_F6</td>
<td>WXK_NUMPAD_F4</td>
</tr>
<tr>
<td>WXK_F7</td>
<td>WXK_NUMPAD_HOME</td>
</tr>
<tr>
<td>WXK_F8</td>
<td>WXK_NUMPAD_LEFT</td>
</tr>
<tr>
<td>WXK_F9</td>
<td>WXK_NUMPAD_UP</td>
</tr>
<tr>
<td>WXK_F10</td>
<td>WXK_NUMPAD_RIGHT</td>
</tr>
<tr>
<td>WXK_F11</td>
<td>WXK_NUMPAD_DOWN</td>
</tr>
<tr>
<td>WXK_F12</td>
<td>WXK_NUMPAD_PRIOR</td>
</tr>
<tr>
<td>WXK_F13</td>
<td>WXK_NUMPAD_PAGEUP</td>
</tr>
<tr>
<td>WXK_F14</td>
<td>WXK_NUMPAD_NEXT</td>
</tr>
<tr>
<td>WXK_F15</td>
<td>WXK_NUMPAD_PAGEDOWN</td>
</tr>
<tr>
<td>WXK_F16</td>
<td>WXK_NUMPAD_END</td>
</tr>
<tr>
<td>WXK_F17</td>
<td>WXK_NUMPAD_BEGIN</td>
</tr>
<tr>
<td>WXK_F18</td>
<td>WXK_NUMPAD_INSERT</td>
</tr>
<tr>
<td>WXK_F19</td>
<td>WXK_NUMPAD_DELETE</td>
</tr>
<tr>
<td>WXK_F20</td>
<td>WXK_NUMPAD_EQUAL</td>
</tr>
<tr>
<td>WXK_F21</td>
<td>WXK_NUMPAD_MULTIPLY</td>
</tr>
<tr>
<td>WXK_F22</td>
<td>WXK_NUMPAD_ADD</td>
</tr>
<tr>
<td>WXK_F23</td>
<td>WXK_NUMPAD_SEPARATOR</td>
</tr>
<tr>
<td>WXK_F24</td>
<td>WXK_NUMPAD_SUBTRACT</td>
</tr>
<tr>
<td>WXK_NUMLOCK</td>
<td>WXK_NUMPAD_DEMICAL</td>
</tr>
<tr>
<td>WXK_SCROLL</td>
<td>WXK_NUMPAD_DEVIDE</td>
</tr>
<tr>
<td>WXK_PAGEUP</td>
<td></td>
</tr>
</table>
<p>Для проверки, была ли нажата клавиша-модификатор во время образования события, используйте функции <code>AltDown</code>, <code>MetaDown</code>, <code>ControlDown</code> или <code>ShiftDown</code>. Функция <code>HasModifiers</code> возвращает значение <code>true</code>, если Control или Alt были нажаты во время генерации сообщения нажатия/отпускания (но не Shift или Meta).</p>
<p>Вместо использования функций <code>ControlDown</code> или <code>MetaDown</code> лучше использовать более высокоуровевую функцию <code>CmdDown</code>, которая вызывает <code>MetaDown</code> на Mac OS X и <code>ControlDown</code> на прочих платформах. См. также &#8220;Разновидности клавиш-модификаторов&#8221; в следующем разделе для более подробных объяснений.<br />
Функция <code>GetPosition</code> возвращает позицию указателя мыши в координатах клиентской области во время получения соответствующих событий.</p>
<p>Совет: если событие нажатия клавиши захвачено и его обработчик не вызвал метод <code>event.Skip()</code>, то данное событие не будет передаваться следующим обработ чикам. Если вы не вызываете <code>event.Skip()</code> для событий, которые не обрабатываете, то на некоторых платформах могут перестать работать горящие клавиши.</p>
<h4>6.2.1 Пример обработчика события ввода символа</h4>
<p>Ниже представлен обработчик клавиш из примера <code>wxThumbnailCtrl</code>, который вы можете найти в папке examples/chap12/thumbnail на прилагаемом CD-ROM’е.</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE( wxThumbnailCtrl, wxScrolledWindow )
EVT_CHAR(wxThumbnailCtrl::OnChar)
END_EVENT_TABLE()
void wxThumbnailCtrl::OnChar(wxKeyEvent&amp; event)
{
    int flags = 0;
    if (event.ControlDown())
        flags |= wxTHUMBNAIL_CTRL_DOWN;
    if (event.ShiftDown())
        flags |= wxTHUMBNAIL_SHIFT_DOWN;
    if (event.AltDown())
        flags |= wxTHUMBNAIL_ALT_DOWN;
    if (event.GetKeyCode() == WXK_LEFT ||
        event.GetKeyCode() == WXK_RIGHT ||
        event.GetKeyCode() == WXK_UP ||
        event.GetKeyCode() == WXK_DOWN ||
        event.GetKeyCode() == WXK_HOME ||
        event.GetKeyCode() == WXK_PAGEUP ||
        event.GetKeyCode() == WXK_PAGEDOWN ||
        event.GetKeyCode() == WXK_PRIOR ||
        event.GetKeyCode() == WXK_NEXT ||
        event.GetKeyCode() == WXK_END)
    {
        Navigate(event.GetKeyCode(), flags);
    }
    else if (event.GetKeyCode() == WXK_RETURN)
    {
        wxThumbnailEvent cmdEvent(
            wxEVT_COMMAND_THUMBNAIL_RETURN,
            GetId());
        cmdEvent.SetEventObject(this);
        cmdEvent.SetFlags(flags);
        GetEventHandler()-&gt;ProcessEvent(cmdEvent);
    }
    else
        event.Skip();
}
</pre>
<p>Для ясности обработчик клавиш навигации выделен в отдельную функцию <code>Navigate</code>. Нажатие клавиш возврата и ввода генерирует высокоуровневое управляющее событие, которое приложение использует для захвата управления. Для всех остальных нажатых клавиш вызывается функция <code>Skip</code>, чтобы позволить другим частям приложения обрабатывать не задействованные здесь события клавиатуры.</p>
<h4>6.2.2 Преобразование кода клавиши</h4>
<p>События нажатия/отпускания предоставляют не преобразуемые коды клавиш, тогда как событие ввода символа предоставляет преобразуемый код клавиши. Не преобразуемый код для алфавитно-цифровых клавиш всегда соответствует значению верхнего регистра. Для остальных клавиш, это значения вида <code>WXK_XXX</code> из таблицы кодов символов. Преобразуемая клавиша, в основном является символом, пояление которого ожидает пользователь как результат комбинации клавиш при вводе в тек-<br />
стовое поле.</p>
<p>Вот несколько поясняющих примеров. Когда клавиша &#8220;А&#8221; нажата, код события нажатия равен коду &#8220;А&#8221; из таблицы ASCII (65), но код события ввода символа &#8211; ASCII &#8220;а&#8221; (97). Притом, если вы нажали &#8220;А&#8221; с Shift, код клавиши в событии нажатия по-прежнему будет &#8220;А&#8221;, в то время как код клавиши события ввода символа теперь тоже станет &#8220;А&#8221;.</p>
<p>В это простом случае ясно, что в обработчике события нажатия ASCII-код может быть получен путем проверки как не преобразуемого кода клавиши, так и значения, возвращенного функцией <code>ShiftDown</code>. </p>
<p>Но в общем случае, если вам нужен ASCII-код клавиш, вы должны использовать событие ввода символа (с <code>EVT_CHAR</code>), так как для не алфавитно-цифровых клавиш преобразование зависит от раскладки клавиатуры и может быть выполнена правильно самой системой.</p>
<p>Другой вид преобразования происходит когда зажат Control, например, Ctrl+А. Событие нажатия передает тот же код &#8220;А&#8221;, но событие ввода символа будет иметь код &#8220;1&#8243;. Это ASCII-значение этой комбинации клавиш.</p>
<p>Вы можете исследовать работу других клавиш у себя в системе, запустив пример samples/keyboard и понажимав разные клавиши.</p>
<h4>6.2.3 Разновидности клавиш-модификаторов</h4>
<p>В ОС Windows клавиши-модификаторы это Control и Alt, а также особая win-клавиша, работающая как Meta. В ОС UNIX, клавиша, работающая как Meta настраивается (запустите утилиту xmodmap, чтобы посмотреть, как настроена ваша система).</p>
<p>Иногда NumLock настроена как Meta, и из за этого функция <code>HasModifiers</code> не возвращают значение <code>true</code> при удержанной клавише Meta, так как при этом нормально обрабатываются нажатия клавиш с включенным <code>NumLock</code>.</p>
<p>В Mac OS X клавиша Command (с символом apple) выполняет функции Meta, а Option — функции Alt.<br />
Эти различия показаны в таблице 6.4, где первая колонка — название модификаторов в wxWidgets, остальные три — клавиши, используемые для этих модификаторов на основных платформах. Клавиши Mac проиллюстрированы для наглядности.</p>
<table>
<tr>
<td>Модификатор</td>
<td>Клавиша в Windows</td>
<td>Клавиша в UNIX</td>
<td>Клавиша в Mac OS X</td>
</tr>
<tr>
<td>Shift</td>
<td>Shift</td>
<td>Shift</td>
<td>Shift</td>
</tr>
<tr>
<td>Control</td>
<td>Control</td>
<td>Control</td>
<td>Control</td>
</tr>
<tr>
<td>Alt</td>
<td>Alt</td>
<td>Alt</td>
<td>Option</td>
</tr>
<tr>
<td>Meta</td>
<td>Windows</td>
<td>(Настраивается)</td>
<td>Command</td>
</tr>
</table>
<p>Так как в Mac OS X клавиша Command используется для тех же целей, что и Control на других платформах, то можно использовать функцию <code>CmdDown</code> объекта <code>wxKeyEvent</code> вместо <code>ControlDown</code> или <code>MetaDown</code> для перехвата этих команд на разных платформах.</p>
<p>Следует отметить, что также можно передать код клавиши функции <code>wxGetKeyState</code>, чтобы проверить была ли нажата клавиша. Последняя возможность особенно полезна в обработчике событий, пришедших не от клавиатуры.</p>
<h4>6.2.4 Акселераторы</h4>
<p>Акселераторы — это &#8220;горячие&#8221; клавиши для различных команд меню, которые позволяют пользователю вызывать команды очень быстро. Такие горячие клавиши имеют преимущество в обработке перед другими обработчиками клавиатуры, такими как <code>EVT_CHAR</code>. Стандартный набор таких акселераторов включает в себя Ctrl+O (чтобы открыть файл) и Ctrl+V (чтобы вставить данные в приложение). Самый легкий способ реализовать акселераторы — определить их непосредственно в пунктах меню. Например:</p>
<pre class="brush: cpp;">
menu-&gt;Append(wxID_COPY, wxT(&quot;Copy\tCtrl+C&quot;));
</pre>
<p>wxWidgets интерпретирует текст после символа табуляции как акселератор и добавляют его в таблицу акселераторов меню. В этом примере при нажатии пользователем Ctrl+C посылается команда <code>wxID_COPY</code>, как будто был выбран соответствующий пункт меню.</p>
<p>Вы можете использовать Control, Alt или Shift в различных сочетаниях, дополняя символом или функциональной клавишей, следующими за &#8220;+&#8221; или &#8220;-&#8221;. Вот примеры правильных сочетаний клавиш-акселераторов: Ctrl+B, G, Shift-Alt-K, F9, Ctrl+F3,<br />
Esc и Del. Вы можете использовать следущие зарезервированные имена клавиш: Del, Back, Ins, Insert, Enter, Return, PgUp, PgDn, Left, Right, Up, Down, Home, End, Space, Tab, Esc и Escape. Регистр в именах клавиш не важен (любые сочетания верхнего и нижнего регистра будут работать).</p>
<p>Напоминаем, что в Mac OS X описание горячих клавиш, использующих Ctrl, будет<br />
в действительности использовать клавишу Command.</p>
<p>Другой способ включить акселераторы — заполнить таблицу <code>wxAcceleratorTable</code><br />
объектами <code>wxAcceleratorEntry</code> и связать ее с окном, используя метод <code>wxWindow::SetAcceleratorTable</code>. Каждый объект <code>wxAcceleratorEntry</code> инициализируется битовым списком модификаторов (один или несколько <code>wxACCEL_ALT</code>,<br />
<code>wxACCEL_CTRL</code>, <code>wxACCEL_SHIFT</code> и <code>wxACCEL_NORMAL</code>), кодом клавиши (см. таблицу 6.3) и идентификатором. Например,</p>
<pre class="brush: cpp;">
wxAcceleratorEntry entries[4];
entries[0].Set(wxACCEL_CTRL, (int) ’N’, wxID_NEW);
entries[1].Set(wxACCEL_CTRL, (int) ’X’, wxID_EXIT);
entries[2].Set(wxACCEL_SHIFT, (int) ’A’, wxID_ABOUT);
entries[3].Set(wxACCEL_NORMAL, WXK_DELETE, wxID_CUT);
wxAcceleratorTable accel(4, entries);
frame-&gt;SetAcceleratorTable(accel);
</pre>
<p>Можно использовать несколько таблиц акселераторов в оконной иерархии, а также сочетать наборы акселераторов с определенной таблицей <code>wxAcceleratorTable</code>.</p>
<p>Это полезно, если у вас есть альтернативные акселераторы для отдельной команды, которые вы не можете целиком вписать в текст пункта меню.</p>
<h4>6.3 Обработка событий от джойстика</h4>
<p>Класс <code>wxJoystick</code> дает вашему приложению возможность получать информацию от одного или двух джойстиков в ОС Windows или Linux. Как правило, вы создаете объект <code>wxJoystick</code>, передавая <code>wxJOYSTICK1</code> или <code>wxJOYSTICK2</code> и храните объект в ОЗУ, пока он нужен. Когда вам нужно получить с него данные, пошлите функцию <code>SetCapture</code>, передав указатель на окно, которое будет получать события джойстика, а затем вызовите <code>ReleaseCapture</code>, если вам больше не нужны события. Вы можете поставить захват на все время работы приложения вызвав <code>SetCapture</code> при инициализации и <code>ReleaseCapture</code> при выходе.</p>
<p>Для более детального описания событий и методов рассмотрим пример samples/joystick из дистрибутива wxWidgets. Управляя джойстиком пользователь может рисовать последовательности линий на холсте, нажимая любую из кнопок джойстика. При нажатии также воспроизводится звук.</p>
<p>Ниже представлен фрагмент кода инициализации. Сначала приложение, создавая временный объект джойстика, проверяет, установлен ли джойстик и завершается, если нет. Звуковой файл buttonpress.wav загружается в объект <code>wxSound</code>, хранящийся в объекте приложения. Минимальная и максимальная позиции джойстика также сохраняются, чтобы линии помещались в окно.</p>
<pre class="brush: cpp;">
#include &quot;wx/wx.h&quot;
#include &quot;wx/sound.h&quot;
#include &quot;wx/joystick.h&quot;
bool MyApp::OnInit()
{
    wxJoystick stick(wxJOYSTICK1);
    if (!stick.IsOk())
    {
        wxMessageBox(wxT(&quot;No joystick detected!&quot;));
        return false;
    }
    m_fire.Create(wxT(&quot;buttonpress.wav&quot;));
    m_minX = stick.GetXMin();
    m_minY = stick.GetYMin();
    m_maxX = stick.GetXMax();
    m_maxY = stick.GetYMax();
    // Создаем главный фрейм окна
    ...
    return true;
}
</pre>
<p>MyCanvas — это окно, которое хранит объект джойстика, а также получает от<br />
него события. Вот реализация MyCanvas:</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
EVT_JOYSTICK_EVENTS(MyCanvas::OnJoystickEvent)
END_EVENT_TABLE()
MyCanvas::MyCanvas(wxWindow *parent, const wxPoint&amp; pos, const wxSize&amp; size):
wxScrolledWindow(parent, wxID_ANY, pos, size, wxSUNKEN_BORDER)
{
    m_stick = new wxJoystick(wxJOYSTICK1);
    m_stick-&gt;SetCapture(this, 10);
}

MyCanvas::~MyCanvas()
{
    m_stick-&gt;ReleaseCapture();
    delete m_stick;
}

void MyCanvas::OnJoystickEvent(wxJoystickEvent&amp; event)
{
    static long xpos = -1;
    static long ypos = -1;
    wxClientDC dc(this);
    wxPoint pt(event.GetPosition());
    // Если возможны отрицательные координаты, то делаем, чтобы минимум был 0
    int xmin = wxGetApp().m_minX;
    int xmax = wxGetApp().m_maxX;
    int ymin = wxGetApp().m_minY;
    int ymax = wxGetApp().m_maxY;
    if (xmin &lt; 0) {
        xmax += abs(xmin);
        pt.x += abs(xmin);
    }
    if (ymin &lt; 0) {
        ymax += abs(ymin);
        pt.y += abs(ymin);
    }
    // Масштабируем по размеру холста
    int cw, ch;
    GetSize(&amp;cw, &amp;ch);
    pt.x = (long) (((double)pt.x/(double)xmax) * cw);
    pt.y = (long) (((double)pt.y/(double)ymax) * ch);
    if (xpos &gt; -1 &amp;&amp; ypos &gt; -1 &amp;&amp; event.IsMove() &amp;&amp; event.ButtonIsDown())
    {
        dc.SetPen(*wxBLACK_PEN);
        dc.DrawLine(xpos, ypos, pt.x, pt.y);
    }
    xpos = pt.x;
    ypos = pt.y;
    wxString buf;
    if (event.ButtonDown())
        buf.Printf(wxT(&quot;Joystick (%d, %d) Fire!&quot;), pt.x, pt.y);
    else
        buf.Printf(wxT(&quot;Joystick (%d, %d)&quot;), pt.x, pt.y);
    frame-&gt;SetStatusText(buf);
    if (event.ButtonDown() &amp;&amp; wxGetApp().m_fire.IsOk())
    {
        wxGetApp().m_fire.Play();
    }
}
</pre>
<h4>6.3.1 События wxJoystick</h4>
<p>Класс <code>wxJoystick</code> создает события типа <code>wxJoystickEvent</code>. Соответствующие им макросы представлены в таблице 6.5. Каждый макрос принимает один аргумент —<br />
функцию обработки события.</p>
<ul>
<li><code>EVT_JOY_BUTTON_DOWN(func)</code> Обрабатывает событие <code>wxEVT_JOY_BUTTON_DOWN</code>, генерируемое при нажатии кнопки.</li>
<li><code>EVT_JOY_BUTTON_UP(func)</code> Обрабатывает событие <code>wxEVT_JOY_BUTTON_UP</code>, генерируемое при отпускании кнопки.</li>
<li><code>EVT_JOY_MOVE(func)</code> Обрабатывает событие <code>wxEVT_JOY_MOVE</code>, генерируемое при движении джойстика в плоскости XY.</li>
<li><code>EVT_JOY_ZMOVE(func)</code> Обрабатывает событие <code>wxEVT_JOY_ZMOVE</code>, генерируемое при движении джойстика по оси Z.</li>
<li><code>EVT_JOYSTICK_EVENTS(func)</code> Обрабатывает все события джойстика.</li>
</ul>
<h4>6.3.2 Методы класса wxJoystickEvent</h4>
<p>Ниже представлено описание функции класса <code>wxJoystickEvent</code>, которые вы можете вызывать для получения дополнительной информации о событии. Как обычно, вы можете вызвать функцию <code>GetEventType</code>, чтобы получить тип события, что полезно при использовании макроса <code>EVT_JOYSTICK_EVENTS</code>, который отлавливает все события от джойстика.</p>
<p>Вызов <code>ButtonDown</code> позволяет проверить, было ли событие вызвано нажатием кнопки. Вы можете дополнительно передать идентификатор кнопки <code>wxJOY_BUTTONn</code><br />
(где n = 1, 2, 3 или 4) чтобы определить, какая конкретно кнопка была нажата, или <code>wxJOY_BUTTON_ANY</code>, если вам это не важно. Метод <code>ButtonUp</code> работает также, но проверяет событие отпускание соответствующей кнопки. Метод <code>IsButton</code> равносилен применению конструкции <code>ButtonDown() || ButtonUp()</code>.</p>
<p>Чтобы проверить, была ли кнопка нажата во время генерации события (если, например, событие представляет не само нажатие кнопки), вызывите метод <code>ButtonIsDown</code> с теми же аргументами, что и ButtonDown. В противном случае используйте <code>GetButtonState</code> (с теми же аргументами), чтобы получить битовый список идентификаторов <code>wxJOY_BUTTONn</code>.<br />
Вызовете метод <code>IsMove</code> чтобы проверить, было ли событие движением в плоскости XY и <code>IsZMove</code> — по оси Z.<br />
Функция <code>GetPosition</code> возвращает объект <code>wxPoint</code> с текущей позицией в плоскости XY, а <code>GetZPosition</code> возвращает целое, представляющее собой Z-координату,<br />
если таковая поддреживается.</p>
<p>Наконец, вы можете определить, какой джойстик послужил причиной события (<code>wxJOYSTICK1</code> или <code>wxJOYSTICK2</code>) вызвав <code>GetJoystick</code>.</p>
<h4>6.3.3 Методы класса wxJoystick</h4>
<p>Мы не хотим приводить здесь все методы джойстика полностью, для этого вы можете обратиться к справочной информации по классу <code>wxJoystick</code>, но укажем наиболее интересные.</p>
<p>Как было показано в примере, функцию <code>SetCapture</code> необходимо вызывать для прямого получения данных с джойстика в определенное окно, и, соответственно, <code>ReleaseCapture</code> для освобождения и использования его другими приложениями. В случае, если джойстик занят другим приложением или неисправен, вызывайте <code>IsOK</code> перед попыткой захвата. Вы также можете определить характеристики джойстика при помощи функций <code>GetNumberButtons</code>, <code>GetNumberJoysticks</code>, <code>GetNumberAxes</code>, <code>HasRudder</code> и прочих.</p>
<p>Вы можете получить состояние джойстика извне обработчика события с такими фунциями как <code>GetPosition</code> и <code>GetButtonState</code>.</p>
<p>Вашему приложению почти всегда потребуется вызвать <code>GetXMin</code>, <code>GetXMax</code> и подобные функции для определения диапазона, поддерживаемого джойстиком.</p>
<h4>6.4 Заключение</h4>
<p>В этой главе вы узнали о получении данных с мыши, клавиатуры и джойстика. Теперь вы сможете добавить взаимодействие с устройствами ввода в ваше приложение. Для углубления степени понимания рекомендуем изучить примеры samples/keyboard, samples/joytest и samples/dragimag, а также класс <code>wxThumbnailCtrl</code> в examples/chap12 на прилагаемом CD-ROM.</p>
<p>Следующая глава расскажет, как можно добиться гибкой, переносимой, легко переводимой, и, прежде всего, привлекательной компоновки элементов окна с помощью нашего гибкого друга — сайзера (sizer).</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-vi-obrabotka-dannyx-s-ustrojstv-vvoda/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава X &#8211; Работа с Изображениями &#8211; Часть 2</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-2/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-2/#comments</comments>
		<pubDate>Thu, 22 Jan 2009 17:43:45 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=475</guid>
		<description><![CDATA[Читать первую часть главы Программирование с wxImage wxImage можно использовать, когда Вам нужен платформо-независимый класс работы с изображениями, или как промежуточный класс для загрузки и сохранения изображений. Формат хранения информации об изображении для каждого пикселя использует байт для красного, байт для зеленого, и байт для синего каналов, плюс дополнительный байт для пикселя, если изображение имеет [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-1/">Читать первую часть главы</a></p>
<h3>Программирование с wxImage</h3>
<p><code>wxImage</code> можно использовать, когда Вам нужен платформо-независимый класс работы с изображениями, или как промежуточный класс для загрузки и сохранения изображений. Формат хранения информации об изображении для каждого пикселя использует байт для красного, байт для зеленого, и байт для синего каналов, плюс дополнительный байт для пикселя, если изображение имеет альфа канал.</p>
<p>Основные функции <code>wxImage</code> в Таблице 10-6.<br />
<span id="more-475"></span><br />
<b>Таблица 10-6. <code>wxImage</code> Функции</b></p>
<ul>
<li><code>wxImage</code> &#8211; Изображение может быть создано с заданной шириной и высотой, из другого изображения, XPM данных, битовых данных (char[]) и опционально данных об альфа канале, из файла, су указанием типа файла, или из потока ввода.</li>
<li><code>ConvertAlphaToMask</code> &#8211; Конвертирует альфа канал (если есть) в маску.</li>
<li><code>ConvertToMono</code> &#8211; Конвертирует в новое монохромное изображение.</li>
<li><code>Copy</code> &#8211; Возвращает идентичную копию, не используя подсчета ссылок.</li>
<li><code>Create</code> &#8211; Создает изображение заданного размера, опционально инициализирует его из данных.</li>
<li><code>Destroy</code> &#8211; Удаляет внутренние данные, если никакой другой объект их не использует.</li>
<li><code>GetData, SetData</code> &#8211; Возвращают или задают указатель на внутренние данные (<code>unsigned char*</code>).</li>
<li><code>GetImageCount</code> &#8211; Возвращает количество изображений в файле или потоке.</li>
<li><code>GetOption, GetOptionInt, SetOption, HasOption</code> &#8211; Возвращают, задают, или проверяют объект на наличие опции.</li>
<li><code>GetSubImage</code> &#8211; Возвращает область изображения, как новое изображение.</li>
<li><code>GetWidth, GetHeight</code> &#8211; Возвращают размеры изображения.</li>
<li><code>Getred, GetGreen, GetBlue, SetRGB, GetAlpha, SetAlpha</code> &#8211; Возвращают, или задают значения красного, синего, зеленого, и альфа значения для пикселя.</li>
<li><code>HasMask, GetMaskRed, GetMaskGreen, GetMaskBlue, SetMaskColour</code> &#8211; Функции для проверки наличия маски, установки и взятия цвета маски.</li>
<li><code>LoadFile, SaveFile</code> &#8211; Загрузка из файла и сохранение изображения в файл.</li>
<li><code>Mirror</code> &#8211; Зеркально отображает изображение в заданном направлении, возвращает новое изображение.</li>
<li><code>Ok</code> &#8211; Возвращает true если изображение инициализировано.</li>
<li><code>Paste</code> &#8211; Вставляет изображение в текущее изображение, в заданной точке.</li>
<li><code>Rotate, Rotate90</code> &#8211; Вращает изображение, возвращает новое изображение.</li>
<li><code>SetMaskFromImage</code> &#8211; Устанавливает маску, определяет изображение или цвет, который нужно использовать для прозрачности.</li>
<li><code>Scale, Rescale</code> &#8211; Изменяют размеры изображения, возвращают новое изображение, или сохраняют изменения в текущем.</li>
</ul>
<h3>Загрузка и Сохранение Изображений</h3>
<p><code>wxImage</code> может загружать, или сохранять в нескольких форматах, используя обработчики, которые встроены в <code>wxImage</code> и обеспечают такую расширяемость. Обработчики форматов <code>wxImage</code> также используются для других классов растровых изображений, если те не имеют соответственной реализации операций с файлами.</p>
<p>В Таблице 10-7 указаны все типы обработчиков изображений, на платформах поддерживаемых wxWidgets. По-умолчанию всегда установлен <code>wxBMPHandler</code> обработчик. Для того, что бы использовать другие форматы, установите нужный обработчик с помощью <code>wxImage::AddHandler</code> или <code>wxInitAllImageHandlers</code>.</p>
<p>Если Вы используете определенный формат, у Вас должен быть вот такой код в вашей <code>wxApp::OnInit</code> функции:</p>
<pre class="brush: cpp;">
#include &quot;wx/image.h&quot;

wxImage::AddHandler( new wxPNGHandler );
wxImage::AddHandler( new wxJPEGHandler );
wxImage::AddHandler( new wxGIFHandler );
wxImage::AddHandler( new wxXPMHandler );
</pre>
<p>Или же можно просто вызвать:</p>
<pre class="brush: cpp;">
wxInitAllImageHandlers();
</pre>
<p>Ниже приведен пример загрузки и сохранения изображений из файлов и потоков. Учтите, при загрузке фалов, правильно указывать абсолютный путь к файлу, а не относительный путь для рабочей директории.</p>
<pre class="brush: cpp;">
// Загружаем изображение, используя конструктор, с указание типа файла
wxImage image(wxT(&quot;image.png&quot;), wxBITMAP_TYPE_PNG);
if (image.Ok())
{
    ...
}

// Оставляем wxImage самому определить тип файла
wxImage image(wxT(&quot;image.png&quot;));

// Загрузка в два шага
wxImage image;
if (image.LoadFile(wxT(&quot;image.png&quot;)))
{
    ...
}

// Загрузка в два шага, с использованием индекса изображения, для
// форматов, с несколькими изображениями в файле:
// загружаем изображение номер два, если оно есть
wxImage image;
int imageCount = wxImage::GetImageCount(wxT(&quot;image.tif&quot;));
if (imageCount &gt; 2)
    image.LoadFile(wxT(&quot;image.tif&quot;), wxBITMAP_TYPE_TIFF, 2);

// Загрузка из потока
wxFileInputStream stream(wxT(&quot;image.tif&quot;));
wxImage image;
image.LoadFile(stream, wxBITMAP_TYPE_TIF);

// Сохранение в файл
image.SaveFile(wxT(&quot;image.png&quot;)), wxBITMAP_TYPE_PNG);

// Сохранение в поток
wxFileOutputStream stream(wxT(&quot;image.tif&quot;));
image.SaveFile(stream, wxBITMAP_TYPE_TIF);
</pre>
<p>Изображения сохраняются в файл в 24-битном формате, за исключением XPM и PCX форматов, чьи обработчики подсчитывают количество цветов и сохраняют с нужной глубиной. В JPEG формате есть опция качества, которую можно установить перед сохранением. Значение является целым числом между 0 и 100, где 0 это наихудшее качество с высоким уровнем сжатия, и 100 наивысшее качество с плохим сжатием.</p>
<pre class="brush: cpp;">
// Сохраняем с оптимальным сжатием и компрессией
image.SetOption(wxIMAGE_OPTION_QUALITY, 80);
image.SaveFile(wxT(&quot;picture.jpg&quot;), wxBITMAP_TYPE_JPEG);
</pre>
<p>Вам может понадобиться использовать <code>wxImage::SetOption</code> когда Вы сохраняете XPM в поток, так как Вы не указываете при сохранении имя файла, и обработчик не будет знать какое значение присвоить переменной C, которая является частью данных XPM . Например:</p>
<pre class="brush: cpp;">
// Сохраняем XPM в поток
image.SetOption(wxIMAGE_OPTION_FILENAME, wxT(&quot;myimage&quot;));
image.SaveFile(stream, wxBITMAP_TYPE_XPM);
</pre>
<p>Учтите, обработчик добавит суффикс <code>_xpm</code>  к имени файла, которое Вы укажете.</p>
<h3>Прозрачность</h3>
<p>Есть два способа использования прозрачности в <code>wxImage</code>: маска и альфа канал. Один цвет изображения может быть указан как цвет маски, что приведет к автоматическому созданию объекта <code>wxMask</code> при конвертировании в <code>wxBitmap</code>.<br />
<code>wxImage</code> также поддерживает альфа канал. В дополнение к каждому байту в пикселе для красного, зеленого, и синего компонентов цвета, класс содержит байт, который указывает значение непрозрачности (opacity)  для данного пикселя. Значение альфа  0 соответствует прозрачному пикселю (нулевая непрозрачность), и значение 255 указывает на то, что пиксель 100% непрозрачный.<br />
Не у всех изображений есть альфа канал, и перед использованием <code>GetAlpha</code>, Вы должны проверить наличие альфа канал с помощью <code>HasAlpha</code>. В данный момент, альфа канал поддерживают только изображения, загруженные из PNG файлов, или изображения с назначенным альфа каналом функцией <code>SetAlpha</code>. Сохранение изображений с альфа каналом пока не поддерживается. Рисовать изображения с альфа каналом можно сконвертировав изображение в <code>wxBitmap</code> и вызвав <code>wxDC::DrawBitmap</code> или <code>wxDC::Blit</code>.<br />
В нижеприведенном коде показывается, как создать <code>wxImage</code> с маской. Изображение будет синим, и будет содержать прозрачный прямоугольник.</p>
<pre class="brush: cpp;">
// Создаем изображение с маской
// Сначала рисуем в wxBitmap
wxBitmap bitmap(400, 400);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.SetBackground(*wxBLUE_BRUSH);
dc.Clear();
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(50, 50, 200, 200);
dc.SelectObject(wxNullBitmap);

// Конвертируем растровое изображение (bitmap) в картинку (image)
wxImage image = bitmap.ConvertToImage();

// Устанавливаем красный как цвет маски
image.SetMaskColour(255, 0, 0);
</pre>
<p>Другой способ сделать маску – это создать ее из другого изображения. В следующем примере, <code>image.bmp</code> содержит основное изображение, и <code>mask.bmp</code> содержит черные пиксели, которые будут указывать на прозрачные области.</p>
<pre class="brush: cpp;">
// Загрузим изображение и его маску
wxImage image(wxT(&quot;image.bmp&quot;), wxBITMAP_TYPE_BMP);
wxImage maskImage(wxT(&quot;mask.bmp&quot;), wxBITMAP_TYPE_BMP);

// Укажем черный, как цвет маски
image.SetMaskFromImage(maskImage, 0, 0, 0);
</pre>
<p>Если Вы загрузили изображение с диска, Вы можете проверить его на прозрачность, и получить цвет маски:</p>
<pre class="brush: cpp;">
// Загружаем изображение с прозрачностью
wxImage image(wxT(&quot;image.png&quot;), wxBITMAP_TYPE_PNG);

// Получаем маску
if (image.HasMask())
{
    wxColour maskColour(image.GetMaskRed(),
    image.GetMaskGreen(),
    image.GetMaskBlue());
}
</pre>
<h3>Преобразования</h3>
<p><code>wxImage</code> поддерживает масштабирование, вращение, и зеркальное отражение картинки. Вот несколько примеров:</p>
<pre class="brush: cpp;">
// Масштабировать изображение как 200x200
// и назначить результат другому объекту.
// image1 не модифицируется.
wxImage image2 = image1.Scale(200, 200);

// Изменяем размер на 200x200
image1.Rescale(200, 200);

// Вращаем на указаное число радиан.
// image1 не модифицируется.
wxImage image2 = image1.Rotate(0.5);

// Вращаем на 90 градусов по часовой стрелке.
// image1 не модифицируется.
wxImage image2 = image1.Rotate90(true);

// Отражаем изображение по горизонтали.
// image1 не модифицируется.
wxImage image2 = image1.Mirror(true);
</pre>
<p>Уменьшение Цветности<br />
Если Вам нужно уменьшить количество цветов в изображении, Вы можете использовать статические функции класса <code>wxQuantize</code>. Нужная нам функция <code>Quantize</code>, в качестве аргументов принимает исходное изображение, возвращаемое изображение, выборочно палитру <code>wxPalette**</code> для сокращенных из изображения цветов, и желаемое количество цветов. Так же можно указать переменную типа <code>unsigned char**</code>, для получения 8-битного представления возвращаемого изображения и стиль, для лучшего управления возвращаемыми данными; для более детальной информации, смотрите справочное руководство.<br />
Данный пример показывает, как уменьшить цветность изображения до 256 цветов:</p>
<pre class="brush: cpp;">
#include &quot;wx/image.h&quot;
#include &quot;wx/quantize.h&quot;

wxImage image(wxT(&quot;image.png&quot;));

int maxColorCount = 256;
int colors = image.CountColours();
wxPalette* palette = NULL;
if (colors &gt; maxColorCount )
{
    wxImage reducedImage;
    if (wxQuantize::Quantize(image, reducedImage,
                               &amp; palette, maxColorCount))
    {
        colors = reducedImage.CountColours();
        image = reducedImage;
    }
}
</pre>
<p>С изображением может идти палитра, связанная с ним <code>wxPalette</code>, например когда изображение загружено из GIF файла. Тем не менее, изображение хранится в RGB формате, а палитра просто указывает значение индексов в RGB формате. Для <code>wxImage</code> также можно назначить палитру <code>wxPalette</code>, и в результате SaveFile может сохранить данное изображение с ограниченным количеством цветов. Например, если Windows BMP обработчик обнаруживает, что в опциях изображения указан <code>wxBMP_8BPP_PALETTE</code> формат, он сохраняет изображение с палитрой изображения; если указан формат <code>wxBMP_8BPP</code>, обработчик создает палитру из данных изображения. Некоторые обработчики сами производят уменьшение цветности, например  PCX, пока не подберут достаточное количество уникальных цветов. </p>
<p>Больше информации по wxPalette, смотрите в разделе &#8220;wxPalette&#8221; в Главе 5.</p>
<h3>Манипуляции Непосредственно с Данными wxImage</h3>
<p>Вы можете получить доступ непосредственно к данным изображения функцией <code>GetData</code> , для более быстрой манипуляции данными, чем через <code>GetRed</code>, <code>GetBlue</code>, <code>GetGreen</code>, и <code>SetRGB</code>. Ниже показан пример преобразования цветного изображения в черно-белое:</p>
<pre class="brush: cpp;">
void wxImage::ConvertToGrayScale(wxImage&amp; image)
{
    double red2Gray   = 0.297;
    double green2Gray = 0.589;
    double blue2Gray  = 0.114;
    int w = image.GetWidth(), h = image.GetHeight();
    unsigned char *data = image.GetData();

    int x,y;
    for (y = 0; y &lt; h; y++)
        for (x = 0; x &lt; w; x++)
        {
            long pos = (y * w + x) * 3;

            char g = (char) (data[pos]*red2Gray +
                              data[pos+1]*green2Gray +
                              data[pos+2]*blue2Gray);
            data[pos] = data[pos+1] = data[pos+2] = g;
        }
}
</pre>
<h3>Списки Изображений и Пакеты Иконок</h3>
<p>Иногда удобно объединять несколько изображений в один объект. Списки <code>wxImageList</code> можно использовать непосредственно в Вашем приложении, или для иконок элементов управления wxWidgets, которые используют списки изображений (image lists). <code>wxNotebook</code>, <code>wxTreeCtrl</code>, и <code>wxListCtrl</code> используют <code>wxImageList</code> для иконок в своих элементах. Также можно просто нарисовать отдельное изображение из списка <code>wxImageList</code> в контекст устройства.</p>
<p><code>wxImageList</code> создается с указанием высоты и ширины каждого изображения, булевым значением, которое указывает на то будет ли использоваться маска, и начальным размером списка (для внутренней оптимизации). Потом нужно добавить несколько <code>wxBitmap</code> или <code>wxIcon</code> изображений. Для списков нельзя использовать <code>wxImage</code> объект, но можно передать его в конструктор <code>wxBitmap</code>. <code>wxImageList::Add</code> возвращает целочисельный индекс, который потом можно использовать как идентификатор изображения; после того, как Вы добавите изображение в список, Вы можете его уничтожить, потому что <code>wxImageList</code> делает его копию.</p>
<p>Далее несколько примеров создания <code>wxImageList</code> и добавления в него изображений.</p>
<pre class="brush: cpp;">
// СозданиеImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);

// Добавление растрового изображения с прозрачностью из PNG
wxBitmap bitmap1(wxT(&quot;image.png&quot;), wxBITMAP_TYPE_PNG);
imageList-&gt;Add(bitmap1);

// Добавление изображения с прозрачностью из другого растрового изображения
wxBitmap bitmap2(wxT(&quot;image.bmp&quot;), wxBITMAP_TYPE_BMP);
wxBitmap maskBitmap(wxT(&quot;mask.bmp&quot;), wxBITMAP_TYPE_BMP);
imageList-&gt;Add(bitmap2, maskBitmap);

// Добавление растрового изображения с маской, указанной цветом маски
wxBitmap bitmap3(wxT(&quot;image.bmp&quot;), wxBITMAP_TYPE_BMP);
imageList-&gt;Add(bitmap3, *wxRED);

// Добавление иконки
#include &quot;folder.xpm&quot;
wxIcon icon(folder_xpm);
imageList-&gt;Add(icon);
</pre>
<p>Можно нарисовать изображение непосредственно в контекст устройства, передав флаг, который указывает, как будет нарисовано изображение. wxIMAGELIST_DRAW_TRANSPARENT, например, указывает, что изображение рисуется с использованием прозрачности, есть еще три формата рисования: <code>wxIMAGELIST_DRAW_NORMAL<code>, <code>wxIMAGELIST_DRAW_SELECTED</code>, или <code>wxIMAGELIST_DRAW_FOCUSED</code>.</p>
<pre class="brush: cpp;">
// Рисуем все изображения в списке
wxClientDC dc(window);
size_t i;
for (i = 0; i &lt; imageList-&gt;GetImageCount(); i++)
{
    imageList-&gt;Draw(i, dc, i*16, 0, wxIMAGELIST_DRAW_NORMAL|
                                    wxIMAGELIST_DRAW_TRANSPARENT);
}
</pre>
<p>Для того, что бы назначить иконки вкладкам блокнота (notebook), нужно создать список изображений с иконками 16x16 , и вызвать <code>wxNotebook::SetImageList</code> или <code>wxNotebook::AssignImageList</code>. Если Вы будете использовать первый вариант, блокнот не будет удалять список, когда будет уничтожатся; во втором варианте, блокнот принимает на себя управление списком и Вам не нужно волноваться из-за удаления списка изображений. Теперь, когда Вы добавляете страницы в блокнот, Вы можете указать индекс иконки, которая будет показываться возле текста на вкладке (или вместо него, если на вкладке нет надписи). Ниже показан пример кода, где добавляется две страницы с иконками на вкладках.</p>
<pre class="brush: cpp;">
// Создадим wxImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);

// Добавим несколько иконок
wxBitmap bitmap1(wxT(&quot;folder.png&quot;), wxBITMAP_TYPE_PNG);
wxBitmap bitmap2(wxT(&quot;file.png&quot;), wxBITMAP_TYPE_PNG);
int folderIndex = imageList-&gt;Add(bitmap1);
int fileIndex = imageList-&gt;Add(bitmap2);

// Создадим блокнот с двумя страницами
wxNotebook* notebook = new wxNotebook(parent, wxID_ANY);
wxPanel* page1 = new wxPanel(notebook, wxID_ANY);
wxPanel* page2 = new wxPanel(notebook, wxID_ANY);

// Назначим список изображений
notebook-&gt;AssignImageList(imageList);

// Добавим страницы с иконками
notebook-&gt;AddPage(page1, wxT(&quot;Folder options&quot;), true, folderIndex);
notebook-&gt;AddPage(page2, wxT(&quot;File options&quot;), false, fileIndex);
</pre>
<p>В <code>wxTreeCtrl</code> и <code>wxListCtrl</code> используется тот же принцип с указанием списка изображений, или назначением его элементу (когда элемент управления берет на себя удаление списка).</p>
<p>Если у Вас много иконок, и Вам трудно управлять ими с помощью индексов, можете написать собственный класс, который ассоциирует индексы с символьными именами. Ниже показан простейший пример как это можно реализовать:</p>
<pre class="brush: cpp;">
#include &quot;wx/hashmap.h&quot;

WX_DECLARE_STRING_HASH_MAP(int, IconNameToIndexHashMap);

// Класс для обращения к индексам через имя
class IconNameToIndex
{
public:
    IconNameToIndex() {}

    // Добавление изображения с именем в список изображений
    void Add(wxImageList* list, const wxBitmap&amp; bitmap,
        const wxString&amp; name) {
        m_hashMap[name] = list-&gt;Add(bitmap);
    }

    // Добавление иконки с именем в список изображений
    void Add(wxImageList* list, const wxIcon&amp; icon,
        const wxString&amp; name) {
        m_hashMap[name] = list-&gt;Add(icon);
    }

    // Поиск индекса по имени
    int Find(const wxString&amp; name) { return m_hashMap[name]; }

private:
    IconNameToIndexHashMap m_hashMap;
};
</pre>
<p><code>wxIconBundle</code> это класс для набора изображений, но он предназначен для хранения разных разрешений одного изображения, а не множества картинок. Этот класс помогает подобрать системе картинку нужного размера. Например, иконка из заголовка окна может быть меньше, чем та же иконка файла, или иконка в менеджере задач. Ниже показан пример использования пакета иконок (icon bundle).</p>
<pre class="brush: cpp;">
// Создаем пакет с одной иконкой
#include &quot;file16x16.xpm&quot;
wxIconBundle iconBundle(wxIcon(file16x16_xpm));

// Добавляем иконку из файла
iconBundle.Add(wxIcon(wxT(&quot;file32x32.png&quot;), wxBITMAP_TYPE_PNG));

// Создаем пакет иконок из нескольких иконок в одном фале
wxIconBundle iconBundle2(wxT(&quot;multi-icons.tif&quot;), wxBITMAP_TYPE_TIF);

// Получает иконку с заданным размером, или если не найдена, берет иконку
// с размерами wxSYS_ICON_X, wxSYS_ICON_Y
wxIcon icon = iconBundle.GetIcon(wxSize(16,16));

// Назначает пакет иконок приложению
wxFrame* frame = new wxFrame(parent, wxID_ANY);
frame-&gt;SetIcons(iconBundle);
</pre>
<p>В Windows, <code>SetIcons</code> извлекает иконки размером 16x16 и 32x32 из пакета.</p>
<h3>Настройка Графики в wxWidgets</h3>
<p><code>wxArtProvider</code> класс – это класс, который позволяет настраивать встроенную графику ("art") в wxWidgets приложениях. Например, Вы хотите заменить стандартные иконки в wxWidgets HTML справке или иконки в общих диалогах, таких как просмотрщик логов.<br />
В wxWidgets есть стандартный объект <code>wxArtProvider</code>, и когда вашей программе нужна графическая информация, вызывается <code>wxArtProvider::GetBitmap</code> и <code>wxArtProvider::GetIcon</code> для получения иконок.</p>
<p>У графических объектов есть два идентификатора: графический идентификатор (<code>wxArtID</code>) и пользовательский идентификатор (<code>wxArtClient</code>). Пользовательский идентификатор применяется, если разным окнам нужно использовать разные изображения для одних графических идентификаторов. Как пример, окно справки wxHTML использует следующий код, для изображения кнопки "назад" на панели инструментов:</p>
<pre class="brush: cpp;">
wxBitmap bmp = wxArtProvider::GetBitmap(wxART_GO_BACK,wxART_TOOLBAR);
</pre>
<p>Вы можете посмотреть идентификаторы и графику, встроенную в wxWidgets, скомпилировав и запустив проект <code>samples/artprov</code> в wxWidgets директории. На Изображении 10-1 показано окно браузера графики.</p>
<p>Для того, что бы заменить графические элементы wxWidgets, создайте производный класс из <code>wxArtProvider</code>, перегрузите <code>CreateBitmap</code>, и вызовите <code>wxArtProvider::PushProvider</code> в <code>OnInit</code> функции для того, что бы wxWidgets использовала ваш класс. Ниже показан пример замени большинства графики окна справки <code>wxHTML</code>.</p>
<pre class="brush: cpp;">
// XPM’ы с графикой
#include &quot;bitmaps/helpbook.xpm&quot;
#include &quot;bitmaps/helppage.xpm&quot;
#include &quot;bitmaps/helpback.xpm&quot;
#include &quot;bitmaps/helpdown.xpm&quot;
#include &quot;bitmaps/helpforward.xpm&quot;
#include &quot;bitmaps/helpoptions.xpm&quot;
#include &quot;bitmaps/helpsidepanel.xpm&quot;
#include &quot;bitmaps/helpup.xpm&quot;
#include &quot;bitmaps/helpuplevel.xpm&quot;
#include &quot;bitmaps/helpicon.xpm&quot;

#include &quot;wx/artprov.h&quot;

// Класс графики
class MyArtProvider : public wxArtProvider
{
protected:
    virtual wxBitmap CreateBitmap(const wxArtID&amp; id,
                                  const wxArtClient&amp; client,
                                  const wxSize&amp; size);
};

// CreateBitmap функция
wxBitmap MyArtProvider::CreateBitmap(const wxArtID&amp; id,
                                     const wxArtClient&amp; client,
                                     const wxSize&amp; size)
{
    if (id == wxART_HELP_SIDE_PANEL)
        return wxBitmap(helpsidepanel_xpm);
    if (id == wxART_HELP_SETTINGS)
        return wxBitmap(helpoptions_xpm);
    if (id == wxART_HELP_BOOK)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_FOLDER)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_PAGE)
        return wxBitmap(helppage_xpm);
    if (id == wxART_GO_BACK)
        return wxBitmap(helpback_xpm);
    if (id == wxART_GO_FORWARD)
        return wxBitmap(helpforward_xpm);
    if (id == wxART_GO_UP)
        return wxBitmap(helpup_xpm);
    if (id == wxART_GO_DOWN)
        return wxBitmap(helpdown_xpm);
    if (id == wxART_GO_TO_PARENT)
        return wxBitmap(helpuplevel_xpm);
    if (id == wxART_FRAME_ICON)
        return wxBitmap(helpicon_xpm);
    if (id == wxART_HELP)
        return wxBitmap(helpicon_xpm);

    // Любые иконки wxWidgets, которые здесь не реализованы,
    // будут поставлены «родным» классом графики.
    return wxNullBitmap;
}

// Инициализация
bool MyApp::OnInit()
{
    ...

    wxArtProvider::PushProvider(new MyArtProvider);

    ...
    return true;
}
</pre>
<h3>Итоги</h3>
<p>В этой главе мы рассмотрели использование четырех основных классов изображений <code>wxBitmap</code>, <code>wxIcon</code>, <code>wxCursor</code>, и <code>wxImage</code> и  двух классов для объединения изображений wxImageList и wxIconBundle. Также мы посмотрели, как можно заменить иконки и изображения wxWidgets своими собственными. Для примеров использования классов изображений, смотрите <code>samples/image</code>, <code>samples/listctrl</code>, и <code>samples/dragimag</code> в wxWidgets директории.<br />
В следующей главе  мы рассмотрим классы, которые позволяют реализовать  перенос данных с помощью буфера обмена и drag’n’drop.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава X &#8211; Работа с Изображениями &#8211; Часть 1</title>
		<link>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-1/</link>
		<comments>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-1/#comments</comments>
		<pubDate>Thu, 22 Jan 2009 17:40:03 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info/?p=471</guid>
		<description><![CDATA[Скачать PDF-версию (942 КБ) В этой главе рассматривается работа с растровыми изображениями. Изображения очень важны для &#8220;дизайна&#8221; вашего приложения, и могут использоваться с элементами управления, например с панелями инструментов, списками, вкладками, кнопками, HTML окнами, или при рисовании. Иногда их можно сделать невидимыми в приложении, например, когда нужно избежать мерцания во время прорисовки. В этой главе, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://depositfiles.com/files/f9fxhcftj">Скачать PDF-версию (942 КБ)</a></p>
<p>В этой главе рассматривается работа с растровыми изображениями. Изображения очень важны для &#8220;дизайна&#8221; вашего приложения, и могут использоваться с  элементами управления, например с  панелями инструментов, списками, вкладками, кнопками, HTML окнами, или при рисовании. Иногда их можно сделать невидимыми в приложении, например, когда нужно избежать мерцания во время прорисовки. В этой главе, мы рассмотрим разные классы изображений и методы перегрузки стандартных классов иконок и изображений, которые есть в wxWidgets.<br />
<span id="more-471"></span></p>
<h3>Программирование с использованием wxBitmap</h3>
<p>С помощью <code>wxBitmap</code> Вы можете делать несколько вещей:</p>
<ul>
<li>Рисовать его в окне с помощью контекста устройства.</li>
<li>Использовать его, как изображение для таких классов, как <code>wxBitmapButton</code>, <code>wxStaticBitmap</code>, или <code>wxToolBar</code>.</li>
<li>Использовать его для рисования методом  двойной буферизации (рисования в невидимом буфере <code>wxMemoryDC</code>, перед тем как рисовать в окне).</li>
</ul>
<p>На некоторых платформах (в частности на Windows), растровые изображения имеют ограниченные ресурсы, и если у Вас много изображений, которые Вам  нужно хранить в памяти, предпочтительней работать с <code>wxImage</code> объектами и конвертировать их во временный <code>wxBitmap</code> для рисования в контексте устройства.</p>
<p>Перед тем, как мы обсудим создание wxBitmap и рисование с его помощью, давайте рассмотрим функции класса (Таблица 10-2).</p>
<ul>
<li><code>wxBitmap</code> &#8211; Растровое изображение может быть создано с заданными высотой и шириной, из другого растрового изображения, из <code>wxImage</code>, XPM данных (<code>char**</code>), битовых данных (<code>char[]</code>), или из файла, с указанием имя файла и его типа.</li>
<li><code>ConvertToImage</code> &#8211; Конвертирует в <code>wxImage</code>, с сохранением прозрачности.</li>
<li><code>CopyFromIcon</code> &#8211; Создает растровое изображение из <code>wxIcon</code>.</li>
<li><code>Create</code> &#8211; Создает растровое изображения из данных, или заданного размера.</li>
<li><code>GetWidth</code>, <code>GetHeight</code> &#8211; Возвращает размеры растрового изображения.</li>
<li><code>GetDepth</code> &#8211; Возвращает глубину цвета изображения.</li>
<li><code>GetMask</code>, <code>SetMask</code> &#8211; Возвращает  <code>wxMask</code> объект или <code>NULL</code>.</li>
<li><code>GetSubBitmap</code> &#8211; Возвращает область текущего изображения, как новое растровое изображение.</li>
<li><code>LoadFile</code>, <code>SaveFile</code> &#8211; Загружает файл и (для некоторых форматов) сохраняет его.</li>
<li>Ok</code> - Возвращает <code>true</code>, если объект содержит данные растрового изображения.</li>
</ul>
<h3>Создание wxBitmap</h3>
<p>Есть несколько способов создать объект <code>wxBitmap</code>.<br />
Вы можете создать неинициализированный объект (без данных изображения), используя конструктор по умолчанию. Вам нужно будет вызвать <code>Create</code>, <code>LoadFile</code> или назначить объекту существующее растровое изображение для того, что бы с ним работать.<br />
Вы можете создать <code>wxBitmap</code>, задав ему размер, и глубину. Созданное растровое изображение будет заполнено произвольными данными, поэтому Вам придется на нем что-нибудь нарисовать. Снизу показан пример, который создает  изображение 200 x 100 пикселей, и задает ему белый цвет фона.</p>
<pre class="brush: cpp;">
// Создает изображение размером 200x100 пикселей с текущей глубиной дисплея.
wxBitmap bitmap(200, 100,  -1);

// Создаем контекст устройства памяти (memory device context, далее DC)
wxMemoryDC dc;

// Назначаем контексту устройства наше изображение
dc.SelectObject(bitmap);

// задаем белый фон
dc.SetBackground(*wxWHITE_BRUSH);

// Закрашиваем изображение белым (очищаем)
dc.Clear();

// Отключаем изображение от контекста
dc.SelectObject(wxNullBitmap);
</pre>
<p>Вы можете создать растровое изображение из любой картинки, сохранив при этом маску, или альфа канал исходного изображения:</p>
<pre class="brush: cpp;">
// Загружаем картинку из файла
wxImage image(wxT(&quot;image.png&quot;), wxBITMAP_TYPE_PNG);

// Конвертируем в растровое изображение
wxBitmap bitmap(image);
</pre>
<p>Растровое изображение так же можно создать, используя иконку, функцией <code>CopyFromIcon</code>:</p>
<pre class="brush: cpp;">
// Загружаем иконку
wxIcon icon(wxT(&quot;image.xpm&quot;), wxBITMAP_TYPE_XPM);

// Конвертируем иконку в растровое изображение
wxBitmap bitmap;
bitmap.CopyFromIcon(icon);
</pre>
<p>Или же можно загрузить изображение из файла:</p>
<pre class="brush: cpp;">
// Load from a file
wxBitmap bitmap(wxT(&quot;picture.png&quot;, wxBITMAP_TYPE_PNG);
if (!bitmap.Ok())
{
    wxMessageBox(wxT(&quot;Sorry, could not load file.&quot;));
}
</pre>
<p><code>wxBitmap</code> может загружать все типы файлов, которые может загружать <code>wxImage</code> (смотрите Таблицу 10-7), используя <code>wxImage</code> или более эффективную реализацию некоторых типов файлов для конкретной платформы. wxWidgets поддерживает наиболее популярные форматы PNG, JPEG, TIFF, BMP, и XPM, загрузка и сохранение которых поддерживается на всех платформах.<br />
<strong>Таблица 10-7. Доступные Обработчики Форматов  Изображений</strong></p>
<ul>
<li><code>wxBMPHandler</code> - Для загрузки и сохранения Windows файлов растровых изображений.</li>
<li><code>wxPNGHandler</code> - Для загрузки и сохранения  файлов PNG. Поддерживаются изображения с прозрачностью и альфа каналом.</li>
<li><code>wxJPEGHandler</code> - Для загрузки и сохранения файлов JPEG.</li>
<li><code>wxGIFHandler</code> - GIF файлы: только для загрузки, из-за юридических вопросов.</li>
<li><code>wxPCXHandler</code> - Для загрузки и сохранения PCX файлов. <code>wxPCXHandler</code> подсчитывает количество цветов в изображении; если в изображении 256 или меньше, оно будет сохранено в 8-битном формате; в противном случае в 24-битном.</li>
<li><code>wxPNMHandler</code> - Для загрузки и сохранения PNM файлов. Загрузка PNMs работает только для ASCII или строковых RGB изображений. При сохранении в PNM формате, wxPNMHasndler всегда сохраняет в строковом RGB.</li>
<li><code>wxTIFFHandler</code> - Для загрузки и сохранения TIFF файлов.</li>
<li><code>wxIFFHandler</code> - Для загрузки IFF файлов.</li>
<li><code>wxXPMHandler</code> - Для загрузки и сохранения XPM файлов.</li>
<li><code>wxICOHandler</code> - Для загрузки и сохранения Windows иконок.</li>
<li><code>wxCURHandler</code> - Для загрузки и сохранения файлов курсора Windows.</li>
<li><code>wxANIHandler</code> - Для загрузки и сохранения анимированных файлов курсора Windows.</li>
</ul>
<p>Также можно загрузить PICT ресурсы для Mac OS X, указав <code>wxBITMAP_TYPE_PICT_RESOURCE</code>.<br />
Если Вы хотите загрузить специфические ресурсы для данной платформы, Вы можете использовать <code>wxBITMAP</code> макрос. Например:</p>
<pre class="brush: cpp;">
#if !defined(__WXMSW__) &amp; !defined(__WXPM__)
#include &quot;picture.xpm&quot;
#endif

wxBitmap bitmap(wxBITMAP(picture));
</pre>
<p>На Windows и OS/2 этот код будет загружать ресурс <code>picture</code> из исполняемого файла, на всех других платформах, он будет загружать переменную <code>picture_xpm</code>  из XPM файла. В любом случае XPM поддерживается всеми платформами, поэтому необходимости в этом макросе нет.</p>
<h3>Использование wxMask</h3>
<p>Каждый объект <code>wxBitmap</code> может иметь <code>wxMask</code>, монохромное растровое изображение, которое указывает прозрачные области основного растрового изображения. Оно создается автоматически, когда Вы загружаете изображение с прозрачностью, например XPM, PNG, или GIF изображения, но Вы можете создать его программно, и назначить функцией <code>SetMask</code>. Создать <code>wxMask</code> можно из <code>wxBitmap</code>, или из <code>wxBitmap</code>, с заданием цвета, который будет указывать на прозрачную область.</p>
<p>Следующий пример создает монохромное прозрачное изображение <code>mainBitmap</code>, шириной в 32 пикселя и 32 пикселя высотой, из данных растрового изображения (<code>imageBits</code>) и маски (<code>maskBits</code>), где 1 это черный а 0 белый для битов изображения, и 1 непрозрачность а 0 прозрачность для маски.</p>
<pre class="brush: cpp;">
static char imageBits[] = { 255, 255, 255, 255, 31,
  255, 255, 255, 31, 255, 255, 255, 31, 255, 255, 255,
  31, 255, 255, 255, 31, 255, 255, 255, 31, 255, 255,
  255, 31, 255, 255, 255, 31, 255, 255, 255, 25, 243,
  255, 255, 19, 249, 255, 255, 7, 252, 255, 255, 15, 254,
  255, 255, 31, 255, 255, 255, 191, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255 };

static char maskBits[] = { 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 255, 31, 0, 0, 255,
  31, 0, 0, 254, 15, 0, 0, 252, 7, 0, 0, 248, 3, 0, 0,
  240, 1, 0, 0, 224, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0 };

wxBitmap mainBitmap(imageBits, 32, 32);
wxBitmap maskBitmap(maskBits, 32, 32);
mainBitmap.SetMask(new wxMask(maskBitmap));
</pre>
<h3>Формат XPM</h3>
<p>Если Вам нужны небольшие растровые изображения с прозрачностью, например для кнопок на панели инструментов или для изображений на вкладках и списках, в wxWidgets очень удобно использовать XPM формат. Преимущество этого формата в том, что он использует C/C++ синтаксис, таким образом он может подгружаться динамически, и компилироваться в вашу программу. Например:</p>
<pre class="brush: cpp;">
// Также можно использовать #include &quot;open.xpm&quot;

static char *open_xpm[] = {
/* columns rows colors chars-per-pixel */
&quot;16 15 5 1&quot;,
&quot;  c None&quot;,
&quot;. c Black&quot;,
&quot;X c Yellow&quot;,
&quot;o c Gray100&quot;,
&quot;O c #bfbf00&quot;,
/* pixels */
&quot;                &quot;,
&quot;          ...   &quot;,
&quot;         .   . .&quot;,
&quot;              ..&quot;,
&quot;  ...        ...&quot;,
&quot; .XoX.......    &quot;,
&quot; .oXoXoXoXo.    &quot;,
&quot; .XoXoXoXoX.    &quot;,
&quot; .oXoX..........&quot;,
&quot; .XoX.OOOOOOOOO.&quot;,
&quot; .oo.OOOOOOOOO. &quot;,
&quot; .X.OOOOOOOOO.  &quot;,
&quot; ..OOOOOOOOO.   &quot;,
&quot; ...........    &quot;,
&quot;                &quot;
};

wxBitmap bitmap(open_xpm);
</pre>
<p>Как Вы видите, XPM файлы состоят из символьных данных. Перед данными собственно изображения, записана палитра, где к каждому символу привязан свой цвет, с использованием встроенного идентификатора цвета, или  шести-цифровым числом в шестнадцатеричном формате, перед которым ставится шестнадцатеричный флаг “#”. Идентификатор <code>None</code> указывает на прозрачную область изображения. Формат XPM непопулярен в графических редакторах под Windows, но Вы можете сохранить изображение как PNG и конвертировать его в XPM с помощью ImageBlocks (поставляется с DialogBlocks), или можно самому написать свой конвертер, используя wxWidgets.</p>
<h3>Рисование растровых изображений (Bitmaps)</h3>
<p>Растровое изображение непосредственно можно нарисовать двумя разными способами. Вы можете ассоциировать (назначить)  его контексту устройства памяти (<code>wxMemoryDC</code>) и потом использовать <code>wxDC::Blit</code> для того, что бы перенести содержимое растрового изображения в другой контекст устройства. Или же можно просто использовать <code>wxDC::DrawBitmap</code>. В обоих случаях, если изображение имеет прозрачность или альфа канал, Вы должны указать это, передав <code>true</code> в функцию.<br />
В этом примере показаны оба метода:</p>
<pre class="brush: cpp;">
// Рисование растрового изображения с wxMemoryDC
wxMemoryDC memDC;
memDC.SelectObject(bitmap);

// Рисуем в координатах 100, 100 на конечном DC
destDC.Blit(100, 100,                         // Draw at (100, 100)
    bitmap.GetWidth(), bitmap.GetHeight(),    // Draw full bitmap
    &amp;amp; memDC,                                  // Draw from memDC
    0, 0,                                     // Draw from bitmap origin
    wxCOPY,                                   // Logical operation
    true);                                    // Take mask into account
memDC.SelectObject(wxNullBitmap);

// Альтернативный способ: используем DrawBitmap
destDC.DrawBitmap(bitmap, 100, 100, true);
</pre>
<p>Более детально рисование растровых изображений описывается в Главе 5 "Рисование и Печать".</p>
<h3>Упаковка графических ресурсов</h3>
<p>Если Вы программировали под Windows, Вы привыкли загружать растровые изображения из ресурсов исполняемых файлов. Вы можете не изменять своей привычке, и загружать их из ресурсов, используя <code>wxBITMAP_TYPE_BMP_RESOURCE</code> в конструкторе, но скорее всего Вы предпочитаете менее платформозависимый метод.<br />
Очень удобный способ паковать ресурсы, будь то растровые изображения, HTML файлы, или другие файлы, используемые в приложении, хранить их в одном zip архиве отдельно от исполняемого файла или в отдельной директории данных. Также Вы можете использовать функциональность виртуальных файловых систем в wxWidgets, что бы загружать изображение прямо из zip архива, как показано в следующем примере.</p>
<pre class="brush: cpp;">
// Создадим новый объект файловой системы
wxFileSystem*fileSystem = new wxFileSystem;

wxString archiveURL(wxT(&quot;myapp.bin&quot;));
wxString filename(wxT(&quot;myimage.png&quot;));
wxBitmapType bitmapType = wxBITMAP_TYPE_PNG;

// Создаем URL
wxString combinedURL(archiveURL + wxString(wxT(&quot;#zip:&quot;)) + filename);
wxImage image;
wxBitmap bitmap;

// Открываем архив
wxFSFile* file = fileSystem-&gt;OpenFile(combinedURL);
if (file)
{
    wxInputStream* stream = file-&gt;GetStream();

    // Load and convert to a bitmap
    if (image.LoadFile(* stream, bitmapType))
        bitmap = wxBitmap(image);

    delete file;
}
delete fileSystem;

if (bitmap.Ok())
{
    ...
}
</pre>
<p>Более подробно о виртуальных файловых системах, Вы сможете узнать в Главе 14, "Файлы и Потоки".</p>
<h3>Программирование с wxIcon</h3>
<p><code>wxIcon</code> это небольшое растровое изображение, у которого всегда есть маска. <code>wxIcon</code> можно использовать:</p>
<ul>
<li>Как иконку для фрейма или диалога</li>
<li>Как иконку для <code>wxTreeCtrl</code>, <code>wxListCtrl</code>, или <code>wxNotebook</code> через <code>wxImageList</code> класс (смотрите дальше в этой главе)</li>
<li>Рисовать иконку в контексте устройства, используя <code>wxDC::DrawIcon</code></li>
</ul>
<p><strong>Таблица 10-3 основные функции класса.</strong></p>
<ul>
<li><code>wxIcon</code> - Иконка может быть создана с использованием другой иконки, XPM данных (char**), битовых данных (char[]), или из файла с заданным форматом.
<li><code>CopyFromBitmap</code> - Создает иконку из wxBitmap.
<li><code>GetWidth</code>, <code>GetHeight</code> - Возвращает размер иконки.
<li><code>GetDepth</code> - Возвращает глубину иконки.
<li><code>LoadFile</code> - Загружает иконку из файла.
<li><code>Ok</code> - Возвращает <code>true</code>, если присутствуют данные иконки.
</ul>
<h3>Создание wxIcon</h3>
<p>Объект <code>wxIcon</code> можно создать, используя XPM данные, подключенные к приложению, из объекта <code>wxBitmap</code>, из битовых данных, или загрузить ее из файла, например из XPM файла с прозрачностью. В wxWidgets есть <code>wxICON</code> макрос, аналогичный к <code>wxBITMAP</code> макросу, который был рассмотрен выше, для загрузки из ресурса, характерного для данной платформы либо из XPM данных.<br />
В Windows, <code>LoadFile</code> и схожий конструктор будет работать для Windows растровых изображений (BMP) и иконок (ICO), ресурсов и файлов. Если Вы хотите работать с другим форматом, загрузите файл в <code>wxBitmap</code> и сконвертируйте в иконку.<br />
На Mac OS X и Unix/Linux с использованием GTK+, <code>wxIcon</code> имеет те же возможности при загрузке из файла, что и <code>wxBitmap</code>.<br />
В ниже поданном примере показано создание <code>wxIcon</code> объекта разными способами.</p>
<pre class="brush: cpp;">
// Метод 1: загрузка из XPM данных
#include &quot;icon1.xpm&quot;
wxIcon icon1(icon1_xpm);

// Метод 2: загрузка из ICO ресурса (только для Window и OS/2)
wxIcon icon2(wxT(&quot;icon2&quot;));

// Метод 3: загрузка из ICO файла (только для Window и OS/2)
// Вы можете указывать желаемый размер, так как файл
// может содержать несколько иконок.
wxIcon icon3(wxT(&quot;icon3.ico&quot;), wxBITMAP_TYPE_ICO, 16, 16);

// Метод 4: создание из растрового изображения
wxIcon icon4;
wxBitmap bitmap(wxT(&quot;icon4.png&quot;), wxBITMAP_TYPE_PNG);
icon4.CopyFromBitmap(bitmap);
</pre>
<h3>Использование wxIcon</h3>
<p>В этом коде показаны три разных способа использования иконки <code>wxIcon</code>: установка как иконки фрейма, добавление иконки в список изображений и рисование иконки в контексте устройства.</p>
<pre class="brush: cpp;">
#include &quot;myicon.xpm&quot;
wxIcon icon(myicon_xpm);

// 1: Установка иконкой фрейма
frame-&gt;SetIcon(icon);

// 2: Добавление в wxImageList
wxImageList* imageList = new wxImageList(16, 16);
imageList-&gt;Add(icon);

// 3: Рисование иконки в точке (10, 10)
wxClientDC dc(window);
dc.DrawIcon(icon, 10, 10);
</pre>
<h3>Назначение Иконки Приложению</h3>
<p>Назначить иконку приложению (для того, что бы операционная система использовала ее как значок приложения), нельзя с помощью инструментов wxWidgets, это одно из немногих мест, где Вы должны использовать разные способы для разных платформ.<br />
На Windows, нужно добавить скрипт ресурса (расширение .rc) в ваш makefile,  или в файл проекта,  и добавить выражение <code>ICON</code> в файле .rc, например:</p>
<pre class="brush: cpp;">
aardvarkpro ICON aardvarkpro.ico
#include &quot;wx/msw/wx.rc&quot;
</pre>
<p>Здесь, aardvarkpro.ico это имя файла Windows иконки  с разными разрешениями и глубиной (обычно разрешения  48x48, 32x32 и 16x16). Когда иконка показывается в Проводнике (Windows Explorer), Windows рассматривает иконки из ресурса в алфавитном порядке, таким образом, если в ресурсе у Вас несколько иконок, удостоверьтесь, что нужная иконка для приложения в алфавитном порядке первая в списке; иначе на рабочем столе или в директории будет не та иконка, которую Вы ожидали увидеть.<br />
На Mac, Вам нужно подготовить пакет (bundle) для приложения, в которой есть ICNS файлы. Больше информации о пакетах Вы найдете в разделе об установке в Главе 20, "Сделаем Ваше приложение Идеальным"; нужная секция файла в пакете Info.plist например, может выглядеть вот так:</p>
<pre class="brush: cpp;">
&lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;
  &lt;array&gt;
         &lt;dict&gt;
               &lt;key&gt;CFBundleTypeExtensions&lt;/key&gt;
               &lt;array&gt;
                        &lt;string&gt;pjd&lt;/string&gt;
                 &lt;/array&gt;
                 &lt;key&gt;CFBundleTypeIconFile&lt;/key&gt;
                 &lt;string&gt;dialogblocks-doc.icns&lt;/string&gt;
                 &lt;key&gt;CFBundleTypeName&lt;/key&gt;
                 &lt;string&gt;pjdfile&lt;/string&gt;
                 &lt;key&gt;CFBundleTypeRole&lt;/key&gt;
                 &lt;string&gt;Editor&lt;/string&gt;
           &lt;/dict&gt;
    &lt;/array&gt;
    &lt;key&gt;CFBundleIconFile&lt;/key&gt;
    &lt;string&gt;dialogblocks-app.icns&lt;/string&gt;
...
</pre>
<p>Иконки для вашего приложения и  документов вашего приложения описываются в <code>CFBundleIconFile</code> и <code>CFBundleTypeIconFile</code> свойствах. ICNS файлы Вы можете создать с помощью редактора иконок, которые поставляет Apple. Если Вы преимущественно работаете в другой операционной системе, Вам нужно создать несколько иконок с разрешением 16x16, 32x32, 48x48, и 128x128, сохранить их в PNG формате, скопировать их на Mac, потом скопировать их и вставить в нужном месте в редактор иконок. Удостоверьтесь, что каждый PNG файл содержит маску, которую редактор будет использовать при создании иконки.</p>
<p>В Linux’e, у GNOME и KDE свои способы для назначения иконок приложениям, эти способы коротко будут описаны в Главе 20.</p>
<h3>Программирование с wxCursor</h3>
<p>Курсор используется для указания позиция указателя мыши. Вы можете изменить курсор для отдельного окна, если хотите акцентировать пользователя на конкретной функции мыши в данном окне. Так же как и иконки, курсор это небольшое изображение с поддержкой прозрачности. Создать его можно с помощью как общих, так и с помощью специфических для данной платформы конструкторов. Некоторые из этих конструкторов берут актуальную позицию указателя как самую левую верхнюю точку изображения курсора, и именно эта точка по-умолчанию является "острием" вашего курсора.</p>
<h3>Таблица 10-4 функции класса wxCursor.</h3>
<ul>
<li><code>wxCursor</code> - Курсор может быть создан из <code>wxImage</code>, битовых данных (<code>char[]</code>), используя стандартный идентификатор курсора, или из файла с указанием формата файла.</li>
<li><code>Ok</code> - Возвращает <code>true</code>, если объект содержит данные курсора.</li>
</ul>
<h3>Создание wxCursor</h3>
<p>Самый простой способ задать курсор – это передать стандартный идентификатор конструктору объекта, как показано в примере ниже.</p>
<pre class="brush: cpp;">
// Создание курсора, используя стандартный идентификатор
wxCursor cursor(wxCURSOR_WAIT);
</pre>
<p>Таблица 10-5 список доступных идентификаторов и их внешний вид (на разных платформах могут быть незначительные отличия).</p>
<p><b>Table 10-5. Идентификаторы Стандартных Курсоров</b></p>
<ul>
<li><code>wxCURSOR_ARROW</code> - Стандартный курсор стрелка.</li>
<li><code>wxCURSOR_RIGHT_ARROW</code> - Стандартный курсор, указывающий вправо.</li>
<li><code>wxCURSOR_BLANK</code> - Прозрачный (пустой) курсор.</li>
<li><code>wxCURSOR_BULLSEYE</code> - Курсор мишень.</li>
<li><code>wxCURSOR_CROSS</code> - Курсор крест.</li>
<li><code>wxCURSOR_HAND</code> - Курсор в форме руки.</li>
<li><code>wxCURSOR_IBEAM</code> - I-образный курсор (вертикальная линия).</li>
<li><code>wxCURSOR_LEFT_BUTTON</code> - Изображение мыши с нажатой левой кнопкой (только в GTK+).</li>
<li><code>wxCURSOR_MAGNIFIER</code> - Курсор увеличения.</li>
<li><code>wxCURSOR_MIDDLE_BUTTON</code> - Изображение мыши с нажатой средней кнопкой (только в GTK+).</li>
<li><code>wxCURSOR_NO_ENTRY</code> - Курсор в форме знака "входа нет".</li>
<li><code>wxCURSOR_PAINT_BRUSH</code> - Курсор в форме кисти для рисования.</li>
<li><code>wxCURSOR_PENCIL</code> - Курсор карандаш.</li>
<li><code>wxCURSOR_POINT_LEFT</code> - Курсор указывающий налево.</li>
<li><code>wxCURSOR_POINT_RIGHT</code> - Курсор указывающий направо.</li>
<li><code>wxCURSOR_QUESTION_ARROW</code> - Стрелка и знак вопроса.</li>
<li><code>wxCURSOR_RIGHT_BUTTON</code> - Изображение мыши с нажатой правой кнопкой (только в GTK+).</li>
<li><code>wxCURSOR_SIZENESW</code> - Курсор изменения размера  в направлении СВ-ЮЗ.</li>
<li><code>wxCURSOR_SIZENS</code> - Курсор изменения размера  в направлении  С-Ю.</li>
<li><code>wxCURSOR_SIZENWSE</code> - Курсор изменения размера  в направлении СЗ-ЮВ.</li>
<li><code>wxCURSOR_SIZEWE</code> - Курсор изменения размера  в направлении З-В.</li>
<li><code>wxCURSOR_SIZING</code> - Курсор изменения размера (часто перемещения)</li>
<li><code>wxCURSOR_SPRAYCAN</code> - Курсор пульвелизатора.</li>
<li><code>wxCURSOR_WAIT</code> - Курсор ожидания.</li>
<li><code>wxCURSOR_WATCH</code> - Курсор в форме часов.</li>
<li><code>wxCURSOR_ARROWWAIT</code> - Курсор со стрелкой и песочными часами.</li>
</ul>
<p>Так же можно использовать предопределенные курсоры <code>wxSTANDARD_CURSOR</code>, <code>wxHOURGLASS_CURSOR</code>, и <code>wxCROSS_CURSOR</code>.<br />
<code>wxCursor</code> можно загрузить из Windows ресурсов в Windows или из Mac OS X ресурса курсоров в Mac OS X:</p>
<pre class="brush: cpp;">
// Курсор из Windows ресурса
wxCursor cursor(wxT(&quot;cursor_resource&quot;), wxBITMAP_TYPE_CUR_RESOURCE,
                 hotSpotX, hotSpotY);

// Курсор из Mac OS ресурса курсоров
wxCursor cursor(wxT(&quot;cursor_resource&quot;), wxBITMAP_TYPE_MACCUR_RESOURCE);
</pre>
<p>Вы можете создать свой курсор, используя <code>wxImage</code>. Актуальную позицию указателя можно задать функцией <code>wxImage::SetOptionInt</code>, так как "острие" курсора может не совпадать с левой верхней точкой изображения. Например, у курсора в виде прицела актуальная позиция находится ровно по центру изображения. Вот пример кода, который загружает PNG изображение и использует его в качестве курсора:</p>
<pre class="brush: cpp;">
// Создаем курсор из wxImage
wxImage image(wxT(&quot;cursor.png&quot;), wxBITMAP_TYPE_PNG);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X, 5);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 5);
wxCursor cursor(image);
</pre>
<h3>Использование wxCursor</h3>
<p>Каждое окно может иметь свой курсор, который будет использоваться для указателя, когда мышь будет в пределах данного окна. Если для окна не указан курсор, будет использоваться курсор, заданный родительскому окну; если же у окна нет родителя с заданным курсором, будет использован стандартный курсор.<br />
Курсор для окна задается вот так:</p>
<pre class="brush: cpp;">
window-&gt;SetCursor(wxCursor(wxCURSOR_WAIT));
</pre>
<h3>Использование wxSetCursorEvent</h3>
<p>В Windows и Mac OS X есть подводные камни, которых Вы должны остерегаться, в частности, когда Вы рисуете нестандартное окно. Скажем, Вы рисуете окно с разделителем так, что на самом деле видима очень маленькая часть самого окна; например так рисуются окна с плавающим разделителем, так называемым "переплетом". Далее Вы устанавливаете курсор для переплета (скажем, <code>wxCURSOR_WE</code>) таким образом, пользователь видит, что границу-разделитель можно тянуть. И если для окон-потомков не установлен собственный курсор, то будет применяться курсор, установленный нашему основному окну, в нашем случае курсор, предназначенный только переплету.<br />
Для того, что бы указать, что нужно использовать заданный курсор только для разделителя, а в остальных случаях рисовать стандартный, Вы должны определить обработчик событий с помощью <code>wxSetCursorEvent</code>. Это событие вызывается в Windows и Mac OS X, когда должен изменятся курсор (обычно, когда указатель мыши двигается над окном). Ваш обработчик события должен вызывать <code>wxSetCursorEvent::SetCursor</code>, если Вы хотите изменять курсор в частности для данного окна:</p>
<pre class="brush: cpp;">
BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
    EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor)
END_EVENT_TABLE()

// Указываем, что курсор должен изменятся только для переплета
void wxSplitterWindow::OnSetCursor(wxSetCursorEvent&amp;amp; event)
{
    // Если мы этого не сделаем, курсор изменения размера будет использоваться
    // и в окнах-потомках. Здесь мы указываем, что наш курсор
    // не должен использоваться для дочерних окон.

    if ( SashHitTest(event.GetX(), event.GetY(), 0) )
    {
        // Вызываем обработчик по-умолчанию
        event.Skip();
    }
    //else: Ничего не делать, в частности не вызывать Skip()
}
</pre>
<p>В этом примере, если курсор мыши двигается над переплетом, <code>SashHitTest</code> возвращает <code>true</code> и вызывается <code>Skip</code>, который прерывает обработку события. Это равнозначно тому, что событие не обрабатывалось вообще, и wxWidgets отображает курсор (<code>wxCURSOR_WE</code>) как он задан для окна. Если <code>SashHitTest</code> возвращает <code>false</code>, наш указатель двигается в пределах дочернего окна, значит мы не заменяем стандартный курсор. Если позволить завершится обработчику (не вызывая <code>Skip</code>), не задавая курсор окну, это укажет wxWidgets обрабатывать наше окно-разделитель, как не имеющее заданного курсора. В итоге дочернее окно не унаследует родительский курсор, даже если дочернее окно не имеет собственного курсора (например, если дочернее окно <code>wxTextCtrl</code>, реализация которого имеет свой курсор, но wxWidgets не знает этого).</p>
<p><a href="http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-2/">Читать вторую часть главы</a></p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/perevod-knigi-juliana-smarta-glava-x-rabota-s-izobrazheniyami-chast-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How to Draw Gradient Buttons (wxWidgets Way)</title>
		<link>http://wxwidgets.info/howto_draw_gradient_buttons/</link>
		<comments>http://wxwidgets.info/howto_draw_gradient_buttons/#comments</comments>
		<pubDate>Sun, 03 Aug 2008 14:16:23 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Components]]></category>
		<category><![CDATA[Controls]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[wxButton]]></category>
		<category><![CDATA[wxWinCE]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://wxwidgets.info//?p=59</guid>
		<description><![CDATA[Several days ago I found How to draw gradient buttons post at Native Mobile blog. Looks nice but I think that using GradienFill() is not very convenient because you need to fill all these TRIVERTEX structures. wxWidgets provides more convenient way of drawing gradients by using wxDC::GradientFillLinear(). Here is how it can be done in [...]]]></description>
			<content:encoded><![CDATA[<p>Several days ago I found <a href="http://nativemobile.blogspot.com/2008/07/how-to-draw-gradient-buttons.html">How to draw gradient buttons</a> post at <a href="http://nativemobile.blogspot.com">Native Mobile</a> blog. Looks nice but I think that using <code>GradienFill()</code> is not very convenient because you need to fill all these <code>TRIVERTEX</code> structures. wxWidgets provides more convenient way of drawing gradients by using <code>wxDC::GradientFillLinear()</code>. Here is how it can be done in wxWidgets:<br />
<span id="more-59"></span></p>
<pre class="brush: cpp;">
wxBufferedPaintDC dc(this);

wxRect clientRect = GetClientRect();
wxRect gradientRect = clientRect;
gradientRect.SetHeight(gradientRect.GetHeight()/2);
dc.GradientFillLinear(gradientRect,
wxColour(132,125,132), wxColour(74,69,74), wxSOUTH);
gradientRect.Offset(0, gradientRect.GetHeight());
dc.GradientFillLinear(gradientRect,
wxColour(0,0,0), wxColour(57,56,57), wxSOUTH);

dc.SetPen(wxPen(GetBackgroundColour()));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
dc.DrawLabel(m_Label, clientRect,
wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
</pre>
<p>After some experiments I created a simple owner-drawn button control which utilizes this way of drawing:<br />
<strong>wxGradientButton.h</strong></p>
<pre class="brush: cpp;">
/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.h
// Purpose:
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by:
// Created:     01/08/2008 20:25:42
// RCS-ID:
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:
/////////////////////////////////////////////////////////////////////////////

#ifndef _WXGRADIENTBUTTON_H_
#define _WXGRADIENTBUTTON_H_

/*!
* Includes
*/

////@begin includes
////@end includes

/*!
* Forward declarations
*/

////@begin forward declarations
class wxGradientButton;
////@end forward declarations

/*!
* Control identifiers
*/

////@begin control identifiers
#define ID_WXGRADIENTBUTTON 10003
#define SYMBOL_WXGRADIENTBUTTON_STYLE wxSIMPLE_BORDER|wxFULL_REPAINT_ON_RESIZE
#define SYMBOL_WXGRADIENTBUTTON_IDNAME ID_WXGRADIENTBUTTON
#define SYMBOL_WXGRADIENTBUTTON_SIZE wxSize(100, 100)
#define SYMBOL_WXGRADIENTBUTTON_POSITION wxDefaultPosition
////@end control identifiers

/*!
* wxGradientButton class declaration
*/

class wxGradientButton: public wxWindow
{
DECLARE_DYNAMIC_CLASS( wxGradientButton )
DECLARE_EVENT_TABLE()

wxSize DoGetBestSize() const;
public:
/// Constructors
wxGradientButton();
wxGradientButton(wxWindow* parent,
wxWindowID id = ID_WXGRADIENTBUTTON,
const wxString &amp; label = wxEmptyString,
const wxPoint&amp; pos = wxDefaultPosition,
const wxSize&amp; size = wxSize(100, 100),
long style = wxSIMPLE_BORDER);

/// Creation
bool Create(wxWindow* parent,
wxWindowID id = ID_WXGRADIENTBUTTON,
const wxString &amp; label = wxEmptyString,
const wxPoint&amp; pos = wxDefaultPosition,
const wxSize&amp; size = wxSize(100, 100),
long style = wxSIMPLE_BORDER);

/// Destructor
~wxGradientButton();

/// Initialises member variables
void Init();

/// Creates the controls and sizers
void CreateControls();

////@begin wxGradientButton event handler declarations

/// wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
void OnSize( wxSizeEvent&amp; event );

/// wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
void OnPaint( wxPaintEvent&amp; event );

/// wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
void OnEraseBackground( wxEraseEvent&amp; event );

/// wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
void OnLeftDown( wxMouseEvent&amp; event );

/// wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
void OnLeftUp( wxMouseEvent&amp; event );

////@end wxGradientButton event handler declarations

////@begin wxGradientButton member function declarations

wxString GetLabel() const { return m_Label ; }
void SetLabel(wxString value) { m_Label = value ; }

wxColour GetGradientTopStartColour() const { return m_GradientTopStartColour ; }
void SetGradientTopStartColour(wxColour value) { m_GradientTopStartColour = value ; }

wxColour GetGradientTopEndColour() const { return m_GradientTopEndColour ; }
void SetGradientTopEndColour(wxColour value) { m_GradientTopEndColour = value ; }

wxColour GetGradientBottomStartColour() const { return m_GradientBottomStartColour ; }
void SetGradientBottomStartColour(wxColour value) { m_GradientBottomStartColour = value ; }

wxColour GetGradientBottomEndColour() const { return m_GradientBottomEndColour ; }
void SetGradientBottomEndColour(wxColour value) { m_GradientBottomEndColour = value ; }

wxColour GetPressedColourTop() const { return m_PressedColourTop ; }
void SetPressedColourTop(wxColour value) { m_PressedColourTop = value ; }

wxColour GetPressedColourBottom() const { return m_PressedColourBottom ; }
void SetPressedColourBottom(wxColour value) { m_PressedColourBottom = value ; }

/// Retrieves bitmap resources
wxBitmap GetBitmapResource( const wxString&amp; name );

/// Retrieves icon resources
wxIcon GetIconResource( const wxString&amp; name );
////@end wxGradientButton member function declarations

/// Should we show tooltips?
static bool ShowToolTips();

////@begin wxGradientButton member variables
wxString m_Label;
wxColour m_GradientTopStartColour;
wxColour m_GradientTopEndColour;
wxColour m_GradientBottomStartColour;
wxColour m_GradientBottomEndColour;
wxColour m_PressedColourTop;
wxColour m_PressedColourBottom;
////@end wxGradientButton member variables
};

#endif
// _WXGRADIENTBUTTON_H_
</pre>
<p><strong>wxGradientButton.cpp</strong></p>
<pre class="brush: cpp;">
/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.cpp
// Purpose:
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by:
// Created:     01/08/2008 20:25:42
// RCS-ID:
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes &quot;wx/wx.h&quot;.
#include &quot;wx/wxprec.h&quot;

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include &quot;wx/wx.h&quot;
#endif

////@begin includes
////@end includes

#include &quot;wxGradientButton.h&quot;
#include &lt;wx/dcbuffer.h&gt;

////@begin XPM images
////@end XPM images

/*!
* wxGradientButton type definition
*/

IMPLEMENT_DYNAMIC_CLASS( wxGradientButton, wxWindow )

/*!
* wxGradientButton event table definition
*/

BEGIN_EVENT_TABLE( wxGradientButton, wxWindow )

////@begin wxGradientButton event table entries
EVT_SIZE( wxGradientButton::OnSize )
EVT_PAINT( wxGradientButton::OnPaint )
EVT_ERASE_BACKGROUND( wxGradientButton::OnEraseBackground )
EVT_LEFT_DOWN( wxGradientButton::OnLeftDown )
EVT_LEFT_UP( wxGradientButton::OnLeftUp )

////@end wxGradientButton event table entries

END_EVENT_TABLE()

/*!
* wxGradientButton constructors
*/

wxGradientButton::wxGradientButton()
{
Init();
}

wxGradientButton::wxGradientButton(wxWindow* parent,
wxWindowID id, const wxString &amp; label, const wxPoint&amp; pos,
const wxSize&amp; size, long style)
{
Init();
Create(parent, id, label, pos, size, style);
}

/*!
* wxGradientButton creator
*/

bool wxGradientButton::Create(wxWindow* parent,
wxWindowID id, const wxString &amp; label, const wxPoint&amp; pos,
const wxSize&amp; size, long style)
{
////@begin wxGradientButton creation
wxWindow::Create(parent, id, pos, size, style);
CreateControls();
////@end wxGradientButton creation
m_Label = label;
return true;
}

/*!
* wxGradientButton destructor
*/

wxGradientButton::~wxGradientButton()
{
////@begin wxGradientButton destruction
////@end wxGradientButton destruction
}

/*!
* Member initialisation
*/

void wxGradientButton::Init()
{
////@begin wxGradientButton member initialisation
m_GradientTopStartColour = wxColour(132,125,132);
m_GradientTopEndColour = wxColour(74,69,74);
m_GradientBottomStartColour = wxColour(0,0,0);
m_GradientBottomEndColour = wxColour(57,56,57);
m_PressedColourTop = wxColour(57,56,57);
m_PressedColourBottom = wxColour(0,0,0);
////@end wxGradientButton member initialisation
}

/*!
* Control creation for wxGradientButton
*/

void wxGradientButton::CreateControls()
{
////@begin wxGradientButton content construction
this-&gt;SetForegroundColour(wxColour(255, 255, 255));
this-&gt;SetBackgroundColour(wxColour(0, 0, 0));
this-&gt;SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT(&quot;Tahoma&quot;)));
////@end wxGradientButton content construction
}

/*!
* Should we show tooltips?
*/

bool wxGradientButton::ShowToolTips()
{
return true;
}

/*!
* Get bitmap resources
*/

wxBitmap wxGradientButton::GetBitmapResource( const wxString&amp; name )
{
// Bitmap retrieval
////@begin wxGradientButton bitmap retrieval
wxUnusedVar(name);
return wxNullBitmap;
////@end wxGradientButton bitmap retrieval
}

/*!
* Get icon resources
*/

wxIcon wxGradientButton::GetIconResource( const wxString&amp; name )
{
// Icon retrieval
////@begin wxGradientButton icon retrieval
wxUnusedVar(name);
return wxNullIcon;
////@end wxGradientButton icon retrieval
}

wxSize wxGradientButton::DoGetBestSize() const
{
wxSize labelSize = wxDefaultSize;
GetTextExtent(m_Label, &amp;labelSize.x, &amp;labelSize.y);
return wxSize(wxMax(40, labelSize.x + 20), wxMax(20, labelSize.y + 10));
}

/*!
* wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
*/

void wxGradientButton::OnPaint( wxPaintEvent&amp; event )
{
// Before editing this code, remove the block markers.
wxBufferedPaintDC dc(this);

wxRect clientRect = GetClientRect();
wxRect gradientRect = clientRect;
gradientRect.SetHeight(gradientRect.GetHeight()/2 +
((GetCapture() == this) ? 1 : 0));
if(GetCapture() != this)
{
dc.GradientFillLinear(gradientRect,
m_GradientTopStartColour, m_GradientTopEndColour, wxSOUTH);
}
else
{
dc.SetPen(wxPen(m_PressedColourTop));
dc.SetBrush(wxBrush(m_PressedColourTop));
dc.DrawRectangle(gradientRect);
}

gradientRect.Offset(0, gradientRect.GetHeight());

if(GetCapture() != this)
{
dc.GradientFillLinear(gradientRect,
m_GradientBottomStartColour, m_GradientBottomEndColour, wxSOUTH);
}
else
{
dc.SetPen(wxPen(m_PressedColourBottom));
dc.SetBrush(wxBrush(m_PressedColourBottom));
dc.DrawRectangle(gradientRect);
}
dc.SetPen(wxPen(GetBackgroundColour()));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
if(GetCapture() == this)
{
clientRect.Offset(1, 1);
}
dc.DrawLabel(m_Label, clientRect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
}

/*!
* wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
*/

void wxGradientButton::OnLeftDown( wxMouseEvent&amp; event )
{
if(GetCapture() != this)
{
CaptureMouse();
Refresh();
}
}

/*!
* wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
*/

void wxGradientButton::OnLeftUp( wxMouseEvent&amp; event )
{
if(GetCapture() == this)
{
ReleaseMouse();
Refresh();
if(GetClientRect().Contains(event.GetPosition()))
{
wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
GetEventHandler()-&gt;AddPendingEvent(evt);
}
}
}

/*!
* wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
*/

void wxGradientButton::OnEraseBackground( wxEraseEvent&amp; event )
{
}

/*!
* wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
*/

void wxGradientButton::OnSize( wxSizeEvent&amp; event )
{
Refresh();
}
</pre>
<p>After you compile the code, you&#8217;ll get someting like this:</p>
<div id="attachment_61" class="wp-caption alignnone" style="width: 303px"><a href="http://wxwidgets.info//wp-content/uploads/2009/01/howto_draw_gradient_buttons_1.png"><img class="size-full wp-image-61" title="How to draw gradient buttons in C++/wxWidgets - Screenshot for Windows Mobile" src="http://wxwidgets.info//wp-content/uploads/2009/01/howto_draw_gradient_buttons_1.png" alt="wxGradientButton under Windows Mobile" width="293" height="455" /></a><p class="wp-caption-text">wxGradientButton under Windows Mobile</p></div>
<p>You can download the source code of sample application which uses wxGradientButton control <a title="Download wxGradienButton source code" href="http://wxwidgets.info//wp-content/uploads/2009/01/wxgradientbutton.7z">here</a>. Sample application compiles for Win32 and Windows Mobile 6 platforms.</p>
<p>Read discussion of wxGradientButton at <a href="http://wxforum.shadonet.com/viewtopic.php?p=88479">wxForum</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/howto_draw_gradient_buttons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Книга &#8220;Programming with wxDev-CPP&#8221;</title>
		<link>http://wxwidgets.info/kniga-programming-with-wxdev-cpp/</link>
		<comments>http://wxwidgets.info/kniga-programming-with-wxdev-cpp/#comments</comments>
		<pubDate>Thu, 11 Jan 2007 21:32:41 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxDev-CPP]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info//?p=468</guid>
		<description><![CDATA[Книга для начинающих, которая рассказывает об использовании IDE wxDev-CPP для разработки приложений на С++/wxWidgets. Скачать книгу &#8220;Programming with wxDev-CPP&#8221; Домашняя страница книги &#8220;Programming With wxDev-CPP&#8221;]]></description>
			<content:encoded><![CDATA[<p>Книга для начинающих, которая рассказывает об использовании IDE <a title="Скачать wxDev-CPP" href="http://wxdsgn.sourceforge.net/" target="_blank">wxDev-CPP</a> для разработки приложений на С++/wxWidgets.</p>
<ul>
<li><a title="Скачать бесплатную книгу &quot;Programming With wxDev-CPP&quot;" href="http://depositfiles.com/files/6290563" target="_blank">Скачать книгу &#8220;Programming with wxDev-CPP&#8221;</a></li>
<li><a title="Programming with wxDev-CPP" href="http://wxdevcpp-book.sourceforge.net/" target="_blank">Домашняя страница книги &#8220;Programming With wxDev-CPP&#8221;</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/kniga-programming-with-wxdev-cpp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава XIV &#8211; Файлы и потоки</title>
		<link>http://wxwidgets.info/wxwidgets_book_chapter_14_ru/</link>
		<comments>http://wxwidgets.info/wxwidgets_book_chapter_14_ru/#comments</comments>
		<pubDate>Thu, 11 Jan 2007 18:52:53 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info//?p=388</guid>
		<description><![CDATA[Скачать PDF-версию (262 кб) В этой главе рассказывается о классах, которыми располагает библиотека wxWidgets для низкоуровневого доступа к файлам и потокам. Классы потоков wxWidgets не только защищают ваше приложение от особенностей различных стандартных библиотек C++, но также предоставляют множество полезных функций, включая сжатие, запись в zip-архивы и даже потоковые сокеты. Также рассматривается механизм виртуальных файловых [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://depositfiles.com/files/7071299">Скачать PDF-версию (262 кб)</a></p>
<p>В этой главе рассказывается о классах, которыми располагает библиотека wxWidgets для низкоуровневого доступа к файлам и потокам. Классы потоков wxWidgets не только защищают ваше приложение от особенностей различных стандартных библиотек C++, но также предоставляют множество полезных функций, включая сжатие, запись в zip-архивы и даже потоковые сокеты. Также рассматривается механизм виртуальных файловых систем, который позволяет вашему приложению легко получать данные из источника, отличного от обычных дисковых файлов.<br />
<span id="more-388"></span></p>
<h4>Классы и функции для работы с файлами</h4>
<p>wxWidgets содержит множество различных функций и классов для платформо-независимой работы с файлами. Мы рассмотрим только часто используемых представителей таких классов.</p>
<h5>wxFile и wxFFile</h5>
<p><code>wxFile</code> может быть использован для низкоуровневого ввода/вывода. Он содержит все обычные функции для работы с целочисленными файловыми дескрипторами (открытие/закрытие, чтение/запись, позицирование и т.п.), но в отличие от стандартных функций языка C данный класс сообщает об ошибках через wxLog и автоматически закрывает файл в деструкторе. <code>wxFFile</code> предоставляет похожую функциональность, но использует буферизованный ввод/вывод и содержит указатель на дескриптор типа <code>FILE</code>.<br />
Вы можете создать объект класса <code>wxFile</code>, используя конструктор по умолчанию, а далее вызвать метод <code>Create</code> или <code>Open</code>. Вы также можете использовать конструктор, который в качестве параметров принимает имя открываемого файла и режим работы:</p>
<ul>
<li><code>wxFile::read</code> &#8212; для чтения,</li>
<li><code>wxFile::write</code> &#8212; для записи,</li>
<li><code>wxFile::read_write</code> &#8212; для чтения и записи.</li>
</ul>
<p>Вы также можете создать <code>wxFile</code> из существующего файлового дескриптора, который можно передать в конструктор или с помощью метода <code>Attach</code>. <code>wxFile</code> можно принудительно закрыть вызвав метод <code>Close</code>, который также вызывается автоматически при уничтожении объекта.</p>
<p>Для чтения данных из файла существует метод <code>Read</code>, которому передается указатель на буфер <code>void*</code> и число байт для чтения. Функция возвращает число считанных байтов или <code>wxInvalidOffset</code>, в случае ошибки. Используйте метод <code>Write</code>, чтобы записать буфер <code>void*</code> или строку типа <code>wxString</code> в файл. Метод <code>Flush</code> вызывает немедленную запись измененных данных в файл.</p>
<p>Для проверки достижение конца файла используйте метод <code>Eof</code>, который возвращает <code>true</code>, если указатель находится к конце файла (это отличается от поведения функции <code>Eof</code> класса <code>wxFFile</code>, которая возвращает <code>true</code> только после попытки прочитать информацию, расположенную за последним байтом). Размер файла можно определить вызвав <code>Length</code>.</p>
<p><code>Seek</code> и <code>SeekEnd</code> устанавливают текущую позицию в файле, отсчитывая смещение от начала или конца файла соответственно. <code>Tell</code> возвращает текущее смещение от начала файла с типом <code>wxFileOffset</code> (64-битовое целое число в случае поддержки платформой или 32-битовое целое число в противном случае).</p>
<p>Вызвав статическую функцию <code>Access</code> вы можете определить возможно ли открыть файл в выбранном режиме. Другая статическая функция <code>Exists</code> проверяет существование указанного файла.</p>
<p>Следующий фрагмент кода использует <code>wxFile</code>, чтобы открыть файл с данными и прочитать их в массив.</p>
<pre class="brush: cpp;">
#include &quot;wx/file.h&quot;

if (!wxFile::Exists(wxT(&quot;data.dat&quot;)))
    return false;

wxFile file(wxT(&quot;data.dat&quot;));

if ( !file.IsOpened() )
    return false;

// берем размер файла
wxFileOffset nSize = file.Length();
if ( nSize == wxInvalidOffset )
    return false;

// читаем весь файл в память
wxUint* data = new wxUint8[nSize];

if ( fileMsg.Read(data, (size_t) nSize) != nSize )
{
    delete[] data;
    return false;
}

file.Close();
</pre>
<p>Для иллюстрации записи в файл приведем пример функции, которая сохраняет содержимое текстового элемента управления в файл.</p>
<pre class="brush: xml;">
bool WriteTextCtrlContents(wxTextCtrl* textCtrl,
                           const wxString&amp; filename)
{
    wxFile file;
    if (!file.Open(filename, wxFile::write))
        return false

    int nLines = textCtrl-&gt;GetNumberOfLines();
    bool ok = true;

    for ( int nLine = 0; ok &amp;&amp; nLine &lt; nLines; nLine++ )
    {
        ok = file.Write(textCtrl-&gt;GetLineText(nLine) +
                        wxTextFile::GetEOL());
    }

    file.Close();
    return ok;
}
</pre>
<h5>wxTextFile</h5>
<p><code>wxTextFile</code> реализует довольно прямолинейный путь для чтения и записи маленьких текстовых файлов и их построчной обработки.</p>
<p>Используйте метод <code>Open</code>, чтобы прочитать файл в память и разбить его на строки. Метод <code>Write</code> позволяет сохранить информацию в файл. <code>GetLine</code> или прямое обращение по индексу в массиве позволяет получить требуемую строку. Также перебор строк можно осуществить, используя <code>GetFirstLine</code>, <code>GetNextLine</code> и <code>GetPrevLine</code>. Функции <code>AddLine</code> и <code>InsertLine</code> позволяют добавить строку в конец файла, а удалить требуемую строку можно с помощью <code>RemoveLine</code>. Для полной очистки содержимого файла используйте метод <code>Clear</code>.<br />
В следующем примере к каждой строке в файле добавляется заданная строка, после чего файл записывается обратно на диск.</p>
<pre class="brush: cpp;">
#include &quot;wx/textfile.h&quot;

void FilePrepend(const wxString&amp; filename, const wxString&amp; text)
{
    wxTextFile file;
    if (file.Open(filename))
    {
        size_t i;
        for (i = 0; i &lt; file.GetLineCount(); i++)
        {
            file[i] = text + file[i];
        }
        file.Write(filename);
    }
}
</pre>
<h5>wxTempFile</h5>
<p><code>wxTempFile</code> реализует относительно безопасный метод для замены содержимого существующего файла. Класс <code>wxTempFile</code> является потомком от <code>wxFile</code> и использует временные файлы для записи данных. При этом реальная перезапись выбранного файла происходит только после вызова метода <code>Commit</code>. Использование временных файлов для записи пользовательских данных является отличной идеей, так как в этом случае минимизируются последствия возможных ошибок, которые могут произойти во время записи (таких как выключение электричества, ошибки в программе или других катаклизмов). При использовании временных файлов такие неприятности не смогут повредить текущему файлу на диске.</p>
<p>Замечание: Текущая реализация архитектуры документ/вид не использует временные файлы при создании выходного потока и вызове <code>SaveObject</code>, поэтому вы возможно захотите перегрузить метод <code>DoSaveDocument</code> и создать поток <code>wxFileOutputStream</code> из объекта типа <code>wxTempFile</code>. После записи необходимых данных вызовите метод <code>Sync</code> потокового объекта, а далее <code>Commit</code> для временного файла.</p>
<h5>wxDir</h5>
<p><code>wxDir</code> &#8212; это переносимый эквивалент функций open/read/closedir из системы unix, которые поддерживают перечисление файлов в каталоге. <code>wxDir</code> поддерживает перечисление как файлов, так и каталогов. Данный класс предоставляет гибкий механизм для рекурсивного перечисления файлов, а также более простую в использовании функцию <code>GetAllFiles</code>.</p>
<p>После открытия каталога с помощью <code>Open</code> (или передав нужный путь в конструктор) вызовите <code>GetFirst</code>, передав ему в качестве параметра указатель на строку в которую будет записано найденное имя файла. Дополнительно можно передать фильтр для файлов (по умолчанию пустая строка означает отсутствие фильтра) и необязательные флаги. Далее вызывайте <code>GetNext</code> до тех пор пока не переберете все файлы и функция не возвратит <code>false</code>. Фильтр может содержать групповые символы, такие как &#8220;*&#8221; (означает любое число любых символов) и &#8220;?&#8221; (означает один любой символ). Поле с флагами может быть комбинацией одной или нескольких битовых констант <code>wxDIR_FILES</code> (искать файлы), <code>wxDIR_DIRS</code> (искать каталоги), <code>wxDIR_HIDDEN</code> (искать скрытые файлы) и <code>wxDIR_DOTDOT</code> (добавлять к результату псевдокаталоги &#8220;.&#8221; и &#8220;..&#8221;). По умолчанию ищутся все возможные объекты, кроме &#8220;.&#8221; и &#8220;..&#8221;.</p>
<p>Пример:</p>
<pre class="brush: cpp;">
#include &quot;wx/dir.h&quot;

wxDir dir(wxGetCwd());

if ( !dir.IsOpened() )
{
    // Здесь разбираемся с возникшей ошибкой. wxDir уже показал пользователю
    // сообщение, объясняющее точную причину ошибки
    return;
}

puts(&quot;Enumerating object files in current directory:&quot;);

wxString filename;
wxString filespec = wxT(&quot;*.*&quot;);
int flags = wxDIR_FILES|wxDIR_DIRS;
bool cont = dir.GetFirst(&amp;filename, filespec, flags);
while ( cont )
{
    wxLogMessage(wxT(&quot;%s\n&quot;), filename.c_str());

    cont = dir.GetNext(&amp;filename);
}
</pre>
<p>Заметим, что при возникновении проблем при перечислении файлов (например, в случае недоступности каталога) <code>wxDir</code> покажет пользователю сообщение об ошибке. Используйте класс <code>wxLogNull</code>, чтобы временно отключить данное поведение:</p>
<pre class="brush: cpp;">
// Создаем область действия для logNull
{
    wxLogNull logNull;

    wxDir dir(badDir);
    if ( !dir.IsOpened() )
    {
        return;
    }
}
</pre>
<h5>wxFileName</h5>
<p>Класс <code>wxFileName</code> манипулирует именем файла. Он может разбирать и восстанавливать компоненты полного имени файла, а также реализует различные файловые операции, которые доступны в виде статических функций. Далее приведено несколько примеров того, что можно сделать с помощью данного класса. Ознакомьтесь с документацией, чтобы узнать об остальных поддерживаемых операциях.</p>
<pre class="brush: cpp;">
#include &quot;wx/filename.h&quot;

// Создать имя файла из строки
wxFileName fname(wxT(&quot;MyFile.txt&quot;));

// Нормализовать имя, что в том числе означает, что имя
// будет являться полным в системе Windows
fname.Normalize(wxPATH_NORM_LONG|wxPATH_NORM_DOTS|wxPATH_NORM_TILDE|
                wxPATH_NORM_ABSOLUTE);

// Получить полный путь до файла в виде строки
wxString filename = fname.GetFullPath();

// Получить имя файла относительно текущего каталога
fname.MakeRelativeTo(wxFileName::GetCwd());

// Существует ли заданный файл?
bool exists = fname.FileExists();

// Существует ли другой файл?
bool exists2 = wxFileName::FileExists(wxT(&quot;c:\\temp.txt&quot;));

// Возвращаем имя файла
wxString name = fname.GetName();

// Возвращаем путь до файла
wxString path = fname.GetPath();

// Возвращаем короткое имя файла в Windows или
// идентичное ему в других ОС
wxString shortForm = fname.GetShortPath();

// Создаем каталог
bool ok = wxFileName::Mkdir(wxT(&quot;c:\\thing&quot;));
</pre>
<h5>Функции работы с файлами</h5>
<p>Большинство часто используемых функций приведено в таблице~\ref{tab_filefunc} и определены в файле wx/filefn.h. Также ознакомьтесь также с классом <code>wxFileName</code>, особенно с его статическими функциями (например, <code>wxFileName::FileExists</code>), которые можно использовать без создания объекта класса <code>wxFileName</code>.</p>
<p>В wxWidgets существуют аналоги большинства стандартных функций языка C, такие как <code>wxFopen</code>, <code>wxFputc</code> и <code>wxSscanf</code>. Эти функции в данный момент не документированы, но их определение можно посмотреть в файле include/wx/wxchar.h дистрибутива wxWidgets.</p>
<p>Также полезно знать о символе <code>wxFILE_SEP_PATH</code>, который соответствует разделителю пути для текущей платформы (например, обратный слеш для систем Windows и прямой слеш для систем на базе Unix).</p>
<h4>Классы потоков</h4>
<p>Потоки &#8212; это высокоуровневая модель для чтения и записи данных. Вы можете писать свой код не заботясь о том куда осуществлять запись: в файлы, в память или даже в сокеты (за примером использования потоков с сокетами обратитесь к Главе 18 <b>Программирование с использованием wxSocket</b>). Некоторые классы wxWidgets (например, <code>wxImage</code>), поддерживающие чтение/запись файлов, также могут использовать ввод/вывод в поток.</p>
<p><code>wxStreamBase</code> является базовым классом для всех потоков и объявляет функции такие как <code>OnSysRead</code> и <code>OnSysWrite</code>, которые должны быть реализованы в дочерних классах. Его дочерние классы <code>wxInputStream</code> и <code>wxOutputStream</code> образуют фундамент для всех других классов, осуществляющих чтение и запись, например для <code>wxFileInputStream</code> и <code>wxFileOutputStream</code> соответственно. Рассмотрим потоковые классы, предоставляемые библиотекой wxWidgets.</p>
<h5>Файловые потоки</h5>
<p>Классы <code>wxFileInputStream</code> и <code>wxFileOutputStream</code> базируются на <code>wxFile</code> и могут быть инициализированы именем файла, объектом <code>wxFile</code> или целочисленным файловым дескриптором. Далее приводится пример использования <code>wxFileInputStream</code> для чтения данных, перехода в начало файла и взятия текущего положения в файле.</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;

// Конструктор инициализирует буфер потока и открывает файловый
// дескриптор, ассоциированный с именем файла.
// wxFileInputStream закроет файловый дескриптор при вызове деструктора
wxFileInputStream inStream(filename);

// Читаем несколько байтов
int byteCount = 100;
char data[100];

if (inStream.Read((void*) data, byteCount).
             LastError() != wxSTREAM_NOERROR)
{
    // Возникли какие-то проблемы.
    // За полным списком проблем обратитесь к документации по wxStreamBase
}

// Вы также можете получить число байт, которое реально
// было считано из потока
size_t reallyRead = inStream.LastRead();

// Перемещаемся в начало потока. SeekI возвратит позицию
// в потоке, считая от начала
off_t oldPosition = inStream.SeekI(0, wxFromBeginning);

// Получить текущую позицию в файле
off_t position = inStream.TellI();
</pre>
<p>Использование <code>wxFileOutputStream</code> аналогично. Следующий код использует <code>wxFileInputStream</code> и <code>wxFileOutputStream</code> для копирования файла (в целях эффективности файл копируется блоками по 1024 байта). Для большей ясности все проверки на возможные ошибки удалены.</p>
<pre class="brush: cpp;">
// Копируем данные фиксированного размера из входного потока в
// выходной, используя промежуточный буфер для повышения эффективности
void BufferedCopy(wxInputStream&amp; inStream, wxOutputStream&amp; outStream,
                  size_t size)
{
    static unsigned char buf[1024];
    size_t bytesLeft = size;

    while (bytesLeft &gt; 0)
    {
        size_t bytesToRead = wxMin((size_t) sizeof(buf), bytesLeft);

        inStream.Read((void*) buf, bytesToRead);
        outStream.Write((void*) buf, bytesToRead);

        bytesLeft -= bytesToRead;
    }
}

void CopyFile(const wxString&amp; from, const wxString&amp; to)
{
    wxFileInputStream inStream(from);
    wxFileOutputStream outStream(to);

    BufferedCopy(inStream, outStream, inStream.GetSize());
}
</pre>
<p>Классы <code>wxFFileInputStream</code> и <code>wxFFileOutputStream</code> идентичны <code>wxFileInputStream</code> и <code>wxFileOutputStream</code>, за исключением того, что они базируются на классе <code>wxFFile</code> вместо <code>wxFile</code>. Поэтому их можно инициализировать указателем на <code>FILE</code> или объектом <code>wxFFile</code>. Обработка конца файла также отличается: <code>wxFileInputStream</code> возвращает <code>wxSTREAM_EOF</code> после чтения последнего байта, тогда как <code>wxFFileInputStream</code> возвращает <code>wxSTREAM_EOF</code> при попытке считать данные, расположенны за последним байтом.</p>
<h5>Строковые потоки и потоки в памяти</h5>
<p><code>wxMemoryInputStream</code> и <code>wxMemoryOutputStream</code> используют внутренний буфер для организации потока. Конструкторы обоих этих классов берут в качестве параметров буфер <code>char*</code> и его размер. Данные параметры могут быть опущены, чтобы позволить классу выделять память автоматически по мере необходимости. Мы рассмотрим применение данных классов чуть позже.</p>
<p><code>wxStringInputStream</code> берет в качестве параметра строку из которой будет осуществляться чтение. <code>wxStringOutputStream</code> получает необязательный указатель на строку класса <code>wxString</code>, в которую будет осуществляться запись. Если данный параметр опущен, то класс самостоятельно создаст строку, доступ к которой можно получить через метод <code>GetString</code>.</p>
<h5>Чтение и запись типов данных</h5>
<p>До этого времени мы рассматривали классы, которые работают с <b>сырыми</b> байтами, которые необходимо преобразовать в что-нибудь полезное для приложения. Чтобы это сделать вы можете использовать четыре класса, которые реализуют чтение/запись на более высоком уровне: <code>wxTextInputStream</code>, <code>wxTextOutputStream</code>, <code>wxDataInputStream</code> и <code>wxDataOutputStream</code>. При создании данных объектов требуется указать ссылку на существующий поток, а классы предоставят методы для вставки и извлечения данных для различных типов языка C++.</p>
<p><code>wxTextInputStream</code> читает данные из обычного текстового файла. Если вы обрабатываете файл с помощью <code>wxTextInputStream</code>, то вы должны делать проверку на достижение конца файла перед чтением следующего элемента. Однако вы должны быть готовы получить пустой элемент (такой как пустую строку или нулевое число) в конце файла. Это происходит из-за того, что в большинстве файлов в конце находится несколько пробельных символов (обычно это символ перехода на новую строку). Далее вы видите пример использования <code>wxTextInputStream</code> вместе с <code>wxFileInputStream</code>:</p>
<pre class="brush: cpp;">
wxFileInputStream input( wxT(&quot;mytext.txt&quot;) );
wxTextInputStream text( input );
wxUint8 i1;
float f2;
wxString line;
text &gt;&gt; i1;       // читаем 8-битовое целое число
text &gt;&gt; i1 &gt;&gt; f2; // читаем 8-битовое целое, а далее вещественное число
text &gt;&gt; line;     // читаем текстовую строку
</pre>
<p><code>wxTextOutputStream</code> записывает текстовые данные в выходной поток. При записи используется родной для системы признак окончания строки. Следующий пример записывает данные в стандартный поток для вывода ошибок.</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;
#include &quot;wx/txtstrm.h&quot;

wxFFileOutputStream output( stderr );
wxTextOutputStream cout( output );

cout &lt;&lt; wxT(&quot;This is a text line&quot;) &lt;&lt; endl;
cout &lt;&lt; 1234;
cout &lt;&lt; 1.23456;
</pre>
<p><code>wxDataInputStream</code> и <code>wxDataOutputStream</code> похожи, но работают с бинарными данными. Данные записываются в переносимом формате, поэтому файл будет иметь одинаковую структуру, назависимо от платформы. Далее приведен пример чтения из файла с данными:</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;
#include &quot;wx/datstrm.h&quot;

wxFileInputStream input( wxT(&quot;mytext.dat&quot;) );
wxDataInputStream store( input );
wxUint8 i1;
float f2;
wxString line;

store &gt;&gt; i1;       // читаем 8-битовое целое
store &gt;&gt; i1 &gt;&gt; f2; // читаем 8-битовое целое, а далее вещественное число
store &gt;&gt; line;     // читаем текстовую строку
</pre>
<p>И записи данных в файл:</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;
#include &quot;wx/datstrm.h&quot;

wxFileOutputStream output(wxT(&quot;mytext.dat&quot;) );
wxDataOutputStream store( output );

store &lt;&lt; 2 &lt;&lt; 8 &lt;&lt; 1.2;
store &lt;&lt; wxT(&quot;This is a text line&quot;);
</pre>
<h5>Потоки на базе сокетов</h5>
<p>Классы <code>wxSocketOutputStream</code> и <code>wxSocketInputStream</code> инициализируются существующим объектом <code>wxSocket</code>. Обратитесь к Главе 18 за дополнительными деталями.</p>
<h5>Потоки фильтрации</h5>
<p><code>wxFilterInputStream</code> и <code>wxFilterOutputStream</code> являются базовыми для потоков, которые могут быть помещены над остальными потоками. Примером фильтрующего потока является поток <code>wxZlibInputStream</code>. Если вы передаете ему входной поток, созданный из сжатого zlib или glib файла, то вы можете читать данные из потока <code>wxZlibInputStream</code> без необходимости заботится об их декомпрессии. Аналогично, вы можете создать <code>wxZlibOutputStream</code> и связать с ним выходной поток, такой как <code>wxFileOutputStream</code>. Запись данных в поток <code>wxZlibOutputStream</code> приведет к тому, что они будут сжаты и посланы в <code>wxFileOutputStream</code>.</p>
<p>Следующий пример сжимает строку с данными (buf) в поток в памяти, а далее копирует полученные данные в постоянное хранилище (data).</p>
<p>Следующий пример сжимает строку с данными (buf) в поток в памяти, а далее копирует полученные данные в постоянное хранилище (data).</p>
<pre class="brush: cpp;">
#include &quot;wx/mstream.h&quot;
#include &quot;wx/zstream.h&quot;

const char* buf =
    &quot;01234567890123456789012345678901234567890123456789&quot;;

// Создаем выходной zlib-поток, связанный с потоком в памяти
wxMemoryOutputStream memStreamOut;
wxZlibOutputStream zStreamOut(memStreamOut);

// Записываем содержимое 'buf' в память через zlib-поток
zStreamOut.Write(buf, strlen(buf));

// Получаем размер полуившегося буфера
int sz = memStreamOut.GetSize();

// Создаем хранилище достаточное для хранения сжатых данных и
// копируем туда данные из памяти
unsigned char* data = new unsigned char[sz];
memStreamOut.CopyTo(data, sz);
</pre>
<h5>Потоки с сжатием</h5>
<p><code>wxZipInputStream</code> является достаточно сложным классом, позволяющим работать с архивами, а не только с линейным потоком данных. Обычно работу с архивами производят с помощью группы классов, включающих в себя <code>wxArchiveClassFactory</code> и <code>wxArchiveEntry</code>, но существует возможность читать и писать zip-файлы без прямого их использования. Для использования <code>wxZipInputStream</code> вы можете создать поток из <code>wxInputStream</code> (который самостоятельно откроет архив) или указав имя архива и имя файла внутри архива. Оба метода проиллюстрированы в следующем примере, в котором строки читаются из одного или нескольких файлов внутри архива (первый пример) или из одного явно определенного файла (второй пример).</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;
#include &quot;wx/zipstrm.h&quot;
#include &quot;wx/txtstrm.h&quot;

// Метод 1: создание zip-потока для чтения в два шага

wxZipEntry* entry;

wxFFileInputStream in(wxT(&quot;test.zip&quot;));
wxZipInputStream zip(in);
wxTextInputStream txt(zip);
wxString data;

while (entry = zip.GetNextEntry())
{
    wxString name = entry-&gt;GetName();    // доступ к метаданным
    txt &gt;&gt; data;                         // доступ к данным
    delete entry;
}

// Метод 2: определяем требуемый файл в конструкторе

wxZipInputStream in(wxT(&quot;test.zip&quot;), wxT(&quot;text.txt&quot;));
wxTextInputStream txt(zip);

wxString data;
txt &gt;&gt; data;                             // доступ к данным
</pre>
<p>Класс <code>wxZipOutputStream</code> служит для записи в zip-файлы. Методы <code>PutNextEntry</code> или <code>PutNextDirEntry</code> используются для создания новых файлов внутри архива в которые позже может быть осуществлена запись. Например:</p>
<pre class="brush: cpp;">
#include &quot;wx/wfstream.h&quot;
#include &quot;wx/zipstrm.h&quot;
#include &quot;wx/txtstrm.h&quot;

wxFFileOutputStream out(wxT(&quot;test.zip&quot;));
wxZipOutputStream zip(out);
wxTextOutputStream txt(zip);

zip.PutNextEntry(wxT(&quot;entry1.txt&quot;));
txt &lt;&lt; wxT(&quot;Some text for entry1\n&quot;);

zip.PutNextEntry(wxT(&quot;entry2.txt&quot;));
txt &lt;&lt; wxT(&quot;Some text for entry2\n&quot;);
</pre>
<h5>Виртуальные файловые системы</h5>
<p>В wxWidgets реализован механизм виртуальных файловых систем, который позволяет читать данные из различных источников также как из обычных файлов. С помощью данного механизма можно читать из zip-архивов, из памяти и по протоколам HTTP и FTP. Хотя он не может быть использован для записи редактируемых документов (так как это инструмент для доступа только для чтения), но его можно, к примеру, использовать для доступа к ресурсам в zip-архиве. Класс <code>wxHtmlWindow</code> (механизм помощи wxWidgets на базе HTML) и ресурсы XRC умеют работать с виртуальными файловыми системами. Виртуальные файловые системы более удобны для работы с архивами, чем рассмотренные ранее классы, но последние позволяют не только читать, но и писать в архивы. Хотя оба механизма и используют потоки, но они никак не связаны друг с другом.</p>
<p>В библиотеке реализованы различные виртуальные файловые системы с помощью классов-наследников от <code>wxFileSystemHandler</code>. Экземпляры этих объектов должны быть добавлены через <code>wxFileSystem::AddHandler</code> (чаще всего это делают в функции инициализации приложения <code>OnInit</code>) перед использованием этих файловых систем. Обычно все взаимодействие с файловой системой осуществляется через <code>wxFileSystem</code>, но иногда обработчики предоставляют функции, которые могут использоваться приложением непосредственно, как например функции <code>AddFile</code> и <code>RemoveFile</code> класса <code>wxMemoryFSHandler</code>.</p>
<p>Перед тем как детально изучить взаимодействие приложения с API виртуальной файловой системой рассмотрим возможность использования ее косвенным образом через другие подсистемы библиотеки wxWidgets. Вот пример URL, который может быть использован в HTML-файле, отображаемом <code>wxHtmlWindow</code>:</p>
<pre class="brush: xml;">
&lt;img src=&quot;file:myapp.bin#zip:images/logo.png&quot;&gt;
</pre>
<p>Часть до знака решетка (#) &#8212; это имя архива, а часть после решетки &#8212; это имя протокола файловой системы и местоположение файла внутри архива.</p>
<p>Похожим образом мы можем определить положение виртуального файла внутри XRC-файла:</p>
<pre class="brush: xml;">
&lt;object class=&quot;wxBitmapButton&quot;&gt;
    &lt;bitmap&gt;file:myapp.bin#zip:images/fuzzy.gif&lt;/bitmap&gt;
&lt;/object&gt;
</pre>
<p>В данном примере код, использующий виртуальные файловые системы, скрыт в реализации <code>wxHtmlWindow</code> и XRC. Чтобы напрямую использовать виртуальные файловые системы вы можете использовать классы <code>wxFileSystem</code> и <code>wxFSFile</code>. В следующем коде <code>wxBitmap</code> формируется из изображения, находящегося в zip-архиве. При инициализации приложения с помощью <code>wxFileSystem</code> регистрируется <code>wxZipFSHandler</code>. Приложение использует экземпляр класса <code>wxFileSystem</code> (который можно создать временно или использовать на протяжении всей жизни программы), чтобы открыть файл logo.png из архива myapp.bin. Возвращаемый объект класса <code>wxFSFile</code> опрашивается на предмет ассоциированного с ним потока, который в дальнейшем используется для чтения изображения (<code>wxImage</code> умеет инициализироваться из потока). Далее изображение преобразовывается в <code>wxBitmap</code>, а объекты <code>wxFSFile</code> и <code>wxFileSystem</code> удаляются.</p>
<pre class="brush: cpp;">
#include &quot;wx/fs_zip.h&quot;
#include &quot;wx/filesys.h&quot;
#include &quot;wx/wfstream.h&quot;

// Это нужно сделать один раз при инициализации приложения
wxFileSystem::AddHandler(new wxZipFSHandler);

wxFileSystem* fileSystem = new wxFileSystem;

wxString archive = wxT(&quot;file:///c:/myapp/myapp.bin&quot;);
wxString filename = wxT(&quot;images/logo.png&quot;);

wxFSFile* file = fileSystem-&gt;OpenFile(
              archive + wxString(wxT(&quot;#zip:&quot;)) + filename);
if (file)
{
    wxInputStream* stream = file-&gt;GetStream();

    wxImage image(* stream, bitmapType);
    wxBitmap bitmap = wxBitmap(image);

    delete file;
}
delete fileSystem;
</pre>
<p>Заметим, что в метод <code>wxFileSystem::OpenFile</code> нужно передавать URL, а не обычное имя файла. Когда вы определяете абсолютное положение файла в правой части URL необходимо использовать форму file:/<имя_хоста>//<файл>. Если имя хоста необходимо опустить, то нужно поставить три слеша. Вы можете преобразовать имя файла в URL используя метод <code>wxFileSystem::FileNameToURL</code> и сделать обратное преобразование с помощью <code>wxFileSystem::URLToFileName</code>.</p>
<p>Продемонстрируем использование zip-архива на примере функции <code>LoadTextResource</code>, которая загружает текстовый файл в кодировке ASCII (такой как HTML файл) в переменную text из заданного архива archive и файла filename внутри его.</p>
<pre class="brush: cpp;">
// Загружаем текстовый ресурс из архива
bool LoadTextResource(wxString&amp; text, const wxString&amp; archive,
                      const wxString&amp; filename)
{
    wxString archiveURL(wxFileSystem::FileNameToURL(archive));
    wxFileSystem* fileSystem = new wxFileSystem;

    wxFSFile* file = fileSystem-&gt;OpenFile(
                 archiveURL + wxString(wxT(&quot;#zip:&quot;)) + filename);
    if (file)
    {
        wxInputStream* stream = file-&gt;GetStream();
        size_t sz = stream-&gt;GetSize();
        char* buf = new char[sz + 1];
        stream-&gt;Read((void*) buf, sz);
        buf[sz] = 0;

        text = wxString::FromAscii(buf);

        delete[] buf;

        delete file;
        delete fileSystem;
        return true;
    }
    else
        return false;
}
</pre>
<p>Класс <code>wxMemoryFSHandler</code> позволяет хранить данные в памяти приложения и обращаться к ним как к файлам. Очевидно, что таким образом не стоит хранить в памяти огромные объемы данных, но иногда полезно иметь такую возможность, вместо того, чтобы работать с файлами непосредственно на диске. Например, во время предпросмотра XRC-диалогов DialogBlocks добавляет ссылку на рисунок в памяти, если пользовательский рисунок не доступен. Эти рисунки не существуют на диске, однако на них все равно существует ссылка в XRC, как если бы это были обычные файлы:</p>
<pre class="brush: xml;">
&lt;object class=&quot;wxBitmapButton&quot;&gt;
    &lt;bitmap&gt;memory:default.png&lt;/bitmap&gt;
&lt;/object&gt;
</pre>
<p><code>wxMemoryFSHandler</code> имеет перегруженную функцию <code>AddFile</code>, которая получает в качестве аргумента имя файла и ссылку на <code>wxImage</code>, <code>wxBitmap</code>, <code>wxString</code. или <code>void*</code>. Когда эти данные больше не нужны, вы можете удалить их с помощью <code>RemoveFile</code>. Например:</p>
<pre class="brush: cpp;">
#include &quot;wx/fs_mem.h&quot;
#include &quot;wx/filesys.h&quot;
#include &quot;wx/wfstream.h&quot;
#include &quot;csquery.xpm&quot;

wxFileSystem::AddHandler(new wxMemoryFSHandler);

wxBitmap bitmap(csquery_xpm);
wxMemoryFSHandler::AddFile(wxT(&quot;csquery.xpm&quot;), bitmap,
                           wxBITMAP_TYPE_XPM);
...
wxMemoryFSHandler::RemoveFile(wxT(&quot;csquery.xpm&quot;));
</pre>
<p>Третий (и последний) обработчик для виртуальных файловых систем, поддерживаемых wxWidgets, называется <code>wxInternetFSHandler</code>, который используется для работы с протоколами FTP и HTTP.</p>
<h4>Итоги</h4>
<p>В этой главе дан обзор классов wxWidgets, которые позволяют вашему приложению переносимо работать с файлами и потоками. Мы также дали небольшой обзор механизма виртуальных файловых систем, который позволяет легко получать данные из сжатых архивов, из данных в памяти и из файлов в сети Интернет.</p>
<p>Далее мы рассмотрим темы, которые напрямую не относятся к тому, что видят на экране пользователи, но несмотря на это очень важные: про управление памятью, отладку и обработку ошибок.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/wxwidgets_book_chapter_14_ru/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Перевод книги Julian’а Smart’а &#8211; Глава XIII &#8211; Структуры данных (Часть 2)</title>
		<link>http://wxwidgets.info/wxwidgets_book_chapter_13_ru_part2/</link>
		<comments>http://wxwidgets.info/wxwidgets_book_chapter_13_ru_part2/#comments</comments>
		<pubDate>Thu, 11 Jan 2007 18:42:35 +0000</pubDate>
		<dc:creator>T-Rex</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[wxWidgets]]></category>
		<category><![CDATA[Библиотека]]></category>
		<category><![CDATA[Книги]]></category>

		<guid isPermaLink="false">http://wxwidgets.info//?p=381</guid>
		<description><![CDATA[Читать первую честь этой главы. Хранение и обработка дат и времени wxWidgets предоставляет достаточно комплексный класс wxDateTime для хранения даты и времени с множеством доступных операций, таких как форматирование, часовые пояса, различные арифметические операции и {т.д.} Статические функции дают информацию о текущей дате и времени, а также методы получения информации о високосном годе. Советуем использовать [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wxwidgets.info/wxwidgets_book_chapter_13_ru" title="Перевод книги Julian’а Smart’а - Глава XIII - Структуры данных (Часть 1)">Читать первую честь этой главы.</a></p>
<h4>Хранение и обработка дат и времени</h4>
<p>wxWidgets предоставляет достаточно комплексный класс wxDateTime для хранения даты и времени с множеством доступных операций, таких как форматирование, часовые пояса, различные арифметические операции и {т.д.} Статические функции дают информацию о текущей дате и времени, а также методы получения информации о високосном годе. Советуем использовать этот класс, даже если вам необходимо просто хранить информацию о времени и дате. Вспомогательные классы wxTimeSpan и wxDateSpan дают возможность легко изменять существующие объекты wxDateTime.<br />
<span id="more-381"></span></p>
<h4>wxDateTime</h4>
<p>Класс wxDateTime содержит слишком много методов, чтобы все их рассматривать здесь. Полную документацию по API вы можете найти в документации wxWidgets. В этом разделе мы дадим описание только самым часто используемым методами и операциям.</p>
<p>Хотя при работе класс времени предполагает, что время считается по гринвичу (Greenwich Mean Time &#8212; GMT), вам не надо об этом заботится, так как обычно вы будете работать в одном часовом поясе (локальном времени). Таким образом, все конструкторы и модификаторы wxDateTime, составляющие дату или время из компонентов (например из часов, минут и секунд) предполагают, что эти значения даются для локального времени. Все методы, возвращающие компоненты даты или времени (месяц, день, час, минуту, секунду и т.п.) также дают правильные значения для локального часового пояса, поэтому вам ничего не нужно делать, чтобы получать правильные результаты для вашей локального часового пояса. Чтобы узнать об управлении часовым поясом, обратитесь к документации.</p>
<h4>Конструкторы и модификаторы wxDateTime</h4>
<p>Объект wxDateTime может быть сконструирован из значения типа time_t (время Unix), информации о дате, информации о времени или полной информации о дате и времени. Для каждого конструктора существует соответствующий метод Set, который изменяет существующий объект, так, чтобы он имел определенные время или дату. Аналогично, существуют модификаторы для индивидуальных компонентов, такие как SetMonth или SetHour, которые меняют только одну компоненту даты или времени.</p>
<ul>
<li><code>wxDateTime(time_t)</code> создает объект с датой и временем в соответствии со значением времени Unix.</li>
<li><code>wxDateTime(const struct tm&amp;)</code> создает объект, используя данные из стандартной структуры tm языка C.</li>
<li><code>wxDateTime(wxDateTime_t hour, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0)</code> создает объект, руководствуясь заданной информацией о времени.</li>
<li><code>wxDateTime(wxDateTime_t day, Month month = Inv_Month, int year = Inv_Year, wxDateTime_t hour = 0, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0)</code> создает объект, руководствуясь заданной информацией о времени и дате.</li>
</ul>
<h4>Аксессоры wxDateTime</h4>
<p>Аксессоры для wxDateTime обычно имеют понятные имена: GetYear, GetMonth, Getday, GetWeekDay, GetHour, GetMinute, GetSecond, GetMillisecond, GeTDayOfYear, GetWeekOfYear, GetWeekOfMonth и GetYearDay. wxDateTime также имеет следующие методы:</p>
<ul>
<li>GetTicks возвращает дату и время в формате времени Unix (число секунд прошедших с полночи 1 января 1970 года).</li>
<li>IsValid указывает находится ли в объекте допустимая дата (можно сконструировать объект, который содержит недопустимую дату).</li>
</ul>
<p>Получаем сегодняшнюю дату</p>
<p>Класс wxDateTime содержит два статических метода для получения текущего времени:</p>
<ul>
<li>wxDateTime::Now создает объект wxDateTime с текущей датой с точностью до секунды.</li>
<li>wxDateTime::UNow создает объект wxDateTime с текущей датой с точностью до милисекунды.</li>
</ul>
<h4>Ввод и форматирование даты</h4>
<p>Функции данного раздела преобразовывают объект wxDateTime в текст и из текста. Преобразование даты в текст достаточно тривиально: вы можете использовать форматирование даты и времени в соответствии с текущей локалью (FormatDate and FormatTime), использовать международный стандарт представления даты, определенный в ISO 8601 (FormatISODate и FormatISOTime) или определить произвольный стандарт, используя метод Format.</p>
<p>Создание даты из строки гораздо более интересная задача, потому что существует множество различных форматов. В самом простом случае ее можно считать с помощью ParseFormat, который может разобрать любую дату в определенном формате. ParseRfc822Date считывает дату в формате из RFC 822, который определяет формат даты для электронной почты в Интернете.</p>
<p>Самыми интересными функциями являются ParseTime, ParseDate и ParseDateTime, которые пытаются считать дату и/или время в <b>произвольном</b> формате, позволяя их определить различными путями. Эти функции можно использовать для разбора пользовательского ввода, который обычно не соответствует никакому предопределенному формату. Например, ParseDateTime может разбирать строки наподобие <b>tomorrow</b> (Завтра), <b>March first</b> (Первое марта) и даже <b>next Sunday</b> (Следующее воскресенье).</p>
<h4>Сравнение дат</h4>
<p>Два объекта wxDateTime можно легко сравнить, используя одну из многих функций сравнения. Все эти методы возвращают true или false.</p>
<p>Следующие методы сравнивают с другим объектом класса wxDateTime: IsEqualTo (равен), IsEarlierThan (раньше чем), IsLaterThan (позже чем), IsSameDate (одна и та же дата) и IsSameTime (одно и то же время).</p>
<p>Следующие методы делают сравнения используя два других объекта wxDateTime: IsStrictlyBetween (точно между) и IsBetween (между). Разница между этими двумя методами в том, что IsStrictlyBetween возвращает false, если wxDateObject равен одному из краевых значений промежутка, тогда как IsBetween вернет в таком случае true.</p>
<h4>Арифметика дат</h4>
<p>Библиотека wxWidgets содержит два очень продвинутых класса для выполнения арифметических операций с объектами wxDateTime: wxTimeSpan и wxDateSpan. wxTimeSpan просто содержит разницу в милисекундах и всегда дает быстрый и предсказуемый результат. С другой стороны время имеет и другие важные единицы измерения, такие как недели и месяцы. wxDateSpan пытается осуществить арифметические операции наиболее естественным путем, однако результат таких операций не всегда хорошо определен. Например, сложение 31 января и 1 месяца даст результат 28 (или 29) февраля, который является последним днем февраля, а не 31 февраля (этот день в феврале не существует). Конечно в данном случае мы получаем то, что ожидаем, однако вы очень удивитесь когда увидите, что вычитание того же самого интервала из 28 февраля даст результат 28 января (а не 31 января с которой мы начинали).</p>
<p>Можно выполнять множество различных операций с датами, но не все из них имеют смысл. Например, умножение даты на число является некорректной операцией, однако умножение временного интервала на число корректно.</p>
<ul>
<li>Сложение: Значения класса wxTimeSpan или wxDateSpan можно прибавить к wxDateTime и в результате получить новый объект wxDateTime. Также можно сложить два интервальных класса и получить другой объект того же самого класса.</li>
<li>Вычитание: Вычитать можно те же самые объекты, как и в операции сложения. Кроме того можно взять разность двух объектов класса wxDateTime, которая будет иметь тип wxTimeSpan.</li>
<li>Умножение: Объекты wxTimeSpan и wxDateSpan могут быть умножены на целое число. Результатом данной операции является объект того же самого типа.</li>
<li>Унарный минус: Можно взять отрицание объектов wxTimeSpan или wxDateSpan. Результатом является интервал с тем же самым значением, но противополножным направлением во времени.</li>
</ul>
<p>Следующий небольшой пример показывает использование wxDateSpan и wxTimeSpan для изменения времени, сохраненного в объекте класса wxDateTime. Обратитесь к официальной документации за полным списком доступных методов.</p>
<pre class="brush: cpp;">
void TimeTests()
{
    // Взять текущую дату и время
    wxDateTime DT1 = wxDateTime::Now();

    // Промежуток в 2 недели и 1 день (т.е. в 15 дней)
    wxDateSpan Span1(0, 0, 2, 1);

    // Вычитаем 15 дней от сегодня
    wxDateTime DT2 = DT1 - Span1;

    // Статическое создание однодневной разницы
    wxDateSpan Span2 = wxDateSpan::Day();

    // Промежуток 3 теперь равен 14 дням
    wxDateSpan Span3 = Span1 - Span2;

    // 0 дней (промежуток определен как 2 недели)
    int Days = Span3.GetDays();

    // 14 дней (2 недели)
    int TotalDays = Span3.GetTotalDays();

    // 2 две недели в прошлое
    wxDateSpan Span4 = -Span3;

    // Промежуток в 3 месяца
    wxDateSpan Span5 = wxDateSpan::Month() * 3;

    // 10 часов, 5 минут и 6 сукунд
    wxTimeSpan Span6(10, 5, 6, 0);

    // Добавляем определенный промежуток к DT2
    wxDateTime DT3 = DT2 + Span6;

    // Span7 в 3 раза дольше, чем Span6, но направлен в прошлое
    wxTimeSpan Span7 = (-Span6) * 3;

    // SpanNeg должно быть true, т.к. промежуток отрицателен
    bool SpanNeg = Span7.IsNegative();

    // Статическое создание одночасовой разницы
    wxTimeSpan Span8 = wxTimeSpan::Hour();

    // Один час не длиннее 30+ часов (сравниваются абсолютные значения)
    bool Longer = Span8.IsLongerThan(Span7);
}
</pre>
<h4>Вспомогательные структуры данных</h4>
<p>wxWidgets использует несколько внутренних структур данных для передачи в качестве параметров и возвращения результатов из открытых методов объектов. Прикладные программисты могут также использовать эти вспомогательные функции в своих проектах.</p>
<h4>wxObject</h4>
<p>Класс wxObject является базовым для всех классов библиотеки wxWidgets. Именно он отвечает за реализацию получения информации о типе времени выполнения, подсчета ссылок, объявление виртуального деструктора и дополнительные отладочные версии операторов new и delete. Класс wxClassInfo хранит мета-данные о классе и используется в некоторых методах класса wxObject.</p>
<pre class="brush: cpp;">
MyWindow* window = wxDynamicCast(FindWindow(ID_MYWINDOW), MyWindow);
</pre>
<p>Метод IsKindOf получает в качестве параметра указатель на wxClassInfo и возвращает true, если объект относится к данному типу. Например,</p>
<pre class="brush: cpp;">bool tmp = obj-&gt;IsKindOf(CLASSINFO(wxFrame));</pre>
<p>Методу Ref передается параметр класса const wxObject&amp;, который заменяет текущие данные объекта на ссылку на указанные в параметре. Число ссылок на текущий хранимый объект уменьшается, возможно освобождаются данные, а число ссылок на объект из параметра увеличивается.</p>
<p>UnRef уменьшает число ссылок на ассоциированные с ним данные и удаляет данные в случае, если число ссылок уменьшилось до нуля.</p>
<h4>Класс wxLongLong</h4>
<p>Класс wxLongLong представляет 64-битные целые числа. Когда возможно используется родной 64-битный тип платформы, во всех остальных случаях используется эмулирующий его код. В результате вы можете использовать этот тип также как и любой другой (встроенный) целочисленный тип. Заметим, что число типа wxLongLong является числом со знаком. Если вам необходимо хранить беззнаковые числа, то используйте для этого тип wxULongLong, который имеет почти похожий API, кроме некоторых логических операторов (таких как взятие модуля числа). Для этих классов определены обычные математические операции, а также несколько дополнительных методов:</p>
<ul>
<li>Abs возвращает абсолютное значение wxLongLong. Если данный метод вызвать у константного объекта, то возвратится копия числа. Для неконстантного объека метод изменит сам объект и возвратит ссылку на него.</li>
<li>ToLong возвращает результат преобразования в тип long. Метод вызывает исключение в debug-версии, если при этом происходит потеря точности.</li>
<li>ToString возвращает строковое представление значения числа.</li>
</ul>
<h4>wxPoint и wxRealPoint</h4>
<p>Тип wxPoint используется библиотекой для хранения пары целочисленных координат (точки) на экране или в окне. Как легко понять по названию, класс хранит пару значений x и y. Данные члены класса являются открытыми, а поэтому с ними можно работать непосредственно. Для wxPoint реализованы операторы + и -, которые позволяют прибалять или вычитать из текущий координат значения типа wxPoint или wxSize. wxRealPoint хранит вещественные (double) координаты вместо целочисленных, а также реализует операторы + и -, но только для вещественных точек.</p>
<p>Создать объект wxPoint очень несложно:</p>
<pre class="brush: cpp;">wxPoint myPoint(50, 60);</pre>
<h4>wxRect</h4>
<p>Этот класс используется для хранения информации о прямоугольной области и обычно используется библиотекой wxWidgets для рисования или в элементах управления, таких как wxDC или wxTreeCtrl. Класс wxRect содержит поля x и y, а также width (ширина) и height (высота), которые являются открытыми. Прямоугольники можно складывать и вычитать друг из друга. Также класс поддерживает несколько других полезных методов.</p>
<ul>
<li><code>GetRight</code> возвращает координату x правой границы прямоугольника.</li>
<li><code>GetBottom</code> возвращает координату y нижней границы прямоугольника.</li>
<li><code>GetSize</code> возвращает размер прямоугольника (высоты и ширину) в виде объекта wxSize.</li>
<li><code>Inflate</code> увеличивает размер прямоугольника на заданную величину, которая может быть одинаковой для обоих направлений (один параметр) или разной для разных (два параметра).</li>
<li>Метод <code>Inside</code> определяет, располагается ли данная точка внутри прямоугольника. Точку можно определить как пару координат или как объект wxPoint.</li>
<li><code>Intersects</code> принимает в качестве параметра другой прямоугольник wxRect и определяет перекрываются ли они.</li>
<li><code>Offset</code> перемещает прямоугольник на заданное смещение. Смещение можно задать пару значений или как объект <code>wxPoint</code>.</li>
</ul>
<p>Объект <code>wxRect</code> можно создать тремя способами. Следующие три объекта определяют один и тот же прямоугольник:</p>
<pre class="brush: cpp;">
wxRect myRect1(50, 60, 100, 200);
wxRect myRect2(wxPoint(50, 60), wxPoint(150, 260));
wxRect myRect3(wxPoint(50, 60), wxSize(100, 200));
</pre>
<h4>wxRegion</h4>
<p>Класс wxRegion представляет простую или сложную область на холсте или окне. Данный класс использует технологию подсчета ссылок, а поэтому операции копирования и присваивания выполняются для него очень быстро. В основном wxRegion используется для определения областей отсечения или обновления.</p>
<p>Метод <code>Contains</code> возвращает true, если данная пара координат, wxPoint, прямоугольник или wxRect находятся внутри данной области.</p>
<p><code>GetBox</code> возвращает объект класса <code>wxRect</code>, представляющий прямоугольник, содержащий область.</p>
<p><code>Intersect</code> возвращает true, если выбранный прямоугольник <code>wxRect</code> или <code>wxRegion</code> пересекает область.</p>
<p><code>Offset</code> перемещает область на определенное смещение. Смещение определяется в виде пары координат x и y.</p>
<p>Методы <code>Subtract</code> (вычитание), <code>Union</code> (объединение) или <code>Xor</code> (исключающее или) меняет регион различными способами, предлагая для этого десяток перегруженных функций. У всех этих методов есть версии, принимающие в качестве параметров <code>wxRegion</code> или <code>wxPoint</code>. Обратитесь к документации, чтобы получить полный список доступных методов.</p>
<p>Следующий пример иллюстрирует четыре самых используемых метода инициализации <code>wxRegion</code>. Все следующие строки создают объекты, представляющие одну и ту же область:</p>
<pre class="brush: cpp;">
wxRegion myRegion1(50, 60, 100, 200);
wxRegion myRegion2(wxPoint(50,60), wxPoint(150, 260));
wxRect myRect(50, 60, 100, 200);
wxRegion myRegion3(myRect);
wxRegion myRegion4(myRegion1);
</pre>
<p>Можно использовать класс <code>wxRegionIterator</code>, чтобы пройтись по всем прямоугольникам в данной области, например для перерисовки <b>поврежденной</b> области экрана в обработчике соответствующего события, как показано в следующем примере:</p>
<pre class="brush: cpp;">
// Вызывается когда окно необходимо перерисовать
void MyWindow::OnPaint(wxPaintEvent&amp; event) {
    wxPaintDC dc(this);

    wxRegionIterator upd(GetUpdateRegion());
    while (upd) {
        wxRect rect(upd.GetRect());

        // перерисовываем прямоугольник
        ... тут идет код ...
        upd++;
    }
}
</pre>
<h4>wxSize</h4>
<p>Класс <code>wxSize</code> используется внутри wxWidgets для хранения целочисленных размеров окна, элементов управления, объектов на холсте и {т.д.} Данный объект также часто возвращается методами, которые возвращают информацию о размере.</p>
<p><code>GetHeight</code> и <code>GetWidth</code> возвращают высоту и ширину.</p>
<p><code>SetHeight</code> и <code>SetWidth</code> принимают целочисленный параметр, определяющий новое значение для высоты или ширины.</p>
<p>Метод <code>Set</code> устанавливает новые параметры для размера.</p>
<p>Объет очень легко создать, указав высоту и ширину:</p>
<pre class="brush: cpp;">wxSize mySize(100, 200);</pre>
<h4>wxVariant</h4>
<p>Класс <code>wxVariant</code> является контейнером для любого типа. Значение данного типа может изменяться в процессе выполнения программы, возможно вместе с типом. Этот класс может применяться для уменьшения размера кода в некоторых задачах, таких как редактор различных типов данных или реализации протокола удаленного вызова процедур.</p>
<p><code>wxVariant</code> может сохранять значения типа <code>bool, char, double, long, wxString, wxArrayString, wxList, wxDateTime</code>, указатель на <code>void</code> и массив <code>wxVariant</code>. Однако, любое приложение может расширить возможности хранения в <code>wxVariant</code>. Для этого необходимо создать наследника от <code>wxVariantData</code> и использовать вариант конструктора класса <code>wxVariant</code> с параметром <code>wxVariantData</code> или оператор присваивания, чтобы присвоить классу <code>wxVariant</code> значение вашего типа. Настоящие значения для пользовательских типов необходимо получать через специальные методы объекта <code>wxVariantData</code>. Это отличается от использования стандартных типов для которых можно вызывать встроенные функции, такие как <code>GetLong</code>.</p>
<p>Помните, что не все типы данных могут быть автоматически преобразованы в другие типы. Например, отсутствует преобразование из логического типа в объект <code>wxDateTime</code> и из целочисленного в <code>wxArrayString</code>. Интуиция должна вам подсказать какого рода преобразования существуют. Вы всегда можете узнать текущий хранимый тип, используя для этого метод <code>GetType</code>. Далее приведен простой пример использования <code>wxVariant</code>:</p>
<pre class="brush: cpp;">
wxVariant Var;

// Сохраняем wxDateTime и получаем wxString
Var = wxDateTime::Now();
wxString DateAsString = Var.GetString();

// Сохраняем wxString, а получаем вещественное число
Var = wxT(&quot;10.25&quot;);
double StringAsDouble = Var.GetDouble();

// Тип должен быть &quot;string&quot; (строка)
wxString Type = Var.GetType();

// Это недопустимое преобразование, так как нельзя преобразовать строку
// в число, поэтому метод возвратит 0
char c = Var.GetChar();
</pre>
<h4>Итоги</h4>
<p>Структуры данных, существующие в wxWidgets позволяют вам легко передавать/получать структурированные данные в/из библиотеки wxWidgets и внутри своего приложения. Мощные функции и классы для обработки информации, такие как <code>wxRegEx, wxStringTokenizer, wxDateTime</code> и <code>wxVariant</code> покроют большинство ваших потребностей в хранении и обработке данных без привлечения сторонних библиотек.</p>
<p>Далее мы рассмотрим средства, предоставляемые wxWidgets для работы с файлами и потоками.</p>
]]></content:encoded>
			<wfw:commentRss>http://wxwidgets.info/wxwidgets_book_chapter_13_ru_part2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
