# Προβολέας εικόνων (C)

Κάτι περισσότερο από απλή εφαρμογή Gtk όπως το "Γεια σου κόσμε".
Έργο τεκμηρίωσης GNOME
gnome-doc-list@gnome.org
Johannes Schmid
jhs@gnome.org
Marta Maria Casetti
mmcasetti@gmail.com 2013
Ελληνική μεταφραστική ομάδα GNOME
team@gnome.gr 2012-2015
Δημήτρης Σπίγγος
dmtrs32@gmail.com 2012, 2013
Μαρία Θουκιδίδου
marablack3@gmail.com 2014
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2014, 2015

# Προβολή εικόνων

      Σε αυτό το μάθημα, θα μάθετε:

        Μερικές βασικές έννοιες του προγραμματισμού C/GObject
        Πώς να γράψετε μια εφαρμογή Gtk σε C

# Δημιουργία έργου με το Anjuta

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

Ξεκινήστε το Anjuta και πατήστε αρχείο νέο έργο για να ανοίξετε τον οδηγό του έργου.

Επιλέξτε GTK+ (απλό) από την καρτέλα C, πατήστε συνέχεια, και συμπληρώστε τις λεπτομέρειές σας στις επόμενες λίγες σελίδες. Χρησιμοποιήστε το image-viewer ως όνομα του έργου και του καταλόγου.

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

Πατήστε εφαρμογή και το έργο θα δημιουργηθεί για σας. Ανοίξτε το src/main.c από τις καρτέλες έργο ή αρχείο. Θα πρέπει να δείτε κάποιο κώδικα που ξεκινάει με τις γραμμές:

#include <config.h> #include <gtk/gtk.h>

# Κατασκευάστε τον κώδικα για πρώτη φορά

Η C είναι μια μάλλον περιγραφική γλώσσα, έτσι μην εκπλαγείτε που το αρχείο περιέχει πολύ κώδικα. Ο περισσότερος κώδικας είναι πρότυπο κώδικα. Φορτώνει ένα (κενό) παράθυρο και το εμφανίζει. Περισσότερες λεπτομέρειες υπάρχουν πιο κάτω· προσπεράστε αυτή τη λίστα αν καταλαβαίνετε τα βασικά:

Οι τρεις γραμμές `#include` στην κορυφή περιλαμβάνουν τον `config` (ορίζει χρήσιμη κατασκευή του autoconf), `gtk` (διεπαφή χρήστη) και βιβλιοθήκες `gi18n` (διεθνοποίηση). Συναρτήσεις από αυτές τις βιβλιοθήκες χρησιμοποιούνται στον υπόλοιπο κώδικα.

Η συνάρτηση `create_window` δημιουργεί ένα νέο (άδειο) παράθυρο και συνδέει ένα σήμα για έξοδο της εφαρμογής όταν το παράθυρο κλείνει.

Σύνδεση σημάτων είναι πώς καθορίζετε τι συμβαίνει όταν πατάτε ένα κουμπί, ή όταν συμβεί κάποιο άλλο συμβάν. Εδώ, καλείται η συνάρτηση `destroy` (και τερματίζει την εφαρμογή) όταν κλείνετε το παράθυρο.

Η συνάρτηση `main` τρέχει από προεπιλογή όταν ξεκινάτε μια εφαρμογή C. Καλεί λίγες συναρτήσεις που ρυθμίζουν και έπειτα εκτελούν την εφαρμογή. Η συνάρτηση `gtk_main` ξεκινά τον κύριο βρόχο του GTK, που εκτελεί τη διεπαφή χρήστη και ξεκινά την απάντηση για συμβάντα (όπως κλικ και πατήματα κουμπιών).

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

Αυτός ο κώδικας είναι έτοιμος να χρησιμοποιηθεί, οπότε μπορείτε να τον μεταγλωττίσετε με κλικ κατασκευή κατασκευή έργου (ή πιέζοντας Shift F7).

Πατήστε Execute στο επόμενο παράθυρο που εμφανίζεται για ρύθμιση κατασκευής αποσφαλμάτωσης. Χρειάζεται να το κάνετε αυτό μόνο μια φορά, για την πρώτη κατασκευή.

# Δημιουργία της διεπαφής χρήστη

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

static GtkWidget* create_window (void) { GtkWidget *window; GtkWidget *button; GtkWidget *image; GtkWidget *box;

/* Ρύθμιση της διεπαφής χρήστη */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c");

box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); button = gtk_button_new_with_label (_("Open image")); image = gtk_image_new ();

gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

gtk_container_add (GTK_CONTAINER (window), box);

/* Σήματα σύνδεσης */

/* Εμφάνιση ανοικτού διαλόγου κατά το άνοιγμα αρχείου */ g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);

/* Έξοδος όταν το παράθυρο κλείνει */ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);

return window; }

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

Οι κλήσεις στο `gtk_box_pack_start` προσθέτουν τα δύο γραφικά στοιχεία στο πλαίσιο και ορίζουν τη συμπεριφορά τους. Η εικόνα θα επεκταθεί σε κάθε διαθέσιμο χώρο, ενώ το κουμπί θα είναι απλά τόσο μεγάλο όσο χρειάζεται. Θα παρατηρήσετε ότι δεν ορίζουμε ρητά μεγέθη στα γραφικά στοιχεία. Στο GTK αυτό συνήθως δεν χρειάζεται επειδή είναι πιο απλό να έχετε μια διάταξη που φαίνεται καλή με διαφορετικά μεγέθη παραθύρων. Στη συνέχεια, το πλαίσιο προστίθεται στο παράθυρο.

Χρειαζόμαστε να ορίσουμε τι συμβαίνει όταν ο χρήστης πατά σε ένα πλήκτρο. Το GTK χρησιμοποιεί την έννοια των σημάτων. Όταν το κουμπί πατιέται, ξεκινά το σήμα πατημένο, που μπορούμε να συνδέσουμε με κάποια ενέργεια. Αυτό γίνεται χρησιμοποιώντας τη συνάρτηση `g_signal_connect` που λέει στο GTK να καλέσει τη συνάρτηση `on_open_image` όταν το κουμπί πατιέται και να περάσει την εικόνα ως πρόσθετο όρισμα σε αυτή τη συνάρτηση. Θα ορίσουμε την επανάκληση στην επόμενη ενότητα.

Ο τελευταίος `g_signal_connect()` επιβεβαιώνει ότι η εφαρμογή φεύγει όταν το παράθυρο κλείνει.

Ως τελευταίο βήμα, βεβαιωθείτε να αντικαταστήσετε την κλήση `gtk_widget_show` στη συνάρτηση `main()` από `gtk_widget_show_all()` για να εμφανιστεί το παράθυρο και όλα τα γραφικά στοιχεία που περιέχει.

# Εμφάνιση της εικόνας

Θα ορίσουμε τώρα τον χειριστή σήματος για το σήμα πατημένο ή για το κουμπί που αναφέραμε πριν. Προσθέστε αυτόν τον κώδικα πριν τη μέθοδο `create_window()`.

static void on_open_image (GtkButton* button, gpointer user_data) { GtkWidget *image = GTK_WIDGET (user_data); GtkWidget *toplevel = gtk_widget_get_toplevel (image); GtkFileFilter *filter = gtk_file_filter_new (); GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"), GTK_WINDOW (toplevel), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);

gtk_file_filter_add_pixbuf_formats (filter); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);

switch (gtk_dialog_run (GTK_DIALOG (dialog))) { case GTK_RESPONSE_ACCEPT: { gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gtk_image_set_from_file (GTK_IMAGE (image), filename); break; } default: break; } gtk_widget_destroy (dialog); }

Αυτό είναι λίγο πιο περίπλοκο από όσα έχουμε κάνει μέχρι τώρα, για αυτό θα το χωρίσουμε σε κομμάτια:

Το πρώτο όρισμα του σήματος είναι πάντοτε το γραφικό στοιχείο που έστειλε το σήμα. Μερικές φορές άλλα ορίσματα σχετικά με το σήμα έρχονται μετά από αυτό, αλλά το πατημένο δεν έχει. Επόμενο όρισμα είναι το `user_data` που είναι ένας δείκτης στα δεδομένα που περάσαμε όταν συνδέσαμε το σήμα. Σε αυτήν την περίπτωση είναι το αντικείμενό μας `GtkImage`.

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

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

Οι επόμενες δύο γραμμές περιορίζουν το διάλογο άνοιγμα να εμφανίζει μόνο αρχεία που μπορούν να ανοιχθούν από το GtkImage. Ένα αντικείμενο φίλτρου δημιουργείται πρώτα· έπειτα προσθέτουμε όλα τα είδη των αρχείων που υποστηρίζονται από `GdkPixbuf` (που περιλαμβάνει τις περισσότερες μορφές όπως PNG και JPEG) στο φίλτρο. Τέλος, ορίζουμε αυτό το φίλτρο να είναι το φίλτρο του διαλόγου άνοιγμα.

Ο `gtk_dialog_run` εμφανίζει το διάλογο άνοιγμα. Ο διάλογος θα περιμένει τον χρήστη να διαλέξει μια εικόνα· όταν διαλέξει, ο `gtk_dialog_run` θα επιστρέψει την τιμή `GTK_RESPONSE_ACCEPT` (θα επιστρέψει `GTK_RESPONSE_CANCEL` αν ο χρήστης πατήσει ακύρωση). Η πρόταση `switch` ελέγχει για αυτό.

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

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

# Κατασκευή και εκτέλεση της εφαρμογής

Όλος ο κώδικας πρέπει να είναι έτοιμος τώρα. Κλικ κατασκευή κατασκευή έργου για ανακατασκευή των πάντων και έπειτα τρέξιμο εκτέλεση για έναρξη της εφαρμογής.

Εάν δεν το έχετε ήδη κάνει, επιλέξτε την εφαρμογή Debug/src/image-viewer στον διάλογο που εμφανίζεται. Τελικά, πατήστε τρέξιμο και απολαύστε!

# Υλοποίηση αναφοράς

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

# Επόμενα βήματα

Εδώ είναι κάποιες ιδέες για το πώς μπορείτε να επεκτείνετε αυτή την απλή παρουσίαση:

Βάλτε τον χρήστη να επιλέξει ένα κατάλογο αντί για αρχείο και δώστε ελέγχους να γυρίζουν όλες τις εικόνες σε έναν κατάλογο.

Εφαρμόστε τυχαία φίλτρα και εφέ στην εικόνα όταν αυτή φορτωθεί και επιτρέψτε στον χρήστη να αποθηκεύσει την επεξεργασμένη εικόνα.

Το GEGL παρέχει ισχυρές δυνατότητες επεξεργασίας εικόνας.

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

You can use GIO to handle network file transfers and the like, and GNOME Scan to handle scanning.