29 marca 2018

Python – aplikacja okienkowa commander ver.1

Witam, tym wpisem zaczynam omawianie nowego programu w pythonie. Całość oczywiście zostanie znów oparta o kivy, a co za tym idzie ? będziemy tworzyć aplikacje okienkową, działającą pod różnymi systemami operacyjnymi. Będzie to najbardziej uboga wersja Total Commandera, lub po prostu exploratora plików.

Zaczynajmy,

na początku importujemy kivy i wszystkie niezbędne nam klasy:

import kivy

import os

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.uix.listview import ListItemButton, ListView
from kivy.adapters.listadapter import ListAdapter

Następnie stworzymy główną klasę programu, ja nazwałem ją po prostu „Program”. Wewnątrz umieściłem rzeczy których w poprzednich programach brakowało. Ustawiłem tytuł okna głównego programu, oraz ikonę:

class Program(App):
    title = 'Folder list'
    icon = 'icon.png'

    def build(self):
        return Folder()


Program().run()

Nad linią Program().run() możemy ustawić flagę fullscreen na false, lecz to sprawa gustu, możemy również wręcz odwrotnie wpisać tam „1”, wtedy fullscreen przyjmie true:

Config.set('graphics', 'fullscreen', '0')

Klasa Program zwraca nam klasę Folder, więc pewnie wszyscy się domyślają, że i taką zaraz napiszemy.

Jako parametr do klasy Folder dodamy GridLayout ponieważ ten zaimportowaliśmy i tego właśnie layoutu użyjemy. Ustawiamy również wewnątrz dwie globalne zmienne, elements równy 0 oraz folder równy ścieżce głównej programu, dla Linuksa równy „/” dla Windowsa „C:\\”. Poniżej całości funkcja „__init__”, podaję kod:

elements = 0
folder = "/"

def __init__(self, **kwargs):
    kwargs['cols'] = 2
    super(Folder, self).__init__(**kwargs)

    self.show_list()

W kodzie powyżej znalazło się wywołanie metody „show_list” wewnątrz klasy „Folder”. Dokładnie, „show_list” pokaże nam listę folderów oraz plików z ścieżki która będzie wartością w zmiennej „folder”.

Zerknijmy więc do „show_list()”:

def show_list(self):
    self.clear_widgets()
    self.elements = self.folder.split("/")

    if len(self.elements)<=1:
        list = []
    else:
        list = ['[..]']

    list = list + os.listdir(self.folder)

    listA = ListAdapter(
        data=list,
        selection_mode='single',
        allow_empty_selection=False,
        cls=ListItemButton)

    lista = ListView(adapter=listA, size_hint=(.2, 1.0))

    listA.bind(on_selection_change=self.callback)

    self.add_widget(lista)

Zaczynając od początku funkcji. „clear_widgets” Usuwa wszystkie widgety z widoku aplikacji. Następnie do globalnej zmiennej „elements” dodajemy wynik funkcji split na zmiennej globalnej folder. Dzięki temu w „elements” otrzymamy ładną tablicę z wszystkimi elementami (nazwami katalogów) w naszej ścieżce.

Warunek if sprawdza, jeśli ilość elementów w tablicy „elements” jest mniejszy lub równy 1, nie doda do zmiennej lokalnej „list” niczego, tylko ją zadeklaruje. W przeciwnym przypadku, stworzy tablicę list i doda jej pierwszy rekord równy „[..]”. Po co ten warunek ? Jeśli ilość elementów w tablicy „elements” jest większa niż 1, oznacza to, że nie jesteśmy w katalogu głównym dysku, tylko gdzieś wewnątrz, mamy wtedy możliwość wejścia na poziom wyżej. Przykładowo wyjść z ścieżki „C://katX/katY” do „C://katX”.

Tworzymy obiekt klasy „ListAdapter”, pamiętaj aby jako parametr podać tablicę „list”.

Kolejnym krokiem jest stworzenie obiektu klasy „ListView”, dzięki tej operacji otrzymamy gotowy widget do wyświetlenia, gdy podamy go jako parametr do funkcji add_widget, otrzymamy ładną listę katalogów. Obsługę kliknięcia elementu listy wywołujemy za pomocą funkcji bind, tam jako parametr podajemy nazwę metody która obsłuży u nas kliknięcie na element listy. W naszym przypadku obsługę kliknięcia obsługuje metoda „callback”.

Funkcja „callback”, gdyby nie fakt, że umożliwia nam wejście poziom wyżej w strukturze folderów, była by niebywale krótka, mogła by wyglądać tak:

def callback(self, obj):
    self.folder = self.folder + '/' + obj.selection[0].text

    self.show_list()

Przyznam szczerze, w momencie programowania, tak ta funkcja właśnie wyglądała. Kivy bowiem przekazał jako parametr do funkcji „callback” obiekt z którego pobrałem tekst klikniętego elementu na liście przez użytkownika programu, dodałem go do zmiennej globalnej folder i wywołałem funkcje „show_list()”. Program miał nową strukturę folderów do wyświetlenia, wyczyścił widgety, stworzył nowy i wyświetlił, wsio… ale nie do końca.
Co w sytuacji, gdy użytkownik nie wejdzie głębiej w strukturę folderów, lecz wejdzie poziom wyżej ?

def callback(self, obj):
        if obj.selection[0].text == '[..]':
            folder = ''

            i = 0
            for element in self.elements[0:-1]:
                if(i==0):
                    folder = folder + element
                else:
                    folder = folder + '/' + element
                i = i+1

            self.folder = folder

        else:
            self.folder = self.folder + '/' + obj.selection[0].text

        self.show_list()

Jeśli kliknięty element na liście jest równy „[..]” sprawdzimy wszystkie elementy w tablicy „elements” lecz zignorować musimy ostatni element listy, ponieważ z niego wychodzimy. Następnie za pomocą warunków tworzymy od nowa cała ścieżkę do folderu.

W tym wpisie to wszystko, następny będzie dotyczył wersji 2 programu, w którym postaram się opisać jak można rozbudować obecny program.