Простота превыше всего!

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

Не так давно Pim прислал мне интересную картинку, порожденную современным обществом, изображающую во многом всеобщее стремление в интерфейсостроении. На изображении перечеркнуто множество окон с разнообразными элементами управления и в качестве альтернативы предложена одна единственная кнопка “ПЫЩЬ”. Эта картинка меня так задела, что я потратил пол дня на вспоминание WinAPI и реализацию глубинной задумки неизвестного мне автора.

Моя свежеиспеченная программа позволяет вам без особого труда сделать “ПЫЩЬ”, чем поднять себе и окружающим настроение. Отсюда вытекает, что программа не просто имеет понятный интерфейс, а еще и обладает свойством, как говорят многие, продлевающим жизнь.

Для начала можете оценить программу в действии. Для этого необходимо ее скачать, распаковать архив и запустить исполнимый файл. Адрес для скачивания: http://zhenyushik.org.ua/software/pysh.zip . А тем временем я вам поведаю во всех подробностях о том, как самостоятельно создавать программное обеспечение с понятным итнерфейсом.

Первым делом необходимо скачать из интернета соответсвующие инструменты. Я пользовался открытыми интструментами (с открытым исходным кодом). Итак, необходимо загрузить на свой компьютер:

  1. Графический редактор GIMP
  2. Аудио редактор Audacity
  3. Среду разработки (в комплекте с компилятором gcc под windows) Dev-C++

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

Создание понятного интерфейса необходимо начинать непосредственно с визуального представления этого самого интерфейса. Для этого запускаем GIMP  и в главном меню основного окна программы выбираем: Расш. -> Кнопки -> Круглая кнопка…

На экране отобразится  панель настроек Script-Fu для создания круглой кнопки. Редактируем поля, выбираем цвета и шрифт. Как оказалось, не так просто в разделе “Круглая кнопка…” сделать круглую кнопку. В 99% она у вас будет получаться совсем не круглой. Поэтому рекомендую поиграться со всеми параметрами и смотреть как разрешение результирующего изображения будет зависеть от них. Разрешение изображения после генерации видно прямо в заголовке окна с изображением.

После генерации кнопок не спешите их сохранять, а присмотритесь к изображению в полном размере. Вы будете очень удивлены, но слева и сверху кнопки будет отступ в 1 пиксель. В дальнейшем это создаст очень некрасивое изображение в программе и вся понятность интерфейса будет осквернена! Поэтому необходимо в главном меню окна с изображением выбрать: Изображение -> Размер холста. После изменения размера на 1 точку по горизонтали и вертикали, необходимо схватить миниатюру изображения и сдвинуть в левый верхний угол или же вручную ввести смещение -1 по X и Y  как показано на рисунке.

resize

Установка размера холста

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

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

Следующим этапом разработки может быть звуковая индикация или же написание программного кода. Запись звука в моём случае производилась в самом конце, но для последовательности изложения мы можем его записать перед написанием программы.

Устанавливаем аудиоредактор Audacity, подключаем микрофон к компьютеру… Ну опять же, это было в моем случае. Вам, быть может, захочется использовать какие-то готовые интересные семплы или вырезки из других файлов – дерзайте. А мы тем временем записываем звук, удаляем с дорожки все лишнее и производим экспорт его в Wav (Файл -> Экспортировать в wav). Перед записью рекомендую настроить программу, чтобы результирующий файл был не таким большим. Например снизить частоту дискретизации до 22050 и размер сэмпла до 8 бит. Для этого идем в: Правка -> Настроить… -> Качество. Или можно потом изменить качество какой-нибудь стандартной программой, например “Звукозапись”, которая в славные времена windows 95 называлась “Фонограф”. Сохраняем полученный wav-файл и переходим к самому интересному.

Запускаем Dev-C++. Создаем новый c++ проект типа Windows Application. Даем ему название. Выбираем где он будет храниться на диске. В общем все интуитивно понятно. В конечном итоге IDE создаст нам заготовку для нового проекта, в которой будет производиться создание окна и обработка некоторых событий окна в оконной процедуре.

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

#define MAX_PUSH_COUNT 10

int buttonPushCount = 0;
bool isButtonPushed = false;
HINSTANCE hInst;

При всей нежелательности использования глобальных переменных, мы их все же используем. Это позволяет понятный интерфейс реализовать понятными методами :) .

Создаем в проекте файл ресурсов и добавляем в него наши картинки и звук. Также можно сделать иконку для приложения. Файл ресурсов представляет собой текстовое описание ресурсов, пригодное для компилятора ресурсов.  Вначале идет название ресурса, затем тип и в заключении путь к файлу на диске.

BUTTON BITMAP “../p1_red.bmp”
BUTTON_PUSHED BITMAP “../p2_red.bmp”
PUSH_SOUND WAVE “../psnd_.wav”
PYSH_ICON ICON “../pysh.ico”

Исправляем некоторые части автоматически сгенерированного кода: заменяем иконки, тип курсора.

wincl.hIcon =  LoadIcon (hThisInstance, “PYSH_ICON”);
wincl.hIconSm = LoadIcon (hThisInstance, “PYSH_ICON”);
wincl.hCursor = LoadCursor (NULL, IDC_HAND);

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

RECT rc;
GetClientRect(GetDesktopWindow(), &rc);

HBITMAP hbm;
hbm = LoadBitmap(hInst, “BUTTON”);
BITMAP bm;
GetObject(hbm, sizeof(BITMAP), (LPSTR) &bm);
DeleteBitmap(hbm);

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

hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
“Пыщь!”, /* Title Text */
WS_POPUP, /* default window */
CW_USEDEFAULT , /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
bm.bmWidth, /* The programs width */
bm.bmHeight, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);

Использованный стиль WS_POPUP хорош тем, что не имеет заголовка у окна.

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

HRGN hWinReg;
hWinReg = CreateEllipticRgn(0, 0, bm.bmWidth, bm.bmHeight);
SetWindowRgn(hwnd, hWinReg, TRUE);

Ну и перемещаем окошко в центр.

MoveWindow(hwnd, (rc.right – bm.bmWidth) / 2, (rc.bottom – bm.bmHeight) / 2, bm.bmWidth, bm.bmHeight, FALSE);

Перейдем к главному месту – оконной процедуре. В этой процедуре происходит обработка сообщений поступающих окну.

Объявляем набор переменных необходимых для базового рисования в окошке

HDC hdc;
PAINTSTRUCT ps;
HBITMAP hbm;
RECT rt;

При приходе сообщении о перерисовке окна, заполняем окошко соответсвующим bmp-файлом из ресурсов.

hdc = BeginPaint(hwnd, &ps);
if (isButtonPushed) {
hbm = LoadBitmap(hInst, “BUTTON_PUSHED”);
}
else {
hbm = LoadBitmap(hInst, “BUTTON”);
}
DrawBitmap(hdc, 0, 0, hbm);
DeleteBitmap(hbm);
EndPaint(hwnd, &ps);

Для заполнения используем свежепозаимсвованную функцию DrawBitmap, которая обильно используется в учебной литературе.

При нажатии на окне левой кнопкой мыши, генерируется событие WM_LBUTTONDOWN, в обработчике которого мы меняем флаг состояния кнопки, делаем клиентскую область окна недействительной (нуждающейся в перерисовке) и проигрываем из ресурсов звуковой wav-файл. Для того, чтобы наша кнопка не заглючила при выводе курсора за пределы окна с одновременным удержанием в нажатом состоянии кнопки мыши, производим захват сообщений мыши функцией SetCapture. Это позволит получать сообщения, даже если курсор мыши находится за пределами клиенсткой области окна.

isButtonPushed = true;
GetClientRect(hwnd, &rt);
InvalidateRect(hwnd, &rt, TRUE);
PlaySound(“PUSH_SOUND”, hInst, SND_RESOURCE | SND_ASYNC);
SetCapture(hwnd);

Соответсвенно при отпускании кнопки генерируется событие WM_LBUTTONUP и мы все возвращаем на место, включая и “захваченную мышь”. Заодно производим проверку на предмет не достигло ли количество нажатий максимального и если достигло – уничтожаем окно.

isButtonPushed = false;
GetClientRect(hwnd, &rt);
InvalidateRect(hwnd, &rt, TRUE);
buttonPushCount++;
if (buttonPushCount == MAX_PUSH_COUNT) {
DestroyWindow(hwnd);
break;
}
ReleaseCapture();

Добавив подключение необходимых header-файлов кажется, что вот он и конец простой программе с понятным интерфейсом. Но при компиляции линковщик начинает усиленно ругаться на то, что не может подвязать библиотеку, содержащую функцию проигрывания звука. Потратив еще немного времени находим решение – добавляем в параметры проекта путь к файлу описания библиотеки libwinmm.a .

lib

Добавление библиотеки

Компилируем проект и получаем исполнимый файл достаточного большого размера. Всему виной то, что в ресурсах хранятся bmp-файлы и wav-файл, которые  содержат в себе чистые (не сжатые) картинки и звук.

Для уменьшения размера полученного файла для начала рекомендую удалить из него все намеки на отладочную информацию с помощью утилиты strip.exe, входящей в комплект gcc, используемого в качестве компилятора в среде Dev-C++. Утилита находится в соотвествующем каталоге программы, в качестве параметра ей передается имя исполнимого файла или библиотеки.

Далее берем еще одну открытую программу под названием UPX, которая является exe-упаковщиком. В старые добрые dos-времена подобные программы пользовались огромной популярностью. Указываем максимальную степень сжатия и путь к нашему файлу (upx.exe -9 пыщь.exe). Радуемся уменьшенному во много раз размеру. Теперь простой и понятный интерфейс можно вливать в широкие массы.

Почему мы не использовали сверхсовременные технологии .net, flash или еще что-нибудь? Потому, что они излишне загружают компьютер, от чего теряется вся легкость простого и понятного интерфейса. Использование лишь исключительно стандартных winapi функций должно позволить запускать бех проблем программное обеспечение с новым типом интерфейса на любых версиях ОС, даже на старенькой windows 3.11 и в unix-системах используя эмулятор wine. Для совместимости со старыми версиями ОС рекомендую все же не использовать 24-битные bmp-картинки :) .

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

Метки: ,

Комментарии запрещены.