Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Использование графического интерфейса библиотеки FLTK при создании программ на языке программирования С++. Учебно-методическое пособие

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
777 Кб
Скачать

системы, устройство и т.п.) зависит от оконного менеджера. Это не недостаток FLTK, а, скорее, общая проблема программирования графического интерфейса.

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

Процесс работы и формирования значка с использованием программы Visual Studio можно представить в следующем виде: изображение значка создается в графическом формате и хранится в специальном файле с расширением .ico. Файл .ico может содержать изображение значка приложения в нескольких графических разрешениях (например, 16x16, 32x32 и т.д.). В таком случае оконный менеджер может выбрать оптимальный размер изображения для конкретной ситуации. Затем файл .ico подключается к исполняемому файлу в процессе компиляции приложения. Сначала создается небольшой rc-файл, в котором указывается путь к значку. Затем этот файл переформировывается с помощью компилятора ресурсов (rc.exe, входит в набор инструментов командной строки Visual Studio). Компилятор ресурсов преобразует rc-файл в ресурсный файл с расширением .res, который затем может быть добавлен, точно так же, как и любой объектный файл. Значок будет отображаться в ярлыках рабочего стола оконного менеджера и файловых браузерах каждый раз, когда будет указана ссылка на исполняемый файл.

Для подключения значка с помощью FLTK необходимо использовать функцию LoadIcon() с подключением заголовочного файла windows.h, в котором объявляются функции, предоставляющие интерфейс доступа к Windows API, пример использования функции LoadIcon():

#include <FL/Fl.H> #include <FL/Fl_Window.H> #ifdef WIN32

#include <FL/x.H> #include <windows.h> #endif

int main() {

Fl_Window *win = new Fl_Window(400, 200, "Заголовок программы"); #ifdef WIN32

win->icon((const void*)LoadIcon(fl_display, MAKEINTRESOURCE(100)));

#endif

win->show(); Fl::run();

}

Перед этим необходимо создать rc-файл с указанием расположения файла значка, например:

41

IDI_ICON ICON DISCARDABLE "D:/lidar.ico"

Для реализации просмотра изображений или каких-либо миниатюр с текстом, так что миниатюры автоматически переносятся при изменении размера окна, можно наследовать свой класс от класса Fl_Scroll, в новом классе реализовать функции выставления изменившихся положений миниатюр, пример:

class MyThumbnailViewer : public Fl_Scroll { int xsep;

int ysep;

//выстраиваем миниатюры изображений, согласно новому положению void RearrangeChildren(int X, int Y, int W, int H) {

int nchildren = children() – 2; if ( nchildren < 1 ) return;

int sw = ( scrollbar.visible() ) ? scrollbar.w() : 0; int thumb_w = (child(0)->w() + xsep);

int thumb_h = (child(0)->h() + ysep);

//количество миниатюр по горизонтали

int nw = (W – sw – xsep) / thumb_w; int remain = (W – sw – xsep) % thumb_w; if ( nw < 2 ) nw = 2;

int left = X + xsep + (remain/2); int top = Y + ysep;

int tx = left; int ty = top;

for ( int i=0; i<nchildren; i++ ) { Fl_Widget *w = child(i); w->position(tx,ty);

if ( (i % nw) == (nw – 1) ) { ty += thumb_h;

tx = left;

}

else {

tx += thumb_w;

}

}

}

void resize(int X, int Y, int W, int H) { RearrangeChildren(X,Y,W,H); Fl_Scroll::resize(X,Y,W,H);

}

42

public:

MyThumbnailViewer(int X, int Y, int W, int H, const char *L=0) : Fl_Scroll(X,Y,W,H,L) {

xsep = 5; ysep = 5;

}

//Установка расстояния между миниатюрами void separation(int X, int Y) {

xsep = X; ysep = Y; autoarrange();

}

//Определение положения и выставление миниатюр void autoarrange() {

RearrangeChildren(x(),y(),w(),h()); Fl_Scroll::redraw();

}

void draw() {

static int first = 1;

if ( first ) { autoarrange(); first = 0; } Fl_Scroll::draw();

}

};

Непосредственно рисование миниатюр можно реализовать в классе, наследуемом от Fl_Box, пример:

class Thumbnail : public Fl_Box { int handle(int event) {

int ret = 0; switch ( event ) {

case FL_PUSH:

if ( Fl::event_button() == 1 ) { ret = 1;

}

break;

case FL_RELEASE:

if ( Fl::event_button() == 1 && Fl::event_inside(x(),y(),w(),h()) ) {

ret = 1;

fl_alert("thumbnail '%s' clicked", label());

}

break;

}

43

return Fl_Box::handle(event) | ret;

}

public:

Thumbnail(int X, int Y, int W, int H, const char *L=0) : Fl_Box(X,Y,W,H,L) { image(G_cat);

box(FL_UP_BOX); color(FL_GRAY);

}

};

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

ввекторном формате, например, SVG, который является языком разметки масштабируемой векторной графики и входит в подмножество расширяемого языка разметки XML. Данный формат используется для описания двумерной векторной и смешанной векторно/растровой графики в формате XML, рисунок 19. Для реализации создается новый класс, который наследуется от Fl_Box, в новом классе реализуется функция создания и отображение нового изображения

вформате SVG, для этого используется sstream, позволяющий организовать работу со строками через интерфейс потоков, пример реализации нового класса:

сlass RoundedImageDisplay : public Fl_Box { int bordercolor_[3];

int radius_;

Fl_SVG_Image *svg_image_;

protected:

void rebuild_svg() { std::stringstream s;

s << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"

<<"<svg width='" << w() << "' height='" << h() << "'>\n"

<<" <rect x='" << (0-radius_/2) << "' "

<<"y='" << (0-radius_/2) << "' "

<<"rx='" << radius_ << "' "

<<"ry='" << radius_ << "' "

<<"width='" << (w()+radius_) << "' "

<<"height='" << (h()+radius_) << "' "

<<"fill='none' "

<<"stroke='rgb(" << bordercolor_[0] << ","

<<bordercolor_[1] << ","

<<bordercolor_[2] << ")' "

<<"stroke-width='" << radius_ << "' />\n"

<<"</svg>\n";

if ( svg_image_ ) delete svg_image_;

44

svg_image_ = new Fl_SVG_Image(NULL, s.str().c_str()); parent()->redraw();

}

public:

RoundedImageDisplay(int X,int Y,int W,int H,const char *title=0) : Fl_Box(X,Y,W,H,title) {

svg_image_ = 0; radius(20);

bordercolor(0x80,0x80,0x80); box(FL_FLAT_BOX);

}

void bordercolor(int R,int G,int B) { bordercolor_[0] = R; bordercolor_[1] = G; bordercolor_[2] = B; rebuild_svg();

}

void radius(int val) { radius_ = val; rebuild_svg();

}

void draw() { Fl_Box::draw();

if ( svg_image_ ) svg_image_->draw(x(), y());

}

};

45

Рисунок 19 – Виджет, который отображает изображение со сглаженными закругленными углами

Для работы с OpenGL библиотека FLTK предлагает два класса: GlWindow и GlutWindow. Эти классы реализуют специальные типы окон, у которых рабочая поверхность используется для вывода графики OpenGL. Так же, как и обычные окна, они могут содержать дочерние виджеты и обрабатывать сообщения, адресованные главному окну программы. GlWindow предоставляет базовую функциональность, необходимую для работы с OpenGL, а GlutWindow дополнительно использует функции библиотеки GLUT. OpenGL – это графический инструментарий, предоставляющий процедуры для рисования. OpenGL – это обобщение GL. Чтобы его расширить, его пришлось усложнить. OpenGL предоставляет процедуры для рисования графики в окне.

Интерфейс OpenGL разрабатывался максимально независимым от платформы, поэтому в OpenGL не были включены функции для обработки сообщений системы и взаимодействия с окнами. OpenGL программы разрабатываются, в основном, в графических многооконных средах, а значит, необходимы средства для взаимодействия между OpenGL и оконной системой. Для X Window была разработана система GLX, а для Windows GDI – WGL (Wiggle), но эти расширения были довольно сложны и несовместимы друг с другом. Нишу заполнила разработанная Марком Килгардом библиотека GLUT, которая отличалась от GLX/WGL простотой использования и кроссплатформенностью, можно сказать, что GLUT на каждой платформе представляет собой надстройку над расширениями конкретной системы.

46

Учитывая популярность GLUT, разработчик FLTK Билл Спитцак добавил поддержку интерфейса GLUT в набор виджетов. FLTK поддерживает гораздо больше функций, чем GLUT, – это полный набор инструментов пользовательского интерфейса, который позволяет программисту создавать полноценные программы. Он поддерживает работу с окнами, виджеты (например, кнопки и ползунки, даже миниатюрный html-браузер для создания справочных систем), имеет хорошую модель обработки событий и т. д.

Пример использования вызовов OpenGL в FLTK с рисованием скрещенных линий, рисунок 20:

#include <FL/Fl.H>

#include <FL/Fl_Gl_Window.H> #include <FL/gl.h>

class MyGlWindow : public Fl_Gl_Window { void draw() {

if (!valid()) { glLoadIdentity(); glViewport(0,0,w(),h());

glOrtho(-w(),w(),-h(),h(),-1,1);

}

glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0);

glBegin(GL_LINE_STRIP); glVertex2f(w(), h()); glVertex2f(-w(),-h()); glEnd();

glBegin(GL_LINE_STRIP); glVertex2f(w(),-h()); glVertex2f(-w(), h()); glEnd();

}

public:

MyGlWindow(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) {

}

};

int main() {

Fl_Window win(500, 300, "OpenGL X"); MyGlWindow mygl(10, 10, win.w()-20, win.h()-20); win.end();

win.resizable(mygl);

win.show();

return(Fl::run());

}

47

Рисунок 20 – Использование вызовов OpenGL

Одной из проблем вывода графики OpenGL является необходимость изменять параметры матрицы проектирования при изменении размеров окна. В GlWindow можно совместить настройку матрицы проектирования и код, формирующий изображение, в одном методе draw(), благодаря свойству valid() класса GlWindow. Valid() принимает значение 0, если окно только что создано, или если его размеры были изменены. После завершения вызова метода draw() свойство valid() принимает ненулевое значение.

Также у класса GlWindow есть функция resize(), которая вызывается при изменении размеров окна, но переопределение resize() может понадобиться, только если окну GlWindow приходится иметь дело с отличными от OpenGL элементами, например, с дочерними виджетами.

Для включения обработки событий FLTK добавим в программу элемент интерактивности. Пользователь сможет перетаскивать треугольник в окне, «ухватившись» за него мышью. Для этого добавим в класс MyGLWindow метод handle() для реакции на события и несколько вспомогательных полей:

class MyGLWindow : public GlWindow { public:

MyGLWindow(int X, int Y, int W,int H, const char* L=0); int x1, y1, x2, y2, x3, y3, oldX, oldY;

bool moving, isFullScreen; void draw();

int handle(int event);

};

Реализация функции handle(): int MyGLWindow::handle(int event) {

switch(event) { case PUSH:

if (event_key() == 1) {

48

unsigned int pixel[3] = {0,0,0};

glReadPixels(event_x(), h() – event_y(), 1, 1, GL_RGB, GL_UNSIGNED_INT, &pixel);

if ((pixel[0] + pixel[1] + pixel[2]) != 0) { moving = true;

oldX = event_x(); oldY = event_y();

}

}

return 1; case DRAG:

if (moving) {

x1 += (event_x() – oldX)*2;

x2 += (event_x() – oldX)*2;

x3 += (event_x() – oldX)*2;

y1 -= (event_y() – oldY)*2;

y2 -= (event_y() – oldY)*2;

y3 -= (event_y() – oldY)*2; oldX = event_x();

oldY = event_y(); redraw();

}

return 1;

case RELEASE: moving = false; return 1;

case KEY:

switch (event_key()) { case EscapeKey:

destroy(); case 102:

isFullScreen ? fullscreen_off(0, 0, 500, 300) : fullscreen(); isFullScreen = !isFullScreen;

break; default: ;

}

return 1; default:

return GlWindow::handle(event);

}

В функции handle() обрабатываем события мыши PUSH, DRAG и RELEASE. Также обрабатываются события клавиатуры: нажатие на клавишу Esc

49

приводит к завершению работы программы, а кнопка «F» переключает ее между полноэкранным и оконным режимами, для чего используются методы fullscreen() и fullscreen_off(). Для идентификации клавиши «F» используется значение функции event_key(), эта клавиша будет работать независимо от раскладки клавиатуры и состояния CapsLock.

Демонстрация создания 3D-сферы с использованием OpenGL и дополнительного освещения показана в следующем примере, рисунок 21:

#include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/glut.H> #include <FL/gl.h>

#define WIDTH 640 #define HEIGHT 480

void Reshape(int W, int H) {

GLfloat ratio = (float)W / (float)H; glViewport(0, 0, (GLsizei)W, (GLsizei)H); glMatrixMode(GL_PROJECTION); glLoadIdentity();

glOrtho(-1.5*ratio, 1.5*ratio, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

}

void Redraw() {

 

 

 

static int valid = 0;

 

 

 

if (!valid) {

 

 

 

valid = 1;

 

 

 

Reshape(WIDTH, HEIGHT);

 

 

gLfloat mat_ambient[]

= { 1.0, 1.0, 1.0, 1.0 };

// RGBA

gLfloat mat_diffuse[]

= { 1.0, 1.0, 1.0, 1.0 }; // RGBA

gLfloat mat_specular[]

= { 1.0, 1.0, 1.0, 1.0 };

// RGBA

gLfloat light_position[] = { 5.0, 5.0, 0.0, 0.0 };

// XYZ

glClearColor(0.0, 0.0, 0.4, 0.0);

 

 

glShadeModel(GL_SMOOTH);

 

 

glMaterialfv(GL_FRONT, GL_AMBIENT,

mat_ambient);

glMaterialfv(GL_FRONT, GL_DIFFUSE,

mat_diffuse);

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialf(GL_FRONT, GL_SHININESS, 20.0); glLightfv(GL_LIGHT0, GL_POSITION, light_position);

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]