Przeglądarka dokumentacji w FLTK

Niniejsza "aplikacja" nie jest w pełni poprawna - korzysta z funkcji system jak i też nie jest w pełni zabezpieczona i nie powinna być stosowana do celów innych niż nauka FLTK :)

Wiele aplikacji dodaje do /usr/share/doc swoje katalogi z plikami informacyjnymi, changelogami itd. By je przeglądać (pliki *gz) korzystamy w konsoli z polecenia zcat. Naszym celem będzie napisanie aplikacji z graficznym interfejsem FLTK która będzie potrafiła:
- W oknie 1 - lista katalogów w /usr/share/doc
- W oknie 2 pojawiać się będzie zawartość katalogu zaznaczonego w oknie 1
- W oknie 3 pojawi się zawartość pliku wybranego w oknie 2.
fltk_docsapp
Najtrudniejszym chyba etapem było wyszukanie odpowiedniego widgeta. File_Browser nie nadaje się gdyż nie można zaznaczać wpisów. Widget Fl_Select_Browser spełnia nasze oczekiwania - może wczytać plik i każdy wiersz uczynić wierszem w oknie a na każdy wiersz można kliknąć co może wywołać funkcję callback. Oto pełen kod aplikacji (kompilacja: fltk-config --compile nazwa.cpp):
#include <stdlib.h>
#include <string.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Browser.H>
#include <FL/Fl_Select_Browser.H>

using namespace std;
// Pobierz nazwę katalogu na którą kliknięto w oknie 1, dołącz resztę ścieżki i wylistuj do pliku
// i wczytaj go do okna 2
void folder_callback( Fl_Widget* o, void*)
	{
	Fl_Select_Browser* b=(Fl_Select_Browser*)o; 
	Fl_Select_Browser* second=(Fl_Select_Browser*) b -> parent() -> child(2);

	char folder_in_doc[50];
	strcpy(folder_in_doc,"ls /usr/share/doc/");
	strcat(folder_in_doc,b->text(b->value()));
	strcat(folder_in_doc,"/ > /tmp/foo");
	system(folder_in_doc);
	second->load("/tmp/foo");
	b->redraw();
	}
 
// Stwórz pełną ścieżkę do klikniętego pliku i zcat do pliku który wczytujemy
void file_callback( Fl_Widget* o, void*)
	{
	Fl_Select_Browser* b=(Fl_Select_Browser*)o;
	Fl_Select_Browser* second=(Fl_Select_Browser*) b -> parent() -> child(1);
	Fl_Browser* the_end=(Fl_Browser*) b -> parent() -> child(0);
	
	char full_patch[100];
	strcpy(full_patch,"zcat /usr/share/doc/");
	strcat(full_patch,second->text(second->value()));
	strcat(full_patch,"/");
	strcat(full_patch,b->text(b->value()));
	strcat(full_patch," > /tmp/foo");
	system(full_patch);
	
	the_end->load("/tmp/foo");
	b->redraw();
  }

int main ()
 {
 //Główne okno
 Fl_Window *window = new Fl_Window(700,550);
 window->label("Docs viewer");
 // Okno 3, niekoniecznie FL_Browser, ale zaleta - może wczytywać pliki
 Fl_Browser *the_end_widget = new Fl_Browser(300,5,390,530); // child 0
 the_end_widget->textsize(10);
 
 // Pierwsze okno z listą katalogów
 Fl_Select_Browser *folder_list = new Fl_Select_Browser(5,5,280,350); // child 1
 // To jest bardzo brzydkie!
 system("ls /usr/share/doc/ > /tmp/foo");
 // I wczytujemy
 folder_list->load("/tmp/foo");
 folder_list->textsize(10);
 folder_list->callback( folder_callback );
 
 // Okno 2 na pliki
 Fl_Select_Browser *file_list = new Fl_Select_Browser(5,360,280,170); // child 2
 file_list->textsize(10);
 file_list->callback( file_callback );
 
 window->end();
 window->show();
 return Fl::run();
 }
Pisanie takiej aplikacji zaczynamy od stworzenia interfejsu - wyborze widgetów i rozmieszczenia ich w oknie. Gdy to mamy zaczynamy wg. kolejności:
- Załadowanie w funkcji main do okna 1 listy katalogów
- Stworzenie funkcji callback dla tego okna
- Stworzenie funkcji callback dla okna 2
Funkcje callback są bardzo podobne, różnią się praktycznie wykonywanym poleceniem.
void folder_callback( Fl_Widget* o, void*)
 {
 Fl_Select_Browser* b=(Fl_Select_Browser*)o; // to jest okno 1 (okno wywołujące callbacka)
 Fl_Select_Browser* second=(Fl_Select_Browser*) b -> parent() -> child(2); // to jest okno-dziecko o nr. 2
Jest to początek funkcji callback dla 1 okna z listą katalogów. Drugie okno jest tego samego typu co potencjalnie może utrudnić sytuację... Dostęp do okna, które wywołało callback jest prosty co prezentuje pierwszy wiersz z wywołaniem Fl_Select_Browser. Natomiast by dostać się do innego widgeta również go wywołujemy i podajemy jego numer "dziecka" b -> parent() -> child(NUMER);. Dzieci-widgety numerowane są od zera począwszy od tego, który w kodzie funkcji (main) wystąpi wcześniej. Funkcja file_callback ma dostęp do trzech widgetów:
Fl_Select_Browser* b=(Fl_Select_Browser*)o;
 Fl_Select_Browser* second=(Fl_Select_Browser*) b -> parent() -> child(1);
 Fl_Browser* the_end=(Fl_Browser*) b -> parent() -> child(0);
Funkcje wywołuje dziecko nr. 2 (okno z listą plików) i dostęp uzyskujemy w pierwszym wierszu. Drugi wiersz daje dostęp do okna z listą katalogów a trzeci do trzeciego widgetu przeznaczonego na treść pliku.

Notka: operując na "nieznanych" widgetach warto skorzystać z iostream i cout << coś zwracane przez widget << "bla" << endl; by sprawdzać czy callback jest wywoływany i co dany widget zwraca :)
RkBlog

C/C++ i Java, 14 July 2008

Comment article
Comment article RkBlog main page Search RSS Contact