188 lines
9.0 KiB
Markdown
188 lines
9.0 KiB
Markdown
|
---
|
|||
|
title: "FLTK - пишем маленькие кросс-платформенные приложения с олдскульным интерфейсом"
|
|||
|
categories: ["cpp", "archive"]
|
|||
|
date: 2015-08-19T00:00:00+03:00
|
|||
|
draft: false
|
|||
|
featured_image: miniature.jpg
|
|||
|
---
|
|||
|
|
|||
|
|
|||
|
Иногда требуется написать кросс-платформенное приложение с небольшим размером. Для управления микроконтроллером, например. Или [рисования иконок для дисплеев](/avr-lcd-images). Но использовать кросс-платформенные библиотеки вроде Qt, WxWidgets не имеет смысла - весят они ну очень много. Неудобно получается, когда приложение весит 100кб, а графическая библиотека для него – под 30Мб.
|
|||
|
|
|||
|
На помощь к нам приходит FLTK – Fast, Light Toolkit.
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
Библиотека распространяется в виде исходного кода и скачивается с сайта [fltk.org](http://www.fltk.org/software.php"). Значит, сейчас будем её собирать.
|
|||
|
|
|||
|
Весь процесс описывается для Windows, собираем компилятором **MinGw**. Если у вас его нет – [вперёд скачивать](https://sourceforge.net/downloads/mingw). Разделим процесс на две части.
|
|||
|
|
|||
|
# Часть первая – компиляция библиотеки
|
|||
|
|
|||
|
Итак, начнём. Скачиваем последнюю версию FLTK с официального сайта. Архив должен называться fltk-версия-**source**.tar.gz. Распаковываем его в любое удобное место. Я распаковал его прямо на на диск C в папку fltk-src.
|
|||
|
|
|||
|
В распакованном виде всё должно выглядеть так:
|
|||
|
|
|||
|
![src](src.png)
|
|||
|
|
|||
|
Теперь нам нужно запустить MSYS. Переходим `туда_куда_установлен_MinGw\msys\1.0` и запускаем там msys.bat.
|
|||
|
|
|||
|
![mingw1](mingw1.png)
|
|||
|
|
|||
|
Вводим туда `cd /диск/папка_с_fltk`
|
|||
|
|
|||
|
![mingw2](mingw2.png)
|
|||
|
|
|||
|
Потом вводим `./configure --enable-threads --enable-localjpeg --enable-localzlib --enable-localpng` и ждём.
|
|||
|
|
|||
|
![mingw3](mingw3.png)
|
|||
|
|
|||
|
Далее следует ввести `make` и ждать. Можно пойти чай заварить.
|
|||
|
|
|||
|
![mingw4](mingw4.png)
|
|||
|
|
|||
|
Теперь копируем библиотеки в компилятор. Для этого вводим `make install`
|
|||
|
|
|||
|
![mingw5](mingw5.png)
|
|||
|
|
|||
|
Всё, что получилось складывается в папку `туда_куда_установлен_MinGw\msys\1.0\local`. Для удобства я перенёс эти папки в корень MinGw.
|
|||
|
|
|||
|
Всё, библиотека готова к использованию.
|
|||
|
|
|||
|
# Часть вторая – пишем программу
|
|||
|
|
|||
|
Теперь мы можем написать тестовое приложение, используя эту библиотеку. Писать будем программу, которая будет считать количество нарисованных пикселей.
|
|||
|
|
|||
|
Для начала нужно нарисовать макет нашей программы (о FLUID я узнал позже). Я нарисовал в GIMP.
|
|||
|
|
|||
|
![gimp](gimp.png)
|
|||
|
|
|||
|
Зачем это делать? Всё просто. У каждого элемента в окне есть свои координаты. И чтобы не ставить элементы наугад, можно просто навести мышку на точку в графическом редакторе и узнать координаты. Исходя из этого всего пишем программу.
|
|||
|
|
|||
|
fltk_test.cpp:
|
|||
|
```cpp
|
|||
|
#include <FL/Fl.H>
|
|||
|
#include <Fl/Fl_Window.H>
|
|||
|
#include <Fl/Fl_Box.H>
|
|||
|
#include <Fl/fl_draw.H>
|
|||
|
#include <stdio.h>
|
|||
|
#include <map>
|
|||
|
#include <math.h>
|
|||
|
|
|||
|
#define CANVAS_X 10
|
|||
|
#define CANVAS_Y 10
|
|||
|
#define CANVAS_WIDTH 180
|
|||
|
#define CANVAS_HEIGHT 100
|
|||
|
#define GRID_LEN 5 // размер зерна в холсте
|
|||
|
|
|||
|
Fl_Box *count_label;
|
|||
|
char buf[16];
|
|||
|
|
|||
|
struct point {
|
|||
|
int x, y;
|
|||
|
};
|
|||
|
|
|||
|
typedef std::map<std::pair<int, int>, point> PointMap; // карта с координатами пикселей
|
|||
|
PointMap pixels;
|
|||
|
|
|||
|
|
|||
|
class PaintWindow : public Fl_Window { //немного модифицируем стандартное окно
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
PaintWindow(int w, int h, char const *title) : Fl_Window(w, h, title) {
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void setpixel(int x, int y, bool add) {
|
|||
|
std::pair<int, int> p = std::make_pair(x * GRID_LEN, y * GRID_LEN); // с помощью древней магии мы используем два аргумента как ключ к карте пикселей
|
|||
|
|
|||
|
if (add) {
|
|||
|
point pixel;
|
|||
|
pixel.x = x * GRID_LEN;
|
|||
|
pixel.y = y * GRID_LEN;
|
|||
|
pixels[p] = pixel;
|
|||
|
} else {
|
|||
|
pixels.erase(p);
|
|||
|
}
|
|||
|
|
|||
|
sprintf(buf, "%d px", pixels.size());
|
|||
|
count_label->label(buf); // обновляем надпись
|
|||
|
|
|||
|
redraw();
|
|||
|
}
|
|||
|
|
|||
|
int handle(int event) {
|
|||
|
double x = Fl::event_x();
|
|||
|
double y = Fl::event_y();
|
|||
|
|
|||
|
if (x < CANVAS_X || x > CANVAS_X + CANVAS_WIDTH - 1 || y < CANVAS_Y || y > CANVAS_Y + CANVAS_HEIGHT - 1) // если мышка за границей холста, то ничего не делаем
|
|||
|
return Fl_Window::handle(event);
|
|||
|
|
|||
|
if (event == FL_PUSH) {
|
|||
|
setpixel(round(x / GRID_LEN), round(y / GRID_LEN), Fl::event_button() == FL_LEFT_MOUSE); //округляем координаты исходя из зерна, добавляем или удаляем пиксель в зависимости от кнопки мыши
|
|||
|
}
|
|||
|
if (event == FL_DRAG) {
|
|||
|
setpixel(round(x / GRID_LEN), round(y / GRID_LEN), Fl::event_button() == FL_LEFT_MOUSE);
|
|||
|
}
|
|||
|
|
|||
|
return Fl_Window::handle(event);
|
|||
|
}
|
|||
|
|
|||
|
void draw(void) {
|
|||
|
Fl_Window::draw();
|
|||
|
fl_color(FL_WHITE);
|
|||
|
fl_rectf(CANVAS_X, CANVAS_Y, CANVAS_WIDTH, CANVAS_HEIGHT); // заливаем белый квадрат
|
|||
|
fl_color(FL_BLACK);
|
|||
|
|
|||
|
typedef PointMap::iterator it_type;
|
|||
|
for (it_type iterator = pixels.begin(); iterator != pixels.end(); iterator++) { // перебираем все пиксели
|
|||
|
int x = iterator->second.x;
|
|||
|
int y = iterator->second.y;
|
|||
|
fl_rectf(x, y, 5, 5); // рисуем точки
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
PaintWindow *window;
|
|||
|
|
|||
|
int main(void) {
|
|||
|
window = new PaintWindow(200, 300, "Points"); //создаём окно
|
|||
|
count_label = new Fl_Box(34, 177, 133, 56, "..."); // создаём подпись
|
|||
|
count_label->labelsize(50); //выставляем размер шрифта
|
|||
|
|
|||
|
window->end(); // закрываем группу окна
|
|||
|
window->show(); // показываем окно
|
|||
|
return Fl::run();
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Теперь нужно сие дело откомпилить. Открываем терминал в папке с программой и пишем там
|
|||
|
|
|||
|
```cmd
|
|||
|
g++ <имя_исходника> -o <имя_исполняемого_файла> -DWIN32 -D__NO_INLINE__ -static -static-libgcc -static-libstdc++ -lfltk -lmingw32 -lole32 -luuid -lcomctl32 -mwindows
|
|||
|
```
|
|||
|
|
|||
|
**-DWIN32** – флаг, которые заставят думать FLTK, что мы под Windows
|
|||
|
|
|||
|
**-mwindows** – убираем чёрное окошко у приложения и подключаем некоторые системные библиотеки
|
|||
|
|
|||
|
**-DNO_INLINE** – флаг, который заставит работать math в нашей программе
|
|||
|
|
|||
|
**-static -static-libgcc -static-libstdc++** – флаги. благодаря которым программа запустится на других компьютерах и не будет ничего требовать
|
|||
|
|
|||
|
**-lfltk -lmingw32 -lole32 -luuid -lcomctl32** – флаги, с помощью которых подключается библиотека и всё, что ей требуется. В некоторых случаях может также понадобиться флаг -lgdi32.
|
|||
|
|
|||
|
Также можно добавить флаги **-O2** и **-s** для уменьшения размера исполняемого файла.
|
|||
|
|
|||
|
![output](output.png)
|
|||
|
|
|||
|
Теперь можно запустить наше творение :)
|
|||
|
|
|||
|
![app](app.png)
|
|||
|
|
|||
|
И да, код программы ужасен и написан в исключительно демонстрационных целях.
|
|||
|
|
|||
|
Источников в этот раз не будет, так как всю информацию черпал из программ-примеров, находящихся в том же архиве, что и исходник библиотеки (папки examples и test).
|
|||
|
|