# Η σχεδίαση προτύπου/προβολής/ελεγκτή (Python)

Η σχεδίαση προτύπου/προβολής/ελεγκτή
Sebastian Pölsterl
sebp@k-d-w.org 2011
Marta Maria Casetti
mmcasetti@gmail.com 2012

# Η σχεδίαση προτύπου/προβολής/ελεγκτή

# Επισκόπηση

Αμφότερα τα γραφικά συστατικά TreeView και ComboBox κατασκευάζονται στη σχεδίαση πρότυπο/προβολή/ελεγκτής. Το πρότυπο (μια εφαρμογή του `Gtk.TreeModel`, συνήθως `Gtk.TreeStore` ή `Gtk.ListStore`) αποθηκεύει τα δεδομένα· η προβολή (π.χ. `Gtk.TreeView`, `Gtk.ComboBox`, ή `Gtk.ComboBoxText`) δέχεται ειδοποιήσεις αλλαγής και εμφανίζει το περιεχόμενο του προτύπου. Ο ελεγκτής, τελικά, αλλάζει την κατάσταση του προτύπου (μέσα από κάποιες μεθόδους στην εφαρμογή του προτύπου - όπως `append()` ή `remove()`) και ειδοποιεί την προβολή αυτών των αλλαγών (μέσα από σήματα όπως `"changed"`).

# Το πρότυπο

Η κύρια διαφορά μεταξύ των δύο κύριων εφαρμογών του `Gtk.TreeModel` είναι ότι η `Gtk.ListStore` περιέχει απλές γραμμές δεδομένων χωρίς θυγατρικά, ενώ η `Gtk.TreeStore` περιέχει επίσης γραμμές δεδομένων, αλλά κάθε γραμμή μπορεί να έχει θυγατρικές γραμμές (που με τη σειρά τους μπορούν να έχουν θυγατρικές γραμμές κ.ο.κ).

Τα δεδομένα στο πρότυπο μπορούν να ανακτηθούν ή να τροποποιηθούν χρησιμοποιώντας την επανάληψη δένδρου και δείκτη στήλης, ή `Gtk.TreeIter`, ή `Gtk.TreePath`.

Όπως με την ενσωματωμένη λίστα αντικειμένων του Python μπορείτε να χρησιμοποιήσετε `len()` για να πάρετε τον αριθμό των γραμμών και χρησιμοποιήστε τμήματα για ανάκτηση ή ορισμό τιμών. Αλλιώς, η μέθοδος `append()` επιστρέφει ένα στιγμιότυπο `Gtk.TreeIter`, που δείχνει στη θέση της νεοεισαγμένης γραμμής. Μπορείτε επίσης να ανακτήσετε μια `Gtk.TreeIter` καλώντας `get_iter()`.

Καθώς η `Gtk.ListStore` περιέχει μόνο ένα επίπεδο, δηλαδή κόμβους που δεν έχουν οποιουσδήποτε θυγατρικούς κόμβους, μια διαδρομή είναι βασικά ένας δείκτης της γραμμής που θέλετε να προσπελάσετε. Στην περίπτωση της `Gtk.TreeStore`, μια διαδρομή είναι μια λίστα δεικτών ή μιας συμβολοσειράς. Η μορφή συμβολοσειράς είναι μια λίστα αριθμών διαχωριζόμενων με μία άνω-κάτω τελεία. Κάθε αριθμός αναφέρεται στην αντιστάθμιση αυτής της στάθμης. Έτσι, η διαδρομή `"0"` αναφέρεται στον ριζικό κόμβο και η διαδρομή `"2:4"` αναφέρεται στον πέμπτο θυγατρικό του τρίτου κόμβου.

Χρήσιμες μέθοδοι για ένα `Gtk.TreeModel`:

Η `get_iter(path)` επιστρέφει ένα στιγμιότυπο `Gtk.TreeIter` που δείχνει στη `path`. Αυτό αναμένεται να είναι μια λίστα αριθμών διαχωριζόμενων με διπλή τελεία, ή μια πλειάδα. Για παράδειγμα, η συμβολοσειρά `"10:4:0"` είναι ισοδύναμη με την πλειάδα `(10, 4, 0)`, καθώς και οι δυο μπορούν να δημιουργήσουν μια διαδρομή βάθους 3 που να δείχνει στην 11η θυγατρική του ριζικού κόμβου, την 5η θυγατρική της 11ης θυγατρικής και 1η θυγατρική της 5ης θυγατρικής.

Η `iter_next(treeiter)` επιστρέφει ένα στιγμιότυπο `Gtk.TreeIter` που δείχνει τον κόμβο που ακολουθεί την treeiter στο τρέχον επίπεδο ή `None` εάν δεν υπάρχει επόμενη επανάληψη.

Η `iter_has_child(treeiter)` επιστρέφει `True` εάν η `treeiter` έχει θυγατρικά, αλλιώς `False`.

Η `iter_children(treeiter)` επιστρέφει ένα στιγμιότυπο `Gtk.TreeIter` που δείχνει στην πρώτη θυγατρική της `treeiter` ή `None` εάν η `treeiter` δεν έχει θυγατρικές.

Η `get_iter_first()` επιστρέφει ένα στιγμιότυπο `Gtk.TreeIter` που δείχνει στον πρώτο επαναλήπτη στο δένδρο (αε αυτόν στη διαδρομή `"0"`) ή `None` εάν το δένδρο είναι κενό.

Χρήσιμες μέθοδοι για μια `Gtk.ListStore`:

Η `append(row)` προσαρτά μια νέα γραμμή σε αυτή την αποθήκη λίστας, όπου `row` μπορεί να είναι μια λίστα τιμών για κάθε στήλη· η `row` μπορεί επίσης να παραλειφθεί ή `None` και σε αυτήν την περίπτωση μια κενή γραμμή θα προσαρτηθεί. Η μέθοδος επιστρέφει μια `Gtk.TreeIter` που δείχνει στην προσαρτημένη γραμμή.

Η `remove(iter)` αφαιρεί την `iter` από την `Gtk.ListStore` και επιστρέφει `True` εάν η επανάληψη είναι έγκυρη και `False` εάν η επανάληψη δεν είναι. Μετά την αφαίρεση, η `iter` ορίζεται να είναι η επόμενη έγκυρη γραμμή.

Χρήσιμες μέθοδοι για μία `Gtk.TreeStore`:

Η `append(parent, row)` προσαρτά μια νέα γραμμή σε αυτήν την αποθήκη δένδρου· ο `parent` πρέπει να είναι μια έγκυρη Gtk.TreeIter. Εάν ο γονικός δεν είναι `None`, τότε θα προσαρτήσει τη νέα γραμμή μετά την τελευταία θυγατρική του γονικού, αλλιώς θα προσαρτήσει μια γραμμή στο κορυφαίο επίπεδο· η `row` μπορεί να είναι μια λίστα τιμών για κάθε στήλη, ή μπορεί να παραληφθεί ή `None`· στην τελευταία περίπτωση μια κενή γραμμή θα προσαρτηθεί. Η μέθοδος επιστρέφει μια `Gtk.TreeIter` που δείχνει την προσαρτημένη γραμμή.

Η `remove(iter)` αφαιρεί την `iter` από την `Gtk.ListStore` και επιστρέφει `True` εάν η επανάληψη είναι έγκυρη και `False` εάν η επανάληψη δεν είναι. Μετά την αφαίρεση, η `iter` ορίζεται να είναι η επόμενη έγκυρη γραμμή.

# Η προβολή: η περίπτωση TreeView

Μια Treeview δείχνει τη δομή των θυγατρικών και γονικών στοιχείων ως ένα δένδρο. Δείτε για παράδειγμα αυτό το παράδειγμα.

Η `Gtk.TreeViewColumn` χρησιμοποιείται για οργάνωση των κάθετων στηλών.

Χρήσιμες μέθοδοι για μια `Gtk.TreeView`:

Ο `set_model(model)` ορίζει το πρότυπο για αυτήν την προβολή δένδρου. Εάν αυτή η προβολή δένδρου έχει ήδη ένα σύνολο προτύπων, θα το αφαιρέσει πριν τη ρύθμιση του νέου προτύπου. Εάν το πρότυπο είναι `None`, τότε θα αναιρέσει το παλιό πρότυπο.

Η `get_model()` επιστρέφει το πρότυπο αυτής της προβολής δένδρου στο οποίο βασίζεται, `None` εάν το πρότυπο έχει αναιρεθεί.

Η `append_column(column)` προσαρτά `column` στη λίστα των στηλών.

Η `get_selection()` παίρνει την `Gtk.TreeSelection` συσχετισμένη με αυτήν την προβολή δένδρου.

Χρήσιμες μέθοδοι για μια `Gtk.TreeViewColumn`:

Η `add_attribute(renderer, attribute, value)` προσθέτει μια απεικόνιση γνωρίσματος σε αυτήν τη στήλη. Το `attribute` είναι η παράμετρος στον `renderer` για να οριστεί από την `value`

Η `pack_start(renderer, expand)` πακετάρει τον `renderer` στην αρχή αυτής της στήλης. Εάν η `expand` είναι `False`, τότε στον `renderer` δεν κατανέμεται περισσότερος χώρος από όσο χρειάζεται. Οποιοσδήποτε αχρησιμοποίητος χώρος διαιρείται εξίσου μεταξύ των κελιών για τα οποία η επέκταση είναι `True`.

Το `pack_end(renderer, expand)` προσθέτει τον `renderer` στο τέλος αυτής της στήλης. Εάν η `expand` είναι `False`, τότε στον `renderer` δεν κατανέμεται περισσότερος χώρος από όσο χρειάζεται. Οποιοσδήποτε αχρησιμοποίητος χώρος διαιρείται εξίσου μεταξύ των κελιών για τα οποία η `expand` είναι `True`.

`set_sort_column_id(sort_column_id)` sets the column of the model by which this column (of the view) should be sorted. This also makes the column header clickable.

Η `set_sort_indicator(setting)` ορίζει εάν ένα μικρό βέλος εμφανίζεται στην κεφαλίδα της στήλης· η `setting` μπορεί ή να είναι `True` (ο δείκτης προβάλλεται) ή `False`.

Η `set_sort_order(order)` αλλάζει τη σειρά με την οποία η στήλη ταξινομείται· η `order` μπορεί να είναι είτε `Gtk.SortType.ASCENDING` ή `Gtk.SortType.DESCENDING`.

# Η προβολή: η περίπτωση ComboBox

Ένα `Gtk.ComboBox` επιτρέπει την επιλογή ενός στοιχείου από ένα πτυσσόμενο μενού, δείτε αυτό το παράδειγμα. Για μια λίστα κειμενικών επιλογών, μπορεί κάποιος να χρησιμοποιήσει πιο απλό `Gtk.ComboBoxText`. Αμφότερα τα `Gtk.ComboBox` και `Gtk.ComboBoxText` μπορούν να περιέχουν μια εισαγωγή.

Χρήσιμες μέθοδοι για ένα `Gtk.ComboBox`:

Η στατική μέθοδος `new_with_entry()` δημιουργεί ένα νέο κενό `Gtk.ComboBox` με μια εισαγωγή· η στατική μέθοδος `new_with_model(model)` δημιουργεί μια νέα με το αρχικοποιημένο πρότυπο στο `model`· και η στατική μέθοδος `new_with_model_and_entry(model)` είναι ένας συνδυασμός των δύο.

Η `get_active_iter()` επιστρέφει μια `Gtk.TreeIter` που δείχνει στο τρέχον ενεργό στοιχείο. Εάν δεν υπάρχει ενεργό στοιχείο, επιστρέφεται `None`.

Ο `set_model(model)` ορίζει το χρησιμοποιούμενο πρότυπο από αυτό το σύνθετο πλαίσιο για να είναι `model` και θα αναιρέσει ένα προηγούμενο πρότυπο συνόλου (εάν υπάρχει κάποιο). Εάν το `model` είναι `None`, τότε θα αναιρέσει το πρότυπο. Σημειώστε ότι αυτή η συνάρτηση δεν καθαρίζει τους σχεδιαστές.

Ο `set_entry_text_column(text_column)` ορίζει τη στήλη προτύπου την οποία αυτό το σύνθετο πλαίσιο πρέπει να χρησιμοποιήσει για να πάρει συμβολοσειρές από `text_column`. Η στήλη `text_column` σε αυτό το πρότυπο αυτού του σύνθετου πλαισίου πρέπει να είναι του τύπου `str` (αυτό είναι κατάλληλο μόνο εάν αυτό το σύνθετο πλαίσιο δημιουργήθηκε με την ιδιότητα “has-entry” ορισμένη σε αληθή).

Ο `set_wrap_width(width)` ορίζει το πλάτος αναδίπλωσης αυτού του σύνθετου πλαισίου να είναι `width`. Το πλάτος αναδίπλωσης είναι βασικά ο προτιμώμενος αριθμός των στηλών όταν θέλετε το αναδυόμενο να εμφανιστεί σε ένα πλέγμα.

Χρήσιμες μέθοδοι για ένα `Gtk.ComboBoxText`:

Η στατική μέθοδος `new_with_entry()` δημιουργεί ένα νέο κενό `Gtk.ComboBoxText` με μια εγγραφή.

Η `append_text(text)` προσαρτά το `text` στη λίστα των αποθηκευμένων συμβολοσειρών σε αυτό το σύνθετο πλαίσιο.

Η `get_active_text()` επιστρέφει την τρέχουσα ενεργή συμβολοσειρά σε αυτό το σύνθετο πλαίσιο ή `None` εάν δεν επιλέγεται τίποτα. Εάν αυτό το σύνθετο πλαίσιο περιέχει μια εγγραφή, αυτή η συνάρτηση θα επιστρέψει τα περιεχόμενα της (που δεν θα είναι αναγκαστικά ένα στοιχείο από τη λίστα).

# Η προβολή: οι σχεδιαστές κελιού

Η προβολή κάνει χρήση των `Gtk.CellRenderer` των ποικίλων τύπων σχεδίασης των δεδομένων.

Εφαρμογές του `Gtk.CellRenderer` και χρήσιμες μέθοδοι:

`Gtk.CellRendererText` - αποδίδει κείμενο σε ένα κελί

`Gtk.CellRendererToggle` - αποδίδει μια εναλλαγή ή ραδιοπλήκτρο σε ένα κελί. Χρήσιμες μέθοδοι:

`set_active(setting)` - ενεργοποιεί ή απενεργοποιεί έναν αποτυπωτή κελιών

`get_active()` - επιστρέφει εάν ο σχεδιαστής κελιών είναι ενεργός

`set_radio(radio)` - εάν το ράδιο είναι `True`, ο σχεδιαστής κελιών αποδίδει μια εναλλαγή ραδίου (δηλαδή μια εναλλαγή σε μια ομάδα αμοιβαία αποκλειόμενων εναλλαγών)· εάν `False`, αποδίδει μια εναλλαγή ελέγχου (μια αυτόνομη επιλογή τιμής Μπουλ)

`get_radio()` - επιστρέφει εάν αποδίδουμε ραδιοεναλλαγές αντί για πλαίσια ελέγχου.

`Gtk.CellRendererPixbuf` - αποδίδει μια εικόνα σε ένα κελί

`Gtk.CellRendererCombo` - αποδίδει κείμενο σε ένα κελί· αλλά ενώ το `Gtk.CellRendererText` προσφέρει μια απλή εγγραφή για επεξεργασία του κειμένου, το `Gtk.CellRendererCombo` προσφέρει ένα γραφικό συστατικό `Gtk.ComboBox` για επεξεργασία του κειμένου. Μπορεί να χρησιμοποιηθεί με και χωρίς ένα συσχετισμένο γραφικό συστατικό Gtk.Entry, ανάλογα με την τιμή της ιδιότητας “has-entry”.

`Gtk.CellRendererProgress` - αποδίδει μια αριθμητική τιμή ως μια γραμμή προόδου σε ένα κελί· μπορεί να εμφανίσει ένα κείμενο στην κορυφή της γραμμής προόδου

`Gtk.CellRendererSpinner` - αποδίδει μια στρεφόμενη κίνηση σε ένα κελί

`Gtk.CellRendererSpin` - αποδίδει ένα κουμπί στροβιλισμού σε ένα κελί

`Gtk.CellRendererAccel` - αποδίδει έναν επιταχυντή πληκτρολογίου σε ένα κελί

# Ο ελεγκτής: η επιλογή

Οι περισσότερες εφαρμογές θα χρειαστεί να αντιμετωπίσουν μόνο εμφανιζόμενα δεδομένα, αλλά επίσης να δεχθούν συμβάντα εισαγωγής από τους χρήστες. Για να γίνει αυτό, πάρτε απλά μια αναφορά σε ένα αντικείμενο επιλογής και συνδεθείτε στο σήμα `"changed"`.

select = tree.get_selection() select.connect("changed", on_tree_selection_changed)

Έπειτα για να ανακτήσετε δεδομένα για την επιλεγμένη γραμμή:

def on_tree_selection_changed(selection): model, treeiter = selection.get_selected() if treeiter != None: print "You selected", model[treeiter][0]

Χρήσιμες μέθοδοι για μια `Gtk.TreeSelection`:

`set_mode(type)` ορίζει τον τύπο της επιλογής, όπου τύπος είναι ένας από

`Gtk.SelectionMode.NONE` - καμιά επιλογή δεν είναι δυνατή

`Gtk.SelectionMode.SINGLE` - κανένα ή ένα στοιχείο μπορεί να επιλεγεί

`Gtk.SelectionMode.BROWSE` - ακριβώς ένα στοιχείο επιλέγεται. Σε μερικές περιπτώσεις, όπως αρχικά ή κατά τη διάρκεια μιας λειτουργίας αναζήτησης, είναι δυνατό να μην επιλεγεί κανένα στοιχείο. Αυτό που είναι πραγματικά υποχρεωτικό είναι να μην μπορεί να αποεπιλέξει ο χρήστης ένα τρέχον επιλεγμένο στοιχείο εκτός από την επιλογή ενός άλλου στοιχείου.

`Gtk.SelectionMode.MULTIPLE` - οποιοσδήποτε αριθμός στοιχείων μπορεί να επιλεγεί. Το πάτημα εναλλάσσει την κατάσταση ενός στοιχείου. Οποιοσδήποτε αριθμός στοιχείων μπορεί να επιλεγεί. Το πλήκτρο Ctrl μπορεί να χρησιμοποιηθεί για μεγέθυνση της επιλογής και το πλήκτρο Shift για επιλογή μεταξύ εστίασης και του θυγατρικού στο οποίο δείχνει. Μερικά γραφικά συστατικά μπορούν επίσης να επιτρέψουν κλικ-μεταφορά για επιλογή μιας περιοχής στοιχείων.

`get_selected()` επιστρέφει μια πλειάδα `(model, treeiter)`, όπου `model` είναι το τρέχον πρότυπο και `treeiter` ένα `Gtk.TreeIter` που δείχνει στην τρέχουσα επιλεγμένη γραμμή, ή τίποτα εάν δεν επιλεγούν γραμμές. Η μέθοδος δεν δουλεύει εάν η κατάσταση επιλογής οριστεί σε `Gtk.SelectionMode.MULTIPLE`· σε αυτήν την περίπτωση, χρησιμοποιήστε `get_selected_rows()`, που επιστρέφει μια λίστα στιγμιοτύπων `Gtk.TreePath` όλων των επιλεγμένων γραμμών.

# Αναφορές

GtkTreeModel

GtkTreeView

GtkTreeViewColumn

GtkComboBox

GtkCellRenderer

Το μάθημα Python Gtk+ 3 - Γραφικά συστατικά δένδρου και λίστας

Το μάθημα Python Gtk+ 3 - CellRenderers

Το μάθημα Python Gtk+ 3 - ComboBox