Taryn Fox
jewelfox@fursona.net 2012
Μάθετε πώς να τακτοποιήσετε στοιχεία διεπαφής χρήστη όπως εικόνες και ετικέτες.
Ελληνική μεταφραστική ομάδα GNOME
team@gnome.gr 2012-2015
Δημήτρης Σπίγγος
dmtrs32@gmail.com 2012, 2013
Μαρία Θουκιδίδου
marablack3@gmail.com 2014
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2014, 2015

# 2. Καλώς ήλθατε στο πλέγμα

        Αυτό το μάθημα θα σας δείξει πώς να δημιουργήσετε βασικά γραφικά στοιχεία, ή μέρη της διεπαφής χρήστη του GNOME, όπως εικόνες και ετικέτες. Θα μάθετε έπειτα πώς να τα τακτοποιήσετε όλα σε ένα πλέγμα, που σας επιτρέπει να βάλετε τα γραφικά στοιχεία ακριβώς όπου τα θέλετε.
        Έχετε δει το πρώτο μάθημα σε αυτή τη σειρά ήδη; Θα θέλετε να το κάνετε πριν να συνεχίσετε.

# Πηγαίνοντας εγγενώς

Στο τελευταίο μάθημα, δημιουργήσαμε βασικά ένα πλαίσιο παραθύρου GNOME για μια εφαρμογή ιστού. Ο συγκεκριμένος κώδικας GNOME που χρειαζόμαστε να μάθουμε περιστρέφεται γύρω από την τοποθέτηση της WebView -- το γραφικό στοιχείο που περιέχει την εφαρμογή μας -- σε ένα ApplicationWindow και την εμφάνιση του. Η ίδια η εφαρμογή γράφτηκε σε HTML και JavaScript, ακριβώς όπως οι περισσότερες σελίδες στον ιστό.

Αυτήν τη φορά, πρόκειται να χρησιμοποιήσουμε μόνο τα εγγενή γραφικά στοιχεία του GNOME. Ένα γραφικό στοιχείο είναι μόνο ένα πράγμα, όπως ένα πλαίσιο ελέγχου ή εικόνα και το GNOME έχει μια πλατιά ποικιλία για επιλογή. Τα λέμε "εγγενή" γραφικά στοιχεία για να τα διακρίνουμε από πράγματα όπως το κουμπί και η κεφαλίδα στην εφαρμογή ιστού που γράψαμε. Αντί να χρησιμοποιήσουμε κώδικα ιστού, αυτά πρόκειται να είναι 100% GNOME, χρησιμοποιώντας Gtk+.

Το Gtk+ σημαίνει "GIMP Toolkit". Είναι σαν μια εργαλειοθήκη γραφικών στοιχείων που μπορείτε να προσπελάσετε, ενώ δομείτε τις εφαρμογές σας. Γράφτηκε αρχικά για το GIMP, που είναι ένας επεξεργαστής εικόνας ελεύθερου λογισμικού.

# Εγκατάσταση της εφαρμογής μας

Πριν να ψάξουμε οποιαδήποτε γραφικά στοιχεία από την εργαλειοθήκη Gtk+, χρειαζόμαστε πρώτα να γράψουμε το βασικό κώδικα στερεότυπου που η εφαρμογή μας απαιτεί.

#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0'; const Gtk = imports.gi.Gtk;

This part always goes at the start of your code. Depending on what you'll be doing with it, you may want to declare more imports here. What we're writing today is pretty basic, so these are all we need; Gtk for the widgets, using the stable '3.0' API.

Μιλώντας για:

class WelcomeToTheGrid { // Create the application itself constructor() { this.application = new Gtk.Application();

// Connect 'activate' and 'startup' signals to the callback functions this.application.connect('activate', this._onActivate.bind(this)); this.application.connect('startup', this._onStartup.bind(this)); }

// Callback function for 'activate' signal presents windows when active _onActivate() { this._window.present(); }

// Callback function for 'startup' signal builds the UI _onStartup() { this._buildUI (); }

Αυτή είναι η αρχή της ίδιας της εφαρμογής και η συνάρτηση _init που τη δημιουργεί. Λέει στη _buildUI να δημιουργήσει μια ApplicationWindow, που πρόκειται να καλέσει το _window και λέει στο παράθυρό μας να εμφανίζει τον εαυτό του όποτε απαιτείται.

Αυτό το μέρος, πάλι, είναι αρκετά αντιγραφή και επικόλληση, αλλά θέλετε πάντα να δώσετε στην εφαρμογή σας ένα μοναδικό όνομα.

// Build the application's UI _buildUI() {

// Create the application window this._window = new Gtk.ApplicationWindow({ application: this.application, window_position: Gtk.WindowPosition.CENTER, border_width: 10, title: "Welcome to the Grid"});

Τελικά, ξεκινάμε τη συνάρτηση _buildUI δημιουργώντας ένα νέο ApplicationWindow. Ορίζουμε ότι πηγαίνει με αυτήν την εφαρμογή, που θα πρέπει να εμφανιστεί στο κέντρο της οθόνης και εκεί θα πρέπει να είναι τουλάχιστον 10 εικονοστοιχεία μεταξύ της εξωτερικής άκρης και όλων των γραφικών στοιχείων της. Επίσης της δίνουμε έναν τίτλο, που θα εμφανιστεί στην κορυφή του παραθύρου.

# Φτάνοντας στην εργαλειοθήκη Gtk+

Ποια γραφικά στοιχεία πρέπει να χρησιμοποιήσουμε; Λοιπόν, ας πούμε ότι θέλουμε να γράψουμε μια εφαρμογή που φαίνεται σαν αυτή:

Πρόκειται να χρειαστούμε, τουλάχιστον, μια εικόνα και μια ετικέτα κειμένου να πάει μαζί της. Ας αρχίσουμε με την εικόνα:

// Create an image this._image = new Gtk.Image ({ file: "gnome-image.png" });

Μπορείτε να κατεβάσετε το χρησιμοποιούμενο αρχείο εικόνας σε αυτό το παράδειγμα εδώ. Βεβαιωθείτε να το βάλετε στον ίδιο κατάλογο με τον κώδικα που γράφετε.

// Create a label this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!" });

Αυτός ο κώδικας προσθέτει κάτω από την ετικέτα. Μπορείτε να δείτε πώς δημιουργούμε γραφικά στοιχεία, εδώ· καθένα είναι μέρος του Gtk και μπορούμε να του δώσουμε ιδιότητες που προσαρμόζουν τη συμπεριφορά του. Σε αυτήν την περίπτωση, ορίζουμε την ιδιότητα αρχείο της εικόνας να είναι το όνομα αρχείου της εικόνας που θέλουμε και η ιδιότητα ετικέτα της ετικέτας να είναι η πρόταση που θέλουμε κάτω από την εικόνα.

Ναι, ακούγεται περιττό για μια ετικέτα να έχει μια ιδιότητα ετικέτας, αλλά δεν ισχύει. Άλλα γραφικά στοιχεία που περιέχουν κείμενο έχουν μια ιδιότητα ετικέτας, έτσι είναι συνεπές για το γραφικό στοιχείο ετικέτας να έχει επίσης μία.

Δεν μπορούμε απλά να προσθέσουμε αυτά τα γραφικά στοιχεία στο παράθυρό μας στη σειρά, όμως, με τον ίδιο τρόπο που τα στοιχεία HTML εμφανίζονται στη σειρά που τα γράφετε. Αυτό συμβαίνει επειδή ένα ApplicationWindow μπορεί να περιέχει μόνο ένα γραφικό στοιχείο.

Πώς το παρακάμπτουμε; Κάνοντας αυτό το γραφικό στοιχείο έναν αποδέκτη γραφικού στοιχείου, που μπορεί να κρατά περισσότερα από ένα γραφικό στοιχείο και να τα οργανώσουμε μέσα του. Ιδού: το πλέγμα.

// Create the Grid this._grid = new Gtk.Grid ();

Δεν του δίνουμε ακόμα ιδιότητες. Αυτές θα έρθουν αργότερα, καθώς μαθαίνουμε πώς να χρησιμοποιούμε τις δυνάμεις του πλέγματος. Πρώτα, ας προσαρτήσουμε την εικόνα και την ετικέτα που κάναμε στο πλέγμα μας.

// Attach the image and label to the grid this._grid.attach (this._image, 0, 0, 1, 1); this._grid.attach (this._label, 0, 1, 1, 1);

Αυτός ο κώδικας φαίνεται πολύ περίπλοκος, αλλά δεν είναι. Να τι σημαίνουν αυτοί οι αριθμοί:

Ο πρώτος αριθμός είναι σε ποια θέση από αριστερά προς τα δεξιά θα τοποθετηθούν πράγματα, αρχίζοντας από 0. Κάθε γραφικό στοιχείο που χρησιμοποιεί ένα 0 εδώ πηγαίνει όλο αριστερά.

Ο δεύτερος αριθμός είναι σε ποια θέση από πάνω προς τα κάτω θα μπει το δεδομένο γραφικό στοιχείο, ξεκινώντας από 0. Η ετικέτα πηγαίνει κάτω από την εικόνα, έτσι δίνουμε στην εικόνα ένα 0 και στην ετικέτα ένα 1 εδώ.

Ο τρίτος και ο τέταρτος αριθμός είναι πόσες στήλες και γραμμές πρέπει να καταλάβει ένα γραφικό στοιχείο. Θα δούμε πώς αυτά δουλεύουν σε ένα λεπτό.

// Add the grid to the window this._window.add (this._grid);

// Show the window and all child widgets this._window.show_all(); }

};

// Run the application let app = new WelcomeToTheGrid (); app.application.run (ARGV);

Τώρα που έχουμε δημιουργήσει το πλέγμα και προσαρτήσαμε σε αυτό όλα τα γραφικά στοιχεία μας, το προσθέτουμε στο παράθυρο και λέμε στο παράθυρο να εμφανίσει τον εαυτόν του, όπως το τελευταίο μέρος της συνάρτησης _buildUI. Όπως πάντα, για να τελειώσουμε δημιουργούμε ένα νέο στιγμιότυπο της κλάσης της εφαρμογής και του λέμε να εκτελεστεί.

Αποθηκεύστε την εφαρμογή σας ως welcome_to_the_grid.js. Έπειτα, για να εκτελέσετε την εφαρμογή σας ανοίξτε απλά έναν τερματικό, πηγαίνετε στον κατάλογο όπου η εφαρμογή σας είναι και πληκτρολογήστε

     $ gjs welcome_to_the_grid.js

Να! Αλλά περιμένετε. Αυτό δεν φαίνεται σωστό. Γιατί στριμώχνεται η ετικέτα δίπλα στην εικόνα έτσι; Αυτό δεν φαίνεται ωραίο και δυσκολεύει την ανάγνωση. Τι μπορούμε να κάνουμε για αυτό;

# Μικρορύθμιση του πλέγματος

Ένα πράγμα που μπορούμε να κάνουμε, είναι να δώσουμε στην ετικέτα μια ιδιότητα margin_top όταν τη δημιουργούμε. Αυτό δουλεύει όπως η ρύθμιση ενός περιθωρίου για ένα στοιχείο HTML χρησιμοποιώντας ενσωματωμένη μορφή CSS.

// Create a label this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!", margin_top: 20 });

Φυσικά, εάν κάνουμε αυτό τότε εάν αντικαταστήσουμε την ετικέτα με κάτι άλλο -- ή προσθέτοντας σε ένα άλλο γραφικό στοιχείο -- τότε πρέπει να επαναλάβουμε το margin_top σε αυτό ξανά. Αλλιώς τελειώνουμε μα κάτι σαν αυτό:

Μπορούμε να δώσουμε στην εικόνα μια ιδιότητα margin_bottom, αλλά δεν θα δουλέψει όταν η νέα ετικέτα είναι σε μια ξεχωριστή στήλη. Έτσι ας δοκιμάσουμε αυτό:

// Create the Grid this._grid = new Gtk.Grid ({ row_spacing: 20 });

Αυτό το κάνει έτσι ώστε να υπάρχουν πάντα 20 εικονοστοιχεία χώρου μεταξύ κάθε οριζόντιας γραμμής.

Ναι, μπορείτε επίσης να ορίσετε την ιδιότητα column_spacing σε ένα πλέγμα, ή τις ιδιότητες margin_left και margin_right σε κάθε γραφικό στοιχείο. Δοκιμάστε τες εάν θέλετε!

# Προσθήκη περισσότερων γραφικών στοιχείων

Εάν θέλουμε να προσθέσουμε μια δεύτερη ετικέτα, πώς θα μπορούσαμε να κάνουμε έτσι ώστε να φαίνεται πράγματι ότι ανήκε εκεί; Ένας τρόπος είναι να κεντράρετε την εικόνα στην κορυφή, έτσι ώστε να είναι πάνω και από τις δύο ετικέτες αντί για τη μία μόνο στα αριστερά. Εδώ είναι που αυτοί οι άλλοι αριθμοί στη μέθοδο προσάρτησης του πλέγματος έρχονται:

// Create a second label this._labelTwo = new Gtk.Label ({ label: "The cake is a pie." });

// Attach the image and labels to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._label, 0, 1, 1, 1); this._grid.attach (this._labelTwo, 1, 1, 1, 1);

Μετά τη δημιουργία της δεύτερης ετικέτας, την προσκολλάμε στο πλέγμα στα δεξιά της πρώτης ετικέτας. Να θυμάστε, οι πρώτοι δύο αριθμοί υπολογίζουν στήλες και γραμμές από αριστερά προς τα δεξιά και από πάνω προς τα κάτω, ξεκινώντας από 0. Έτσι εάν η πρώτη ετικέτα είναι στη στήλη 0 και στη γραμμή 1, μπορούμε να βάλουμε τη δεύτερη στη στήλη 1 και στη γραμμή 1 για να τη βάλουμε στα δεξιά της πρώτης ετικέτας.

Σημειώστε τον αριθμό 2 στη δήλωση προσάρτησης για την εικόνα. Αυτό κάνει εδώ. Αυτός ο αριθμός είναι πόσες στήλες καλύπτει η εικόνα, θυμάστε; Έτσι όταν το βάζουμε μαζί, πάρουμε κάτι σαν αυτό:

Υπάρχουν δύο πράγματα που θα πρέπει να σημειώσετε, εδώ.

Ο ορισμός της εικόνας να καλύψει δύο στήλες δεν τεντώνει την ίδια την εικόνα οριζόντια. Αντίθετα, τεντώνει το αόρατο πλαίσιο που πάρθηκε από το γραφικό στοιχείο της εικόνας για να γεμίσει και τις δύο στήλες, έπειτα βάζει την εικόνα στο κέντρο αυτού του πλαισίου.

Αν και έχουμε ορίσει τη row_spacing του πλέγματος και τις ιδιότητες border_width του ApplicationWindow, δεν έχουμε ορίσει ακόμα οτιδήποτε βάζει ένα περίγραμμα μεταξύ των δύο ετικετών. Ήταν ξεχωριστές νωρίτερα όταν η εικόνα ήταν μόνο μια στήλη, αλλά τώρα που καλύπτει και τις δύο το GNOME δεν βλέπει λόγο να τις κρατήσει ξέχωρα.

Υπάρχουν τουλάχιστον τρεις τρόποι που μπορούμε να παρακάμψουμε την τελευταία. Πρώτα, μπορούμε να ορίσουμε ένα margin_left ή margin_right σε μία από τις ετικέτες:

Δεύτερο, μπορούμε να ορίσουμε την ιδιότητα πλέγμετος column_homogenous σε αληθή.

// Create the Grid this._grid = new Gtk.Grid ({ column_homogeneous: true, row_spacing: 20 });

Αυτό το κάνει να μοιάζει σαν αυτό:

Και τρίτο, μπορούμε να ορίσουμε την ιδιότητα column_spacing του πλέγματος, με τον ίδιο τρόπο που ορίζουμε το row_spacing του.

// Create the Grid this._grid = new Gtk.Grid ({ column_spacing: 20, row_spacing: 20 });

Αυτό το κάνει να μοιάζει σαν αυτό:

# Χρήση εικόνων παρακαταθήκης

Το GNOME έχει πολλές εικόνες παρακαταθήκης ήδη, που μπορούμε να χρησιμοποιήσουμε εάν δεν θέλουμε να δημιουργήσουμε τις δικές μας ή εάν θέλουμε ένα γενικά αναγνωρισμένο εικονίδιο. Να πώς δημιουργούμε μια εικόνα παρακαταθήκης, συγκρινόμενη με το πώς δημιουργούμε μια κανονική:

// Create an image this._image = new Gtk.Image ({ file: "gnome-image.png" });

// Create a second image using a stock icon this._icon = new Gtk.Image ({ stock: 'gtk-about' });

Μετά από αυτό, το προσκολλάμε στο πλέγμα στα αριστερά της πρώτης ετικέτας. (Δεν χρησιμοποιούμε τη δεύτερη για αυτό το παράδειγμα.)

// Attach the images and label to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._icon, 0, 1, 1, 1); this._grid.attach (this._label, 1, 1, 1, 1);

Αυτά μας δίνει αυτό, όταν το εκτελούμε:

Αυτό είναι πώς το εικονίδιο παρακαταθήκης "About" μοιάζει. Μπορείτε να δείτε μια λίστα όλων των στοιχείων παρακαταθήκης ξεκινώντας με το gtk-about στο τεκμηρίωση ανάπτυξης του GNOME. Γράφτηκε για προγραμματιστές C, αλλά δεν χρειάζεστε να ξέρετε C για να το χρησιμοποιήσετε· απλά κοιτάξτε το μέρος σε εισαγωγικά, όπως "gtk-about" και αντιγράψτε αυτό το μέρος για να χρησιμοποιήσετε το εικονίδιο δίπλα του.

Βάζουμε μονά εισαγωγικά γύρω από το 'gtk-about' εδώ επειδή, αντίθετα με τις συμβολοσειρές κειμένου που έχουν διπλά εισαγωγικά γύρω τους, αυτό το μέρος δεν θα χρειαστεί να μεταφραστεί ποτέ σε άλλη γλώσσα. Πράγματι, εάν μεταφραζότανε θα έσπαγε το εικονίδιο, επειδή το όνομά του είναι ακόμα "gtk-about" ανεξάρτητα από την ομιλούμενη γλώσσα.

# Ποιο είναι το επόμενο;

Πριν πάμε στο επόμενο μάθημα, ας δοκιμάσουμε κάτι λίγο διαφορετικό:

// Create a button this._button = new Gtk.Button ({ label: "Welcome to GNOME, too!"});

// Attach the images and button to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._icon, 0, 1, 1, 1); this._grid.attach (this._button, 1, 1, 1, 1);

Ακριβώς, μετατρέπουμε την ετικέτα σε ένα κουμπί αλλάζοντας απλά το όνομα! Εάν εκτελείτε την εφαρμογή και πατήστε πάνω της, όμως, θα δείτε ότι δεν κάνει τίποτα. Πώς κάνουμε το κουμπί μας να κάνει κάτι; Αυτό θα μάθουμε στο επόμενο μάθημά μας.

Εάν θέλετε, μπορείτε ελεύθερα να ξοδέψετε κάποιο χρόνο πειραματιζόμενοι με πλέγματα, ετικέτες και εικόνες συμπεριλαμβανομένων των εικόνων παρακαταθήκης.

Ένα κόλπο που μπορείτε να χρησιμοποιήσετε για να κάνετε πιο σύνθετες διατάξεις είναι η ένθεση πλεγμάτων το ένα μέσα στο άλλο. Αυτό σας επιτρέπει να ομαδοποιήσετε μαζί σχετικά γραφικά στοιχεία και να τα αναδιατάξετε εύκολα. Ρίξτε μια ματιά στο δείγμα κώδικα RadioButton εάν θα θέλατε να δείτε πώς γίνεται αυτό.

# Δείγμα πλήρους κώδικα

#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0'; const Gtk = imports.gi.Gtk;

class WelcomeToTheGrid {

// Create the application itself constructor() { this.application = new Gtk.Application();

// Connect 'activate' and 'startup' signals to the callback functions this.application.connect('activate', this._onActivate.bind(this)); this.application.connect('startup', this._onStartup.bind(this)); }

// Callback function for 'activate' signal presents windows when active _onActivate() { this._window.present(); }

// Callback function for 'startup' signal builds the UI _onStartup() { this._buildUI (); }

// Build the application's UI _buildUI() {

// Create the application window this._window = new Gtk.ApplicationWindow({ application: this.application, window_position: Gtk.WindowPosition.CENTER, border_width: 10, title: "Welcome to the Grid"});

// Create the Grid this._grid = new Gtk.Grid ({ // column_homogeneous: true, // column_spacing: 20, row_spacing: 20 });

// Create an image this._image = new Gtk.Image ({ file: "gnome-image.png" });

// Create a second image using a stock icon this._icon = new Gtk.Image ({ stock: 'gtk-about' });

// Create a label this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!", /* margin_top: 20 */ });

/* Create a second label this._labelTwo = new Gtk.Label ({ label: "The cake is a pie." }); */

/* Create a button this._button = new Gtk.Button ({ label: "Welcome to GNOME, too!"}); */

// Attach the images and button to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._icon, 0, 1, 1, 1); this._grid.attach (this._label, 1, 1, 1, 1);

// this._grid.attach (this._label, 0, 1, 1, 1); // this._grid.attach (this._labelTwo, 1, 1, 1, 1);

// this._grid.attach (this._button, 1, 1, 1, 1);

// Add the grid to the window this._window.add (this._grid);

// Show the window and all child widgets this._window.show_all(); }

};

// Run the application let app = new WelcomeToTheGrid (); app.application.run (ARGV);