[Go Quickly!] Programowanie – open i save dialog

Jest to czwarty artykuł z serii Go Quickly! autorstwa Grzegorza – dziękujemy.

Zaczynamy pisanie naszego edytora. Otwieramy katalog naszego projektu i uruchamiamy quickly edit – pozwoli nam to edytować wszystkie ważne pliki. O zmianie standardowego edytora pisałem wcześniej.

Zignorować możemy na razie pliki z rozszerzeniem .page – służą one do budowania pomocy w programie. Otworzą się także pliki z przedrostkiem _test, służą do testów jednostkowych. Najbardziej interesujące nas pliki mają w sobie nazwę naszego programu, a także plik __init__.py, będący plikiem startowym programu.

Wszystkie te pliki znajdują się w katalogu pod nazwą naszej aplikacji, który mieści się w katalogu naszej aplikacji. Powinno się tam dodawać wszystkie pliki zawierające kod programu (dla jego poprawnego działania).

Kod głównego okna programu znajduje się w pliku [nazwa_aplikacji]Window.py. Mamy w nim zdefiniowaną klasę okna i metodę jego inicjalizacji.

Aby nasz program mógł odwoływać się do elementów zbudowanych za pomocą Glade’a potrzebujemy pobrać ich obiekty z obiektu bulider’a naszej formatki:

self.new = self.builder.get_object("new")

new to nazwa jaką nadałem wcześniej przyciskowi w projekcie Glade’a. Pobieramy resztę elementów formatki po ich nazwach, czyli widok tekstowy, przyciski, status bar i pasek narzędziowy.

Quickly i PyGTK cz. 4 odsd IMG1

Po uruchomieniu naszego programu pole tekstowe jest aktywne, lecz nie edytujemy żadnego pliku. Przydałoby się je wyłączyć, podobnie jak z przyciskiem save:

self.save.set_sensitive(False)
self.textview1.set_sensitive(False)

Jak można zauważyć nasz tooolbar nie ma wyróżniającego się koloru (szczególnie przy ciemnych motywach). Jest jednak na to sposób:

toolbarContext = self.toolbar1.get_style_context()
toolbarContext.add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)

Powyższa instrukcja ustawia styl wybranego przez nas toolbara na styl główny.

Po uruchomieniu naszej aplikacji czeka nas jednak niespodzianka, czyli niezbyt ładne marginesy. Usuwamy je ustawiając za pomocą Glade’a odstępy elementu skrzynki (vbox1) na 0.

Quickly i PyGTK cz. 4 odsd IMG2

Aby móc edytować plik tekstowy naszym programem, musi on wiedzieć gdzie się on znajduje. Bardzo przydatnym elementem GTK+ w takiej sytuacji są DialogBox'y. Nam potrzebne są save dialog i open dialog, które posłużą do zapisywania nowych plików i otwierania starych.
Na początek deklarujemy w klasie okna zmienną np: __plik; gdzie będzie zapisana ścieżka aktualnie edytowanego pliku. Okno dialog’u tworzymy za pomocą metody:

dialog = Gtk.FileChooserDialog("Nazwa_okna", self, Gtk.FileChooserAction.SAVE,
                              (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

Metoda ta przyjmuje 4 parametry: nazwę okna, referencje do okna nadrzędnego, akcję, przyciski i ich zachowanie.

Możemy także dodać nazwę pliku oraz domyślny katalog w przypadku zapisu. Uruchamiamy nasz DialogBox za pomocą:

response = dialog.run()

Bardzo ważna jest wartość zwracana przez tą metodę. Znajduję się w niej flaga przycisku użytego w DialogBox. Na podstawie tego prostym, if podejmujemy dalsze działania. Musimy jeszcze pamiętać o usunięciu okna po wciśnięciu przycisku:

dialog.destroy()

Quickly i PyGTK cz. 4 odsd IMG3

Teraz pozostało nam przypisanie akcji do przycisków. Służą do tego sygnały, które Quickly generuje dla nas automatycznie. Każdy sygnał możemy indywidualnie nazwać, jeśli zachodzi taka potrzeba. Otwieramy Glade’a, wybieramy widget i w oknie właściwości wybieramy sygnały.

Domyślny wzór nazw sygnałów przedstawia się następująco on_(nazwa obiektu w projekcie)_(nazwa sygnału). Należy pamiętać że wszystkie znaki „-” w nazwach sygnału zstępujemy „_” podczas tworzenia metody w klasie okna.

def on_new_clicked (self, widget):
	#operacje

Każdy sygnał ma inną ilość argumentów którą możemy znaleźć w dokumentacji GTK+.
Tworzymy, więc odpowiednie metody dla naszych sygnałów i implementujemy w nich nasze DialogBox’y.

Pozostało nam tylko odczytać lub zapisać wartość pliku umieszczoną lub wczytaną z pola edycji.
Dla uproszczenie warto stworzyć metody zapisu i odczytu. Odczytujemy plik i cały tekst umieszczamy w naszym widoku tekstowym. Operacje na widoku tekstowym są trochę skomplikowane, ponieważ musimy operować na buforze widoku tekstowego. Aby wstawić tekst wymagane jest także zmianę kodowania na UTF-8:

text = text.encode('utf-8')
self.textview1.get_buffer().set_text(text, len(text))
Teraz odblokowujemy możliwość zapisu oraz widok tekstowy:
self.save.set_sensitive(True)
self.textview1.set_sensitive(True)

Wpisując do działającego programu dużo tekstu widzimy, że tekst powiększa okno lub przy maksymalizacji okna przewija się, ale braknie suwaków. Rozwiązanie polega na dodaniu przewijania okna. Otwieramy Glade’a, wycinamy widok tekstowy, dodajemy w jego miejsce widget o nazwie „Przewijane okno„. Na koniec wklejmy widok teksty do obszaru przewijania.

Quickly i PyGTK cz. 4 odsd IMG4

Przy tworzeniu nowego pliku musimy tylko pamiętać o: wyczyszczeniu pola tekstowego, nazwy pliku, odblokowaniu zapisu oraz widoku tekstowego.
Przy metodzie od zapisu musimy pamiętać o sprawdzeniu czy edytujemy nowy plik, jeśli tak to posługujemy się DialogBox’em do wybrania ścieżki zapisu. Jeżeli wcześniej otworzyliśmy plik, zapisujemy go na podstawie ścieżki w naszej zmiennej __plik.

Odczyt tekstu z bufora widoku tekstu, także nie jest łatwy:

b,e = self.textview1.get_buffer().get_bounds()
text = self.textview1.get_buffer().get_text(b,e,False).decode('utf-8')

Ponieważ musimy pobrać górną i dolą granice bufora, a następnie wyciągnąć tekst z niego oraz odkodować z UTF-8.
Wszystko działa pięknie, tylko, aby wiedzieć jaki plik aktualnie edytujemy, potrzebna nam będzie etykieta w statusbar. Umieszczenie ścieżki pliku jest banalne:

self.label2.set_text(self.__plik)

Quickly i PyGTK cz. 4 odsd IMG5

Ostatnią rzeczą, aby nasza aplikacja sprawnie działała, jest podpięcie akcji przycisków na pasku narzędziowym do menu kontekstowego np:

def on_mnu_new_activate(self, widget):
self.on_new_clicked(widget)

Podstawową funkcjonalność mamy zapewnioną. Hura!

Gotową aplikację można pobrać klikając tutaj.
Jeżeli powyższy artykuł nie rozwiązał lub rozwiązał częściowo Twój problem, dodaj swój komentarz opisujący, w którym miejscu napotkałeś trudności.
Mile widziane komentarze z uwagami lub informacjami o rozwiązaniu problemu.