277 lines
10 KiB
Markdown
277 lines
10 KiB
Markdown
|
---
|
|||
|
title: "Fox Toolkit - пишем маленькие кросс-платформенные приложения с более мощной библиотекой"
|
|||
|
categories: ["cpp", "archive"]
|
|||
|
date: 2015-08-21T00:00:00+03:00
|
|||
|
draft: false
|
|||
|
featured_image: miniature.jpg
|
|||
|
---
|
|||
|
|
|||
|
|
|||
|
После того, как мы [поиграли с FLTK](/fltk-apps), я нашёл ещё одну библиотеку виджетов - Fox Toolkit. Эта библиотека предоставляет более широкие возможности для разработки приложений с графическим интерфейсом.
|
|||
|
|
|||
|
Библиотека также поставляется в виде исходного кода и скачивается с [официального сайта](http://www.fox-toolkit.org/download.html). В статье рассматривается версия 1.6.50. Компилируем под Windows.
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
Все шаги до компиляции аналогичны шагам в [предыдущей статье](/fltk-apps). Открываем документик по пути `куда_распаковали\doc\win32.html` и листаем в самый низ. Ух ты, всё так просто.
|
|||
|
|
|||
|
Только не компилируется нихрена.
|
|||
|
|
|||
|
Оказывается, не один я столкнулся с этой проблемой, так что гугл помог. Вот [тема на форуме](https://forum.fox-toolkit.org/index.php?topic=34.0), которая мне помогла.
|
|||
|
|
|||
|
Итак, что нужно сделать:
|
|||
|
|
|||
|
1. Запустить `./configure --without-x --without-xft` вместо `./configure`
|
|||
|
|
|||
|
2. Исправить заголовочный файл `куда_распаковали\include\xincs.h`:
|
|||
|
|
|||
|
```cpp
|
|||
|
#ifdef HAVE_GL_H // (240 строка)
|
|||
|
#ifndef SUN_OGL_NO_VERTEX_MACROS
|
|||
|
#define SUN_OGL_NO_VERTEX_MACROS
|
|||
|
#endif
|
|||
|
#ifndef HPOGL_SUPPRESS_FAST_API
|
|||
|
#define HPOGL_SUPPRESS_FAST_API
|
|||
|
#endif #include <GL/gl.h>
|
|||
|
#ifndef WIN32 // ifndef заменить на ifdef
|
|||
|
#include <GL/glx.h> // GL/glx.h заменить на GL/glext.h
|
|||
|
#endif // (250 строка)
|
|||
|
```
|
|||
|
|
|||
|
Всё, теперь запускаем **make**, а потом **make install.** Затем можно забирать результат из `туда_куда_установлен_MinGw\msys\1.0\local`.
|
|||
|
|
|||
|
На этом с компиляцией всё.
|
|||
|
|
|||
|
# Пишем программу
|
|||
|
|
|||
|
В качестве примера снова будем писать программу, которая будет считать количество нарисованных пикселей. Почему бы и нет? Используем разметку, которую мы нарисовали в предыдущей статье.
|
|||
|
|
|||
|
fox_test.cpp:
|
|||
|
```cpp
|
|||
|
#include "fox-1.6/fx.h"
|
|||
|
#include <map>
|
|||
|
|
|||
|
char buf[16];
|
|||
|
|
|||
|
struct point {
|
|||
|
int x, y;
|
|||
|
};
|
|||
|
|
|||
|
#define CANVAS_X 10
|
|||
|
#define CANVAS_Y 10
|
|||
|
#define CANVAS_WIDTH 180
|
|||
|
#define CANVAS_HEIGHT 100
|
|||
|
#define GRID_LEN 5 // размер зерна в холсте
|
|||
|
|
|||
|
class PaintWindow : public FXMainWindow {
|
|||
|
FXDECLARE(PaintWindow)
|
|||
|
|
|||
|
typedef std::map<std::pair<int, int>, point> PointMap;
|
|||
|
|
|||
|
|
|||
|
private:
|
|||
|
FXCanvas *canvas; // холст, на котором будем рисовать
|
|||
|
FXLabel *count_label; // надпись
|
|||
|
FXFont *big_font; // шрифт для надписи
|
|||
|
int isMouseDown;
|
|||
|
FXColor drawColor; // цвет пикселей на холсте
|
|||
|
FXColor bgColor; // цвет фона холста
|
|||
|
PointMap pixels; // карта с координатами пикселей
|
|||
|
void setpixel(FXEvent *event);
|
|||
|
|
|||
|
protected:
|
|||
|
PaintWindow() { }
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
enum { // ID обработчиков событий
|
|||
|
ID_CANVAS = FXMainWindow::ID_LAST,
|
|||
|
};
|
|||
|
|
|||
|
long onPaint(FXObject *, FXSelector, void *);
|
|||
|
|
|||
|
long onMouseDown(FXObject *, FXSelector, void *);
|
|||
|
|
|||
|
long onMouseUp(FXObject *, FXSelector, void *);
|
|||
|
|
|||
|
long onMouseMove(FXObject *, FXSelector, void *);
|
|||
|
|
|||
|
PaintWindow(FXApp *a);
|
|||
|
|
|||
|
virtual void create();
|
|||
|
|
|||
|
virtual ~PaintWindow();
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
FXDEFMAP(PaintWindow) PaintWindowMap[] = { // определяем обработчики событий
|
|||
|
FXMAPFUNC(SEL_PAINT, PaintWindow::ID_CANVAS, PaintWindow::onPaint),
|
|||
|
FXMAPFUNC(SEL_LEFTBUTTONPRESS, PaintWindow::ID_CANVAS, PaintWindow::onMouseDown),
|
|||
|
FXMAPFUNC(SEL_RIGHTBUTTONPRESS, PaintWindow::ID_CANVAS, PaintWindow::onMouseDown),
|
|||
|
FXMAPFUNC(SEL_LEFTBUTTONRELEASE, PaintWindow::ID_CANVAS, PaintWindow::onMouseUp),
|
|||
|
FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, PaintWindow::ID_CANVAS, PaintWindow::onMouseUp),
|
|||
|
FXMAPFUNC(SEL_MOTION, PaintWindow::ID_CANVAS, PaintWindow::onMouseMove)
|
|||
|
};
|
|||
|
|
|||
|
FXIMPLEMENT(PaintWindow, FXMainWindow, PaintWindowMap, ARRAYNUMBER(PaintWindowMap))
|
|||
|
|
|||
|
|
|||
|
PaintWindow::PaintWindow(FXApp *a) : FXMainWindow(a, a->getAppName(), NULL, NULL,
|
|||
|
DECOR_TITLE | DECOR_BORDER | DECOR_MINIMIZE |
|
|||
|
DECOR_CLOSE, //настраиваем вид окна
|
|||
|
0, 0, 200, 300) { //выставляем размер окна
|
|||
|
|
|||
|
canvas = new FXCanvas(this, this, ID_CANVAS, FRAME_SUNKEN | FRAME_THICK | LAYOUT_EXPLICIT,
|
|||
|
CANVAS_X,
|
|||
|
CANVAS_Y,
|
|||
|
CANVAS_WIDTH,
|
|||
|
CANVAS_HEIGHT); // задаём параметры холста, LAYOUT_EXPLICIT - абсолютное позиционирование
|
|||
|
|
|||
|
count_label = new FXLabel(this, "...", NULL, LAYOUT_EXPLICIT, 34, 177, 133, 56);
|
|||
|
|
|||
|
FXFontDesc fontdescription;
|
|||
|
getApp()->getNormalFont()->getFontDesc(fontdescription); // получаем стандартный шрифт
|
|||
|
|
|||
|
big_font = new FXFont(getApp(), fontdescription.face, 37,
|
|||
|
FXFont::Normal); // создаём стандартный шрифт с нужным размером
|
|||
|
big_font->create();
|
|||
|
|
|||
|
count_label->setFont(big_font);
|
|||
|
|
|||
|
drawColor = FXRGB(0, 0, 0);
|
|||
|
bgColor = FXRGB(255, 255, 255);
|
|||
|
|
|||
|
isMouseDown = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PaintWindow::~PaintWindow() {
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void PaintWindow::create() {
|
|||
|
FXMainWindow::create();
|
|||
|
show(PLACEMENT_SCREEN); //показываем окно в центре экрана
|
|||
|
}
|
|||
|
|
|||
|
void PaintWindow::setpixel(FXEvent *event) {
|
|||
|
int x = event->win_x;
|
|||
|
int y = event->win_y;
|
|||
|
|
|||
|
if (x < 0 || y < 0 || x + 2 >= CANVAS_WIDTH || y + 2 >= CANVAS_HEIGHT)
|
|||
|
return; // проверяем, не вышел ли курсор за пределы холста
|
|||
|
|
|||
|
x = (event->win_x + 2) / GRID_LEN;
|
|||
|
y = (event->win_y + 2) / GRID_LEN;
|
|||
|
|
|||
|
std::pair<int, int> p = std::make_pair(x * GRID_LEN, y * GRID_LEN); // создаём хеш из двух координат
|
|||
|
|
|||
|
FXDCWindow dc(canvas);
|
|||
|
|
|||
|
bool add = event->click_button == 1; // если кнопка левая, то рисуем, правой - удаляем
|
|||
|
|
|||
|
dc.setForeground(add ? drawColor : bgColor);
|
|||
|
|
|||
|
if (add) {
|
|||
|
point pixel;
|
|||
|
pixel.x = x * GRID_LEN;
|
|||
|
pixel.y = y * GRID_LEN;
|
|||
|
pixels[p] = pixel;
|
|||
|
} else {
|
|||
|
pixels.erase(p);
|
|||
|
}
|
|||
|
|
|||
|
dc.fillRectangle(x * GRID_LEN, y * GRID_LEN, GRID_LEN, GRID_LEN); // рисуем квадратики
|
|||
|
|
|||
|
sprintf(buf, "%d px", pixels.size());
|
|||
|
count_label->setText(buf); // обновляем надпись
|
|||
|
}
|
|||
|
|
|||
|
long PaintWindow::onMouseUp(FXObject *, FXSelector, void *ptr) { // при отпускании мыши
|
|||
|
canvas->ungrab(); // отключаем перетаскивание в холсте
|
|||
|
if (isMouseDown) {
|
|||
|
FXDCWindow dc(canvas);
|
|||
|
dc.setForeground(drawColor);
|
|||
|
isMouseDown = 0;
|
|||
|
}
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
long PaintWindow::onMouseDown(FXObject *, FXSelector, void *ptr) { // при нажатии мыши
|
|||
|
canvas->grab(); // включаем перетаскивание в холсте
|
|||
|
setpixel((FXEvent *) ptr);
|
|||
|
isMouseDown = 1;
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
long PaintWindow::onMouseMove(FXObject *, FXSelector, void *ptr) {
|
|||
|
if (isMouseDown) {
|
|||
|
setpixel((FXEvent *) ptr);
|
|||
|
}
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
long PaintWindow::onPaint(FXObject *, FXSelector,
|
|||
|
void *ptr) { //если окно сворачивается или выходит за пределы видимости, то его нужно перерисовать
|
|||
|
FXEvent *ev = (FXEvent *) ptr;
|
|||
|
FXDCWindow dc(canvas, ev);
|
|||
|
dc.setForeground(bgColor);
|
|||
|
dc.fillRectangle(ev->rect.x, ev->rect.y, ev->rect.w, ev->rect.h);
|
|||
|
|
|||
|
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;
|
|||
|
dc.setForeground(drawColor);
|
|||
|
dc.fillRectangle(x, y, GRID_LEN, GRID_LEN);
|
|||
|
|
|||
|
}
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
int main(int argc, char **argv) {
|
|||
|
FXApp application("Pixels", "MultiMote");
|
|||
|
application.init(argc, argv);
|
|||
|
|
|||
|
new PaintWindow(&application);
|
|||
|
application.create();
|
|||
|
|
|||
|
return application.run();
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
##### Компилируем исходник следующей командой:
|
|||
|
|
|||
|
```cmd
|
|||
|
g++ имя_исходника -o имя_результата -static -static-libgcc -static-libstdc++ -lFOX-1.6 -mwindows
|
|||
|
```
|
|||
|
|
|||
|
**-static -static-libgcc -static-libstdc++** – связываем библиотеки MinGw с приложением, чтобы оно запускалось на других компьютерах
|
|||
|
|
|||
|
**-lFOX-1.6** – подключаем библиотеку
|
|||
|
|
|||
|
**-mwindows** – убираем окно команд и подключаем несколько системных приложений
|
|||
|
|
|||
|
Также можно добавить флаги **-O2** и **-s** для уменьшения размера исполняемого файла.
|
|||
|
|
|||
|
![|580](exe.png)
|
|||
|
|
|||
|
Теперь можно запускать:
|
|||
|
|
|||
|
![|206](app.png)
|
|||
|
|
|||
|
Под linux приложение выглядит точно так же:
|
|||
|
|
|||
|
![|659](linux.png)
|
|||
|
|
|||
|
Цель достигнута :)
|
|||
|
|
|||
|
Итак, можно делать выводы.
|
|||
|
|
|||
|
Библиотека предоставляет гораздо большие возможности, чем FLTK.
|
|||
|
|
|||
|
А если честно, библиотека меня крайне выбесила.
|