519 γραμμές
		
	
	
	
		
			46 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			519 γραμμές
		
	
	
	
		
			46 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								+++
							 | 
						|||
| 
								 | 
							
								title = 'Προγραμματισμός με GTK(\...)'
							 | 
						|||
| 
								 | 
							
								date = '1999-10-01T00:00:00Z'
							 | 
						|||
| 
								 | 
							
								description = ''
							 | 
						|||
| 
								 | 
							
								author = 'Παπαδογιαννάκης Βαγγέλης για το Magaz ( magaz.hellug.gr(http://magaz.hellug.gr) )'
							 | 
						|||
| 
								 | 
							
								issue = ['Magaz 20']
							 | 
						|||
| 
								 | 
							
								issue_weight = 4
							 | 
						|||
| 
								 | 
							
								+++
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								*GTK\... Gimp ToolΚit. Αυτό το πρόγραμμα τα άρχισε όλα. Από τη στιγμή που βγήκε το gimp, δημιουργήθηκαν ένα σωρό εφαρμογές που χρησιμοποιούν τις βιβλιοθήκες
							 | 
						|||
| 
								 | 
							
								απεικόνισής του, οι οποίες σημειωτέον είναι από τις καλύτερες που υπάρχουν. Πάνω σε αυτή βασίζεται ολόκληρο το gnome, και είναι από τα προτιμούμενα της REDHAT
							 | 
						|||
| 
								 | 
							
								και άλλων φυσικά διανομών. \`Ελα όμως που ο προγραμματισμός σε GTK είναι σχετικά δύσκολος\... Μη μασάτε, δεν είναι και τόσο όσο νομίζετε\... Είναι
							 | 
						|||
| 
								 | 
							
								ευκολούτσικος, και δεν θα σας πάρει πάνω από 10 λεπτά διάβασμα για να καταφέρετε να στήσετε το πρώτο σας προγραμματάκι σε GTK. Πολλά από τα σημεία αυτού του
							 | 
						|||
| 
								 | 
							
								άρθρου, έχουν βασιστεί στα tutorials της gtk. όπως αυτά έρχονται με το gtk-devel.rpm πακέτο. Για περισσότερες πληροφορίες σε σημεία του κειμένου, παρακαλώ ρίξτε
							 | 
						|||
| 
								 | 
							
								τους μια ματιά.*
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**1. Περί αυτού του άρθρου. (the boring stuff)**
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**2. Που θα βρείτε το GTK**
							 | 
						|||
| 
								 | 
							
								-------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**3. Προϋποθέσεις**
							 | 
						|||
| 
								 | 
							
								-----------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**4. Βασικές έννοιες προγραμματισμού σε gtk**
							 | 
						|||
| 
								 | 
							
								-------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   [4.1 Βασικά χαρακτηριστικά](#ss4.1)
							 | 
						|||
| 
								 | 
							
								-   [4.2 widgets, signals, κ.λπ.](#ss4.2)
							 | 
						|||
| 
								 | 
							
								-   [4.3 Γεια σας μάγκες! Το πρώτο πρόγραμμα σε gtk](#ss4.3)
							 | 
						|||
| 
								 | 
							
								-   [4.4 Εξήγηση του Hello Magez](#ss4.4)
							 | 
						|||
| 
								 | 
							
								-   [4.5 Πως θα το τρέξετε.](#ss4.5)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**5. Tοποθέτηση των widgets**
							 | 
						|||
| 
								 | 
							
								---------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   [5.1 Boxes, ή αλλιώς κουτιά :)](#ss5.1)
							 | 
						|||
| 
								 | 
							
								-   [5.2 Tοποθέτηση των widgets, partII (λέγε με tables)](#ss5.2)
							 | 
						|||
| 
								 | 
							
								-   [5.3 Η συνέχεια](#ss5.3)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [1. Περί αυτού του άρθρου. (the boring stuff)]{#s1}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Αυτό το άρθρο, δεν έχει σκοπό να σας μάθει gtk, αλλά να σας εξοικειώσει με τις δυσκολότερες έννοιες στο toolkit αυτό, ώστε να αρχίσετε μόνοι σας να
							 | 
						|||
| 
								 | 
							
								προγραμματίζετε. Σε καμία περίπτωση δεν είμαι υπεύθυνος εγώ ειδικά και το magaz γενικότερα αν κάνετε μπάχαλο τον υπολογιστή σας. Στο δικό μου δουλεύουν όλα μια
							 | 
						|||
| 
								 | 
							
								χαρά, και δεν έπαθε τίποτα από όσα γράφω σε αυτό το άρθρο.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								\`Εχω προγραμματίσει να ολοκληρωθεί σε τρεις συνέχειες. Πολύ πιθανόν και 4. Αυτό δεν σημαίνει ότι είμαι υποχρεωμένος να συνεχίσω και με τα άλλα, αλλά δεσμεύομαι
							 | 
						|||
| 
								 | 
							
								να προσπαθήσω. Και αυτό το λεω, γιατί στο παρελθόν είχα κάνει κάτι αντίστοιχό που δεν ολοκληρώθηκε (bash, enlightenment) αλλά είχα δικαιολογία και για τα δύο.
							 | 
						|||
| 
								 | 
							
								Μπορεί κάτι να συμβεί και να μη συνεχιστεί. Σε μια τέτοια περίπτωση, παρακαλώ όποιος έχει την όρεξη να συνεχίσει.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Επίσης, δεν υπάρχει ούτε ΜΙΑ πιθανότητα να μην έχω κάνει εκφραστικά -και ίσως νοηματικά- λαθάκια. Είναι η δυσκολία που υπάρχει στη μετάφραση αυτού που θέλουμε
							 | 
						|||
| 
								 | 
							
								να εκφράσουμε, καθώς και η μεταφορά του σε λέξεις. \`Οσοι από εσάς προγραμματίζουν, ή έχουν τέλος πάντων μια εξοικείωση με την αγγλική ορολογία, καταλαβαίνετε
							 | 
						|||
| 
								 | 
							
								τι θέλω να πω. Να είσαστε λοιπόν ελαστικοί στην κρίση σας.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								\`Οσοι από εσάς ασχολούνται με gtk και βρουν τίποτα ανακρίβειες (πράγμα πολύ πιθανό γιατί ναι μεν προγραμματίζω σε gtk αλλά δεν χρησιμοποιώ όλα όσα εξηγώ σε
							 | 
						|||
| 
								 | 
							
								αυτό το άρθρο), παρακαλώ να μου στείλετε με [mail στο papas\@hellug.gr](mailto:papas@hellug.gr) τις παρατηρήσεις σας, και θα προσπαθήσω να διορθώσω τα λάθη σε
							 | 
						|||
| 
								 | 
							
								ένα από τα επόμενα άρθρα.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Καλό διάβασμα, και happy programming!
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [2. Που θα βρείτε το GTK]{#s2}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Κατά πάσα πιθανότητα, το έχετε ήδη εγκατεστημένο στον υπολογιστή σας. Για όσους από εσάς αρνούνται να εγκαταστήσουν το GTK, επιμένοντας σε υποκατάστατα του
							 | 
						|||
| 
								 | 
							
								τύπου QT - καλά, μη βαράτε :) - σας παραπέμπω στη διεύθυνση <http://www.gtk.org> να το κατεβάσετε σε ότι μορφή θέλετε. Αν θέλετε **rpm**, μην ξεχάσετε να πάρετε
							 | 
						|||
| 
								 | 
							
								και το **devel** πακέτο, γιατί αυτό ουσιαστικά θα μας χρειαστεί ώστε να κάνουμε τα προγράμματά μας να τρέχουν.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [3. Προϋποθέσεις]{#s3}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Δεν υπάρχουν ουσιαστικές προϋποθέσεις. Απλά θα πρέπει να ξέρετε τα βασικά του προγραμματισμού, λίγη C, και να έχετε πολύ όρεξη. Επίσης, θα πρέπει να έχετε στο
							 | 
						|||
| 
								 | 
							
								PATH σας το script **gtk-config**, για να αποφύγουμε να βρίσκουμε λεπτομέρειες που είναι διαφορετικές για κάθε μηχάνημα. Περισσότερες πληροφορίες θα βρείτε στο
							 | 
						|||
| 
								 | 
							
								**man page** του gtk-config (`man gtk-config`)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4. Βασικές έννοιες προγραμματισμού σε gtk]{#s4}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Ας ξεκινήσουμε με τις αρχικές έννοιες, που στη συνέχεια θα μας βοηθήσουν στην κατανόηση του προγραμματισμού σε gtk.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4.1 Βασικά χαρακτηριστικά]{#ss4.1}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Κάθε πρόγραμμα που θα φτιάχνουμε, πρέπει να περιέχει, μεταξύ άλλων, και τα εξής:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Πρώτα από όλα, πρέπει να περιέχει τις βιβλιοθήκες που θα κάνουμε import. Για την gtk, αυτή είναι ή `gtk.h`, που βρίσκεται μέσα στο directory **gtk**
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #include <gtk/gtk.h>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Φυσικά, όπως όλα τα προγράμματα, περιέχει την πολύ γνωστή `main`. Αυτή είναι η πρώτη συνάρτηση που καλείται, και πρέπει οπωσδήποτε να υπάρχει, είναι *int*,
							 | 
						|||
| 
								 | 
							
								γιατί πρέπει να επιστρέφει μια τιμή τύπου int στο *shell* (το γνωστό σε όλους μας **exit status**).
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    int main(int argc, char *argv[]){
							 | 
						|||
| 
								 | 
							
								      ...
							 | 
						|||
| 
								 | 
							
								      ...
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Μέσα σε αυτήν τώρα, πρέπει να υπάρχει μια άλλη, η `gtk_init` που καλείται από όλα τα προγράμματα που είναι γραμμένα σε gtk για την αρχικοποίηση.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    gtk_init(&argc, &argv);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Επίσης, σε κάποιο σημείο πρέπει να καλείται η `gtk_main` η οποία δεν είναι τίποτα άλλο από την συνάρτηση η οποία περιμένει για ενέργειες του χρήστη, όπως το
							 | 
						|||
| 
								 | 
							
								πάτημα ενός κουμπιού στο ποντίκι, ή το πάτημα ενός πλήκτρου.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    gtk_main();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Φυσικά δεν πρέπει να ξεχάσουμε την τιμή που θα επιστρέφει το όλο πρόγραμμά μας (είναι είπαμε *int*), και αυτό γίνεται με την γνωστή `return`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return(0);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Αυτά είναι τα βασικά και απαραίτητα που πρέπει να περιέχει ένα πρόγραμμα σε gtk. Φυσικά, για να γραφεί ένα ολοκληρωμένο και λειτουργικό πρόγραμμα απαιτούνται
							 | 
						|||
| 
								 | 
							
								πολύ περισσότερα που θα δούμε στη συνέχεια, γιαύτο μη βιάζεστε\... Συνεχίστε το διάβασμα για την βουτά στα βαθιά\... )))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4.2 widgets, signals, κ.λπ.]{#ss4.2}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								First things first\...
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### Widgets
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Πριν αρχίσουμε, να δούμε μερικά πράγματα, όπως πχ. τι είναι το gtk\_widget που θα συναντάμε κατ κόρον. Είναι μια δομή, που μέσω αυτής μπορούμε να έχουμε
							 | 
						|||
| 
								 | 
							
								πρόσβαση σε όλα τα widgets της gtk. Αυτά μπορεί να είναι **buttons, radio buttons, check buttons, lists, combo boxes, boxes, toolbars**, και γενικότερα
							 | 
						|||
| 
								 | 
							
								οτιδήποτε βλέπετε στα παραθυράκια των προγραμμάτων gtk.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### signals
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Ο έλεγχος σε ένα πρόγραμμα **gtk** δίδεται χρησιμοποιώντας τα **signals**. Ας σας εξηγήσω όμως με ένα παράδειγμα.\
							 | 
						|||
| 
								 | 
							
								Για να συνδέσουμε ένα συμβάν με μια λειτουργία, μπορούμε να χρησιμοποιούμε μια συνάρτηση όπως η `gtk_signal_connect`.\
							 | 
						|||
| 
								 | 
							
								Αυτή, συντάσσεται όπως βλέπουμε παρακάτω, και επιστρέφει μια τιμή τύπου **gint** (Μια μορφή ακεραίου που χρησιμοποιεί η gtk).
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								         gint gtk_signal_connect(GtkObject *object, gchar name, GtkSignalFunc func, gpointer func_data);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Παρακάτω δίνονται οι απαραίτητες εξηγήσεις για να καταλάβετε τι κάνει το κάθε όρισμα:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   `GtkObject *object`\
							 | 
						|||
| 
								 | 
							
								    Το widget που θα παρακολουθούμε για signal
							 | 
						|||
| 
								 | 
							
								-   `gchar name`\
							 | 
						|||
| 
								 | 
							
								    Το signal για το οποίο παρακολουθούμε
							 | 
						|||
| 
								 | 
							
								-   `GtkSignalFunc func`\
							 | 
						|||
| 
								 | 
							
								    Η συνάρτηση που θα κληθεί όταν γίνει trap στο σινιάλο που παρακολουθούμε
							 | 
						|||
| 
								 | 
							
								-   `gpointer func_data`\
							 | 
						|||
| 
								 | 
							
								    Το όρισμα που θα περάσει στην καλούμενη συνάρτηση (μπορεί να είναι πχ, το πλήκτρο που πατήθηκε)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Το τρίτο όρισμα, είναι μια συνάρτηση που δέχεται σαν ορίσματα ένα δείκτη (pointer) στο widget από το οποίο προκλήθηκε το signal, και ένα δείκτη που αναφέρεται
							 | 
						|||
| 
								 | 
							
								στο τέταρτο όρισμα της καλούσας συνάρτησης (το func\_data δηλαδή). ώστε να ξέρει τι να κάνει με τα δεδομένα που της εστάλησαν (ΜΠΕΡΔΕΥΤΗΚΑΤΕ;)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4.3 Γεια σας μάγκες! Το πρώτο πρόγραμμα σε gtk]{#ss4.3}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Επειδή ήδη αρχίσαμε να κολυμπάμε σε βαθύτερα νερά, ας φτιάξουμε ένα μικρό προγραμματάκι, και ας το εξηγήσουμε στη συνέχεια. Κάντε copy-paste, σε ένα αρχείο το
							 | 
						|||
| 
								 | 
							
								παρακάτω:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #include <gtk/gtk.h>
							 | 
						|||
| 
								 | 
							
								    void hello(GtkWidget *widget, gpointer data){
							 | 
						|||
| 
								 | 
							
								        g_print("Hello Magez!");
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    gint del_eve(GtkWidget *widget, GdkEvent *event, gpointer data){
							 | 
						|||
| 
								 | 
							
								        g_print("close pressed\n");
							 | 
						|||
| 
								 | 
							
								        return(TRUE);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void dest(GtkWidget *widget, gpointer data){
							 | 
						|||
| 
								 | 
							
								        gtk_main_quit();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    int main(int argc, char *argv[]){
							 | 
						|||
| 
								 | 
							
								        GtkWidget *window, *button;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_init(&argc, &argv);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(del_eve), NULL);         
							 | 
						|||
| 
								 | 
							
								        gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(dest), NULL);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_container_set_border_width(GTK_CONTAINER(window), 10);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        button = gtk_button_new_with_label("Hello Magez");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(hello), NULL);
							 | 
						|||
| 
								 | 
							
								        gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_container_add(GTK_CONTAINER(window), button);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_widget_show(button);
							 | 
						|||
| 
								 | 
							
								        gtk_widget_show(window);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        gtk_main();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return(0);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Ονομάστε το αρχείο HelloMagez.c και αποθηκεύστε το κάπου που έχετε δικαιώματα (πχ. στο home directory σας). Παρακάτω θα δούμε πως μπορούμε να δημιουργήσουμε το
							 | 
						|||
| 
								 | 
							
								εκτελέσιμο αρχείο.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4.4 Εξήγηση του Hello Magez]{#ss4.4}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Ας δούμε τώρα πως δουλεύει. Θα εξηγούμε το πρόγραμμα με μικρά βήματα. Αλλά ας μην αρχίσουμε από την αρχή, πάμε κατευθείαν στην main.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`GtkWidget *window, *button;`**\
							 | 
						|||
| 
								 | 
							
								    Εδώ ορίζουμε ότι θα χρησιμοποιήσουμε δύο widgets, με ονόματα `window` και `button`
							 | 
						|||
| 
								 | 
							
								-   **`gtk_init(&argc, &argv);`**\
							 | 
						|||
| 
								 | 
							
								    Η γνωστή **gtk\_init**. Την αναφέραμε προηγουμένως.
							 | 
						|||
| 
								 | 
							
								-   **`window =                                 gtk_window_new(GTK_WINDOW_TOPLEVEL);`**\
							 | 
						|||
| 
								 | 
							
								    Ορισμός στο widget **window** ενός νέου παραθύρου τύπου **`GTK_WINDOW_TOPLEVEL`**, δηλαδή κανονικού παραθύρου προγράμματος.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_signal_connect(GTK_OBJECT(window),                                 "delete_event", GTK_SIGNAL_FUNC(del_eve),                                 NULL);`**\
							 | 
						|||
| 
								 | 
							
								    Εδώ αρχίζουν τα δύσκολα. Μη φοβηθείτε όμως, θα τα εξηγήσουμε όλα. Αυτό που κάνουμε, είναι να συνδέσουμε το συμβάν `delete_event` με την συνάρτηση `del_eve`.
							 | 
						|||
| 
								 | 
							
								    To `delete_event` το στέλνει ο window manager που χρησιμοποιούμε όταν πατήσουμε το **close**, ή αντίστοιχα το κουμπί **close** στην **bar** του
							 | 
						|||
| 
								 | 
							
								    προγράμματος. Γιατί το παγιδεύουμε αυτό; Μα γιατί ίσως να θέλουμε να κάνουμε κάποιες εργασίες πριν να κλείσουμε το παράθυρο, πχ. να αποθηκεύσουμε ένα αρχείο
							 | 
						|||
| 
								 | 
							
								    ρυθμίσεων, ή να εμφανίσουμε ένα μήνυμα του τύπου \`\`Είστε σίγουρος;\'\'\
							 | 
						|||
| 
								 | 
							
								    To `GTK_OBJECT` και το `GTK_SIGNAL_FUNC` είναι ουσιαστικά μακροεντολές, που ελέγχουν αν είναι σωστές οι παράμετροι που περνάμε στην `gtk_signal_connect` και
							 | 
						|||
| 
								 | 
							
								    (σύμφωνα με μερικούς-μερικούς) βοηθάει να είναι ο κώδικας πιο ευανάγνωστος και πιο κατανοητός.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_signal_connect(GTK_OBJECT(window),                                 "destroy", GTK_SIGNAL_FUNC(dest), NULL);`**\
							 | 
						|||
| 
								 | 
							
								    \`Aλλη μια σύνδεση. Σε αυτή συνδέουμε το συμβάν `destroy` με τη συνάρτηση `dest`. Το συμβάν `destroy` συμβαίνει όταν δίνουμε στο `delete_event` την τιμή
							 | 
						|||
| 
								 | 
							
								    FALSE, ή όταν καλούμε το `gtk_widget_destroy()` που είναι μια συνάρτηση στην οποία περνάμε σαν παράμετρο το όνομα του παραθύρου που θέλουμε να καταστρέψουμε
							 | 
						|||
| 
								 | 
							
								    (κλείσουμε). Με αυτό τον τρόπο, με μια συνάρτηση, ελέγχουμε και τις δύο περιπτώσεις.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_container_set_border_width(GTK_CONTAINER(window),                                 10);`**\
							 | 
						|||
| 
								 | 
							
								    Αυτή η εντολή, απλά θέτει μια ιδιότητα για ένα αντικείμενο. Συγκεκριμένα, την ιδιότητα *border* στο widget `window`, που είναι ο χώρος γύρω από το παράθυρο
							 | 
						|||
| 
								 | 
							
								    που μένει ανεκμετάλλευτος και δεν μπορεί να χρησιμοποιηθεί από άλλα widgets. Αυτό το κάνουμε για αισθητικούς λόγους.\
							 | 
						|||
| 
								 | 
							
								    Το `GTK_CONTAINER` είναι και αυτό μια μακροεντολή, για type casting, όπως τα `GTK_OBJECT` και `GTK_SIGNAL_FUNC`.
							 | 
						|||
| 
								 | 
							
								-   **`button = gtk_button_new_with_label("Hello                                 Magez");`**\
							 | 
						|||
| 
								 | 
							
								    Συνάρτηση για τη δημιουργία ενός κουμπιού που γράφει \"Hello Magez\". Φυσικά, κουμπιά μπορούν να δημιουργηθούν και αλλιώς, χωρίς να είμαστε αναγκασμένοι να
							 | 
						|||
| 
								 | 
							
								    τους δώσουμε ένα κείμενο, σε περίπτωση πχ. που το κείμενο θα εξαρτάται από κάποιες μεταβλητές, ή θα πρέπει να αλλάξει μετά από λίγο.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_signal_connect(GTK_OBJECT(button),                                 "clicked", GTK_SIGNAL_FUNC(hello),                                 NULL);`**\
							 | 
						|||
| 
								 | 
							
								    Συνδέουμε το click στο κουμπί, με τη συνάρτηση `hello`. Αυτό είναι πολύ απλό, και εύκολο στην κατανόηση.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_signal_connect(GTK_OBJECT(button),                                 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),                                 GTK_OBJECT(window));`**\
							 | 
						|||
| 
								 | 
							
								    Να και κάτι καινούριο. Με αυτή την εντολή, παρατηρούμε ότι μπορούμε να συνδέσουμε πολλές συναρτήσεις με ένα event (στην περίπτωση αυτή με το click του
							 | 
						|||
| 
								 | 
							
								    ποντικιού στο κουμπί `button`. Αυτό που θα συμβεί είναι ότι πρώτα θα καλέσουμε τη συνάρτηση `hello` και αμέσως μετά τη συνάρτηση `gtk_widget_destroy` που
							 | 
						|||
| 
								 | 
							
								    είναι μια συνάρτηση που \`\`καταστρέφει\'\' το widget που της δίνεται σαν όρισμα, στη συγκεκριμένη περίπτωση το `window`, που είναι το παράθυρο του
							 | 
						|||
| 
								 | 
							
								    προγράμματός μας.\
							 | 
						|||
| 
								 | 
							
								    Θα παρατηρήσατε ότι εδώ χρησιμοποιείται η `gtk_signal_connect_object` αντί της `gtk_signal_connect`. Αυτό συμβαίνει γιατί πρέπει να περάσουμε σαν όρισμα το
							 | 
						|||
| 
								 | 
							
								    widget που πρέπει να καταστραφεί. Περισσότερα για τα signals αργότερα.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_container_add(GTK_CONTAINER(window),                                 button);`**\
							 | 
						|||
| 
								 | 
							
								    Κι άλλα καινούρια! η `gtk_container_add` είναι μια συνάρτηση που προσθέτει ένα widget σε ένα container. Εδώ, widget=`button` και container=`window`.\
							 | 
						|||
| 
								 | 
							
								    Σημειώστε ότι ένα `gtk_container` μπορεί να περιέχει μόνο ένα widget. Υπάρχουν όμως άλλα widgets, που πάνω τους μπορούν να φιλοξενούν πολλά άλλα widgets.
							 | 
						|||
| 
								 | 
							
								    Αυτό, στην ενότητα των widgets θα αναλυθεί πολύ καλύτερα. Προς το παρών αρκεστείτε σε αυτό, και τυχόν απορίες σας θα λυθούν παρακάτω.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_widget_show(button);`**\
							 | 
						|||
| 
								 | 
							
								    Αυτή η συνάρτηση εμφανίζει το widget που δέχεται σαν όρισμα. Παρατηρείστε ότι τα widgets, δεν εμφανίζονται μόνα τους. Δεν φτάνει δηλαδή η συνάρτηση
							 | 
						|||
| 
								 | 
							
								    `gtk_container_add` για να εμφανιστεί. Πρέπει πρώτα να προστεθούν όλα, και μετά να εμφανιστούν. Αυτό, μας προστατεύει από συμπεριφορές του τύπου να γίνονται
							 | 
						|||
| 
								 | 
							
								    όλα render στην οθόνη ένα-ένα το οποίο οπτικά είναι πολύ άσχημο, πιστέψτε με. Εμφανίζουμε λοιπόν με την συγκεκριμένη εντολή το κουμπάκι.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_widget_show(window);`**\
							 | 
						|||
| 
								 | 
							
								    \`Οπως και το παραπάνω, μόνο που εδώ εμφανίζουμε το παράθυρο.
							 | 
						|||
| 
								 | 
							
								-   **`gtk_main();`**\
							 | 
						|||
| 
								 | 
							
								    Περνάμε τον έλεγχο στην `gtk_main` όπως περιγράψαμε προηγουμένως.
							 | 
						|||
| 
								 | 
							
								-   **`retutn(0);`**\
							 | 
						|||
| 
								 | 
							
								    Είναι το **exit status** του προγράμματός μας. Θα μπορούσαμε με κάποιο έλεγχο να είχαμε διαφορετικό **exit status**, ανάλογα με το αν το πρόγραμμα απέτυχε,
							 | 
						|||
| 
								 | 
							
								    αν το πρόγραμμα δεν ολοκληρώθηκε, κ.λπ.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Και ας ρίξουμε μια γρήγορη ματιά στις συναρτήσεις που περιέχει το πρόγραμμα. Αν και είναι πολύ εύκολες στην κατανόηση, υπάρχουν κάνα-δυο σημεία που χρειάζονται
							 | 
						|||
| 
								 | 
							
								εξήγηση.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`void hello(GtkWidget *widget, gpointer                                 data)`**\
							 | 
						|||
| 
								 | 
							
								    \`Οπως βλέπουμε, είναι μια συνάρτηση που απλά καλείται όταν πατήσει ο χρήστης το πλήκτρο, και το μόνο που κάνει είναι να τυπώνει **Hello Magez** και να
							 | 
						|||
| 
								 | 
							
								    προσθέτει μια νέα γραμμή.
							 | 
						|||
| 
								 | 
							
								-   **`gint del_eve(GtkWidget *widget, GdkEvent                                 *event, gpointer data)`**\
							 | 
						|||
| 
								 | 
							
								    Η συνάρτηση που καλείται όταν πατηθεί το κουμπί που τερματίζει το πρόγραμμα. Επιστρέφει τιμή ακεραίου, και όπως βλέπουμε (στο συγκεκριμένο παράδειγμα
							 | 
						|||
| 
								 | 
							
								    τουλάχιστον) επιστρέφει TRUE. Αυτός είναι και ο λόγος που δεν έχουμε έξοδο από το πρόγραμμα όταν -θεωρητικά- το κλείνουμε με το κουμπί κλεισίματος. Αν η
							 | 
						|||
| 
								 | 
							
								    τιμή που επιστρέφει αλλαχθεί σε FALSE, τότε θα έχουμε έξοδο από το πρόγραμμα (δοκιμάστε το). Αυτό συμβαίνει, γιατί η συνάρτηση που καλείται από την
							 | 
						|||
| 
								 | 
							
								    `delete_event` εξ ορισμού από τo gtk επιστρέφει μια τιμή που αν είναι FALSE, καλεί το event `destroy` (θυμηθείτε ότι το έχουμε συνδέσει με τη συνάρτηση
							 | 
						|||
| 
								 | 
							
								    `dest`)
							 | 
						|||
| 
								 | 
							
								-   **`void dest(GtkWidget *widget, gpointer                                 data)`**\
							 | 
						|||
| 
								 | 
							
								    Με τη συνάρτηση αυτή έχουμε έξοδο από το πρόγραμμα, μέσω μιας ενσωματωμένης στο gtk συνάρτησης, της `gtk_main_quit`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [4.5 Πως θα το τρέξετε.]{#ss4.5}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Για να κάνετε compile to πρόγραμμα, χρησιμοποιήστε την εντολή:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    gcc -Wall -g HelloMagez.c -o hellomagez `gtk-config --cflags` `gtk-config --libs`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								\`Οσοι δεν ξέρουν τι είναι αυτό, **man gcc**. Μόλις ολοκληρωθεί η παραπάνω εντολή, στο τρέχον directory θα έχει δημιουργηθεί το αρχείο **hellomagez**, που είναι
							 | 
						|||
| 
								 | 
							
								και το εκτελέσιμο. Τρέξτε το!
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [5. Tοποθέτηση των widgets]{#s5}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Το πιο πιθανό είναι να μην δημιουργήσουμε ποτέ μια εφαρμογή που θα έχει μονάχα ένα *widget*, όπως στην περίπτωση του **HelloMagez**. Μάλλον, αυτό που θα θέλουμε
							 | 
						|||
| 
								 | 
							
								να κάνουμε θα αποτελείται από περισσότερα από ένα *widget*. Ας δούμε πως μπορούμε να τα τοποθετήσουμε στο παράθυρο του προγράμματός μας.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [5.1 Boxes, ή αλλιώς κουτιά :)]{#ss5.1}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Τα *boxes* θα γίνουν οι καλύτεροι φίλοι μας στη διαδικασία σύνταξης εφαρμογών για **gtk**, αλλά - πιστέψτε με - και οι χειρότεροί μας εχθροί. Θα μάθουμε να
							 | 
						|||
| 
								 | 
							
								ζούμε με τα *boxes*, και να είστε σίγουροι ότι δεν θα τα γλιτώσουμε. Τι είναι όμως αυτά τα *boxes*;\
							 | 
						|||
| 
								 | 
							
								Είναι widgets, όπως και όλα τα άλλα. Απλά, μπορούν να περιέχουν περισσότερα από 1 widgets πάνω τους. Δεν είναι ορατά, και χρησιμοποιούνται μονάχα για την
							 | 
						|||
| 
								 | 
							
								ομαδοποίηση αντικειμένων. Τα boxes μπορεί να είναι δύο ειδών, ανάλογα με τον προσανατολισμό που θέλουμε να πάρουν τα προς τοποθέτηση σε αυτό *widgets*:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **HORIZONTAL BOXES**\
							 | 
						|||
| 
								 | 
							
								    Τα τοποθετημένα σε αυτό *widgets* θα μπουν στη σειρά από αριστερά προς τα δεξιά ή από τα δεξιά προς τα αριστερά όπως θα δούμε παρακάτω στην εξήγηση των
							 | 
						|||
| 
								 | 
							
								    συναρτήσεων **`gtk_box_pack_start`** και **`gtk_box_pack_end`**.\
							 | 
						|||
| 
								 | 
							
								    H δημιουργία ενός τέτοιου *box* επιτυγχάνεται με τη χρήση της συνάρτησης **`gtk_hbox_new`**.
							 | 
						|||
| 
								 | 
							
								-   **VERTICAL BOXES**\
							 | 
						|||
| 
								 | 
							
								    Τα τοποθετημένα σε αυτό *widgets* θα μπουν στη σειρά από πάνω προς τα κάτω ή από κάτω προς τα πάνω, πάλι με χρήση των **`gtk_box_pack_start`** και
							 | 
						|||
| 
								 | 
							
								    **`gtk_box_pack_end`**.\
							 | 
						|||
| 
								 | 
							
								    Σε γενικές γραμμές, η δημιουργία ενός τέτοιου *box* επιτυγχάνεται με τη χρήση της συνάρτησης **`gtk_hbox_new`**.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### Δημιουργία, σύνταξη και παραμέτροι.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Για τη δημιουργία ενός box, χρησιμοποιούμε τις **`gtk_hbox_new`** και **`gtk_vbox_new`** όπως αναφέραμε και παραπάνω.\
							 | 
						|||
| 
								 | 
							
								Η σύνταξη και ο τύπος των συναρτήσεων αυτών είναι:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    GtkWidget *gtk_hbox_new(gint homogeneous, gint spacing);
							 | 
						|||
| 
								 | 
							
								    GtkWidget *gtk_vbox_new(gint homogeneous, gint spacing);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Στη συνέχεια θα αναφέρομαι μονάχα στην εντολή `gtk_hbox_new` και ότι ισχύει για αυτήν ισχύει και για την `gtk_vbox_new`. \`Οπως παρατηρούμε, επιστρέφει τιμή
							 | 
						|||
| 
								 | 
							
								τύπου `GtkWidget`, και παίρνει δύο τιμές, τύπου *gint*, τις **homogenous** και **spacing**.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Η **homogenous** μπορεί να είναι TRUE ή FALSE (και φυσικά οποιαδήποτε λογική έκφραση) και μας δίνει τη δυνατότητα να ελέγξουμε αν τα *widgets* που θα
							 | 
						|||
| 
								 | 
							
								τοποθετηθούν στο box θα έχουν το ίδιο πλάτος όλα ή όσο χρειάζεται το κάθε ένα.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Η παράμετρος **spacing** καθορίζει πόσα pixels θα απέχουν μεταξύ τους τα *widgets*.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### Εργασία με τα boxes
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Δεν πιστεύω να σας τρόμαξα με τα όσα έγραψα για τα boxes στην προηγούμενη ενότητα\... \`Οπως θα δείτε, η εργασία με τα boxes είναι μια εύκολη υπόθεση, αν ξέρετε
							 | 
						|||
| 
								 | 
							
								να δουλεύετε τις συναρτήσεις **`gtk_box_pack_start`** και **`gtk_box_pack_end`**. Στη συνέχεια θα δούμε πόσο εύκολη είναι η εργασία με αυτές τις συναρτήσεις.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**`gtk_box_pack_start`**\
							 | 
						|||
| 
								 | 
							
								**`gtk_box_pack_end`**
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Η μορφή αυτών των συναρτήσεων είναι:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void gtk_box_pack_start(GtkBox *box, GtkWidget *child, gint expand, gint fill, gint padding );
							 | 
						|||
| 
								 | 
							
								    void gtk_box_pack_end(GtkBox *box, GtkWidget *child, gint expand, gint fill, gint padding );
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Δεν επιστρέφουν καμία τιμή (είναι void απ\' ότι βλέπετε) και τα ορίσματα που δέχονται εξηγούνται παρακάτω:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`GtkBox *box`**\
							 | 
						|||
| 
								 | 
							
								    Το όνομα του *box* στο οποίο αναφερόμαστε.
							 | 
						|||
| 
								 | 
							
								-   **`GtkWidget *child`**\
							 | 
						|||
| 
								 | 
							
								    Το όνομα του *widget* το οποίο προσθέτουμε.
							 | 
						|||
| 
								 | 
							
								-   **`gint expand`**\
							 | 
						|||
| 
								 | 
							
								    Είναι μορφής *gint*, και αυτό που περιγράφει είναι αν το *widget* που τοποθετούμε θα πιάνει όλη την περιοχή του *box*. Μπορούμε να του αποδώσουμε τις τιμές
							 | 
						|||
| 
								 | 
							
								    TRUE και FALSE. TRUE στην περίπτωση που θέλουμε να πιάνει όλη την διαθέσιμη περιοχή, και FALSE αν θέλουμε να πιάνει μόνο όση περιοχή του είναι απαραίτητη.
							 | 
						|||
| 
								 | 
							
								    Δίδοντας την τιμή FALSE μπορούμε να επιτύχουμε (αριστερή στην περίπτωση της **`gtk_box_pack_start`** ή δεξιά στην περίπτωση της **`gtk_box_pack_end`**)
							 | 
						|||
| 
								 | 
							
								    στοίχιση.\
							 | 
						|||
| 
								 | 
							
								    \`Οπως καταλαβαίνετε, αν δοθεί η τιμή TRUE, δεν έχει σημασία πια από τις **`gtk_box_pack_start`** ή **`gtk_box_pack_end`** χρησιμοποιήσουμε.
							 | 
						|||
| 
								 | 
							
								-   **`gint fill`**\
							 | 
						|||
| 
								 | 
							
								    Η τιμή αυτής της παραμέτρου έχει σημασία μόνο αν η τιμή της **`expand`** είναι TRUE. Και αυτό γιατί περιγράφει αν ο επιπλέον χώρος που μένει μετά τη
							 | 
						|||
| 
								 | 
							
								    δημιουργία των *widgets* θα ανήκει σε αυτά (Δηλ. θα τα μεγαλώσει) στην περίπτωση που πάρει την τιμή TRUE ή αν θα ανήκει στο *box* σαν αδιάθετος χώρος στην
							 | 
						|||
| 
								 | 
							
								    περίπτωση που της δώσουμε την τιμή FALSE
							 | 
						|||
| 
								 | 
							
								-   **`gint padding`**\
							 | 
						|||
| 
								 | 
							
								    Αριθμός τύπου *gint*, που καθορίζει πόσος χώρος (σε pixels) γύρω από το κάθε *widget* δεν θα χρησιμοποιείται.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [5.2 Tοποθέτηση των widgets, partII (λέγε με tables)]{#ss5.2}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Υπάρχει και άλλος ένας τρόπος για να στοιχίσουμε τα widgets στο παράθυρο της εφαρμογής μας. Αυτός επιτυγχάνεται με τη χρήση της συνάρτησης **`gtk_table_new`**
							 | 
						|||
| 
								 | 
							
								που δημιουργεί έναν πίνακα στο παράθυρο της εφαρμογής μας. Φυσικά, και αυτή η συνάρτηση χρησιμοποιείται μόνο για την τοποθέτηση των διαφόρων *widgets* στο
							 | 
						|||
| 
								 | 
							
								παράθυρο, και δεν σχεδιάζεται κανένας πίνακας στην εφαρμογή μας.\
							 | 
						|||
| 
								 | 
							
								Η σύνταξή της είναι η εξής:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    GtkWidget *gtk_table_new(gint rows, gint columns, gint homogeneous );
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Είναι προφανές ότι rows είναι ο αριθμός των γραμμών του πίνακά μας και columns ο αριθμός των στηλών του.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Το homogenous περιγράφει τον τρόπο που τα κελιά του πίνακα θα διανέμονται και θα τοποθετούνται πάνω στο παράθυρό μας. Αν είναι TRUE, τότε όλα τα κελιά του
							 | 
						|||
| 
								 | 
							
								πίνακα μεγαλώνουν ή μικραίνουν, σύμφωνα με το μεγαλύτερο *widget* στον πίνακα. Αν πάρει την τιμή FALSE, το μέγεθος ορίζεται από το πιο μακρύ *widget* στην κάθε
							 | 
						|||
| 
								 | 
							
								στήλη και το πιο ψηλό *widget* στην σειρά. Αυτό που ουσιαστικά συμβαίνει είναι ότι αν το HOMOGENEOUS είναι TRUE, όλα τα *widgets* έχουν το ίδιο μέγεθος, και
							 | 
						|||
| 
								 | 
							
								είναι ομοιόμορφα τοποθετημένα πάνω στο box.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Η διάταξη των κελιών του πίνακα, διαμορφώνεται από το 0 μέχρι τις τιμές *rows* και *columns*. Μoιάζει δηλαδή με το παρακάτω. Η αρίθμηση όπως βλέπετε, ξεκινάει
							 | 
						|||
| 
								 | 
							
								από την πάνω αριστερή γωνία.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								          0          1          2
							 | 
						|||
| 
								 | 
							
								         0+----------+----------+
							 | 
						|||
| 
								 | 
							
								          |          |          |
							 | 
						|||
| 
								 | 
							
								         1+----------+----------+
							 | 
						|||
| 
								 | 
							
								          |          |          |
							 | 
						|||
| 
								 | 
							
								         2+----------+----------+
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Για την τοποθέτηση ενός widget σε ένα πίνακα, χρησιμοποιούμε την συνάρτηση **`gtk_table_attach`**, της οποίας η σύνταξη είναι η παρακάτω
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void gtk_table_attach(GtkTable  *table, GtkWidget *child, gint left_attach, gint right_attach,
							 | 
						|||
| 
								 | 
							
								                          gint top_attach, gint bottom_attach, gint xoptions,
							 | 
						|||
| 
								 | 
							
								                          gint yoptions, gint xpadding, gint ypadding);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Δεν επιστρέφei καμία τιμή και τα ορίσματα που δέχεται είναι
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`GtkTable *table`**\
							 | 
						|||
| 
								 | 
							
								    Το Table στο οποίο αναφερόμαστε
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`GtkWidget *child`**\
							 | 
						|||
| 
								 | 
							
								    Το widget που θέλουμε να τοποθετήσουμε
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint left_attach`**\
							 | 
						|||
| 
								 | 
							
								    Η αριστερή συντεταγμένη από όπου θα αρχίζει το widget
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint right_attach`**\
							 | 
						|||
| 
								 | 
							
								    Η δεξιά συντεταγμένη από όπου θα τελειώνει το widget
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint top_attach`**\
							 | 
						|||
| 
								 | 
							
								    Η πάνω συντεταγμένη από όπου θα αρχίζει το widget
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint bottom_attach`**\
							 | 
						|||
| 
								 | 
							
								    Η κάτω συντεταγμένη που θα τελειώνει το widget
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint xoptions`**\
							 | 
						|||
| 
								 | 
							
								    χρησιμοποιείται για τον καθορισμό του τρόπου πακεταρίσματος, και θα το δούμε στη συνέχεια πιο αναλυτικά
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint yoptions`**\
							 | 
						|||
| 
								 | 
							
								    \`Οπως και το παραπάνω, και οι τιμές που μπορεί να πάρει τόσο αυτό όσο και το `xoptions` είναι οι παρακάτω:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    -   **`GTK_FILL`**\
							 | 
						|||
| 
								 | 
							
								        Αν η περιοχή (συνήθως το κουτί του πίνακα) είναι μεγαλύτερο από το widget που τοποθετούμε, το widget θα μεγαλώσει τόσο ώστε να καλύψει όλο τον χώρο που
							 | 
						|||
| 
								 | 
							
								        υπάρχει.
							 | 
						|||
| 
								 | 
							
								    -   **`GTK_SHRINK`**\
							 | 
						|||
| 
								 | 
							
								        Αν κατά την απόδοση χώρου σε ένα κουτί ο χώρος που δίνεται σε ένα widget είναι μικρότερος από το μέγεθός του ίδιου του widget, τότε αυτό θα μικράνει
							 | 
						|||
| 
								 | 
							
								        ώστε να χωράει. Κάτι τέτοιο συμβαίνει όταν ο χρήστης κάνει resize σε ένα παράθυρο. Αν δεν είναι ορισμένο το **`GTK_SHRINK`** είναι πολύ πιθανό σε μια
							 | 
						|||
| 
								 | 
							
								        τέτοια περίπτωση να μην εμφανίζονται τα widgets μέσα στον χώρο του παραθύρου μας.
							 | 
						|||
| 
								 | 
							
								    -   **`GTK_EXPAND`**\
							 | 
						|||
| 
								 | 
							
								        Με αυτό τον τρόπο μπορούμε να αποδώσουμε στο table μας όλο τον χώρο που απομένει στο παράθυρο μετά τη δημιουργία του.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Οι παραπάνω τιμές που μπορούν να πάρουν, είναι δυνατό να συνδυαστούν με το **OR** για να καλύψουμε περισσότερες από μια περιπτώσεις.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint xpadding`**\
							 | 
						|||
| 
								 | 
							
								    Το γνωστό και πολλάκις εξηγημένο padding στον οριζόντιο άξονα
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								-   **`gint ypadding`**\
							 | 
						|||
| 
								 | 
							
								    \`Οτι και το παραπάνω, αναφέρεται όμως στον κατακόρυφο άξονα
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Για όλους εσάς που όλα αυτά τα ορίσματα στην παραπάνω συνάρτηση σας φάνηκαν πολλά, υπάρχει και μια άλλη, που κάνει την ίδια (περίπου) δουλειά απλούστερα.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void gtk_table_attach_defaults(GtkTable *table, GtkWidget *widget, gint left_attach,
							 | 
						|||
| 
								 | 
							
								                                   gint right_attach, gint top_attach, gint bottom_attach);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								\`Οπως παρατηρούμε, μόνο οι βασικές παραμέτροι περνάνε στη συνάρτηση. Ουσιαστικά δηλαδή, μόνο τα controls θέσης και μεγέθους. Οι παραμέτροι που δεν αναφέρονται,
							 | 
						|||
| 
								 | 
							
								παίρνουν κάποιες προκαθορισμένες τιμές. Αυτές είναι οι πλέον χρησιμοποιούμενες, και συγκεκριμένα τα **X** και **Y options** γίνονται
							 | 
						|||
| 
								 | 
							
								**`GTK_FILL |                               GTK_EXPAND`**, (ελπίζω να ξέρετε ότι το \`\`\|\'\' είναι το **OR**) και στα **X** και **Y padding** δίδεται η τιμή
							 | 
						|||
| 
								 | 
							
								0.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Για να καθορίσουμε το spacing ανάμεσα σε συγκεκριμένες γραμμές και στήλες ενός πίνακα, χρησιμοποιούμε τις παρακάτω συναρτήσεις:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								         void gtk_table_set_row_spacing(GtkTable *table, gint row, gint spacing);
							 | 
						|||
| 
								 | 
							
								         void gtk_table_set_col_spacing(GtkTable *table, gint col, gint spacing);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								όπου row ή col η γραμμή ή η στήλη στην οποία αναφερόμαστε, και spacing η απόσταση που θέλουμε να ορίσουμε σαν spacing. Για τις στήλες το spacing προστίθεται στα
							 | 
						|||
| 
								 | 
							
								ΔΕΞΙΑ και για τις γραμμές ΚΑΤΩ.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Είναι επίσης δυνατό να καθορίσουμε για ΟΛΕΣ τις στήλες ή γραμμές το spacing, χρησιμοποιώντας τις συναρτήσεις:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								         void gtk_table_set_row_spacings(GtkTable *table, gint spacing);
							 | 
						|||
| 
								 | 
							
								         void gtk_table_set_col_spacings(GtkTable *table, gint spacing);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								----------------------------------------------------------------------------------------------------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								\`Οπως πολύ καλά καταλάβατε, η τελευταία στήλη και η τελευταία σειρά δεν λαμβάνουν αυτή την τιμή, γιατί θα δημιουργούσε ένα κενό στα αριστερά και ένα κενό κάτω.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Είναι φανερό ότι το να δουλεύει κανείς με tables είναι εύκολο. Εγώ προσωπικά δεν το προτιμώ, παρόλο που είναι βασικά η μόνη λύση στην περίπτωση που θέλουμε
							 | 
						|||
| 
								 | 
							
								απόλυτα στοιχισμένα κουτάκια και κουμπάκια και widgets. Δοκιμάστε το πάντως, και πολλές φορές θα σας λύσει τα χέρια
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### [5.3 Η συνέχεια]{#ss5.3}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Τον επόμενο μήνα θα συνεχίσουμε αυτό το άρθρο και θα ασχοληθούμε περισσότερο με τα widgets (buttons, radio/check/toggle buttons, text boxes, κ.λπ.) και τις
							 | 
						|||
| 
								 | 
							
								ιδιότητές τους. Μέχρι τότε, πολλά φιλάκια.
							 | 
						|||
| 
								 | 
							
								
							 |