Πέμπτη, 18 Ιανουαρίου 2018

Αναθεώρηση 39 (Έκδοση 9.0)

Αλλαγές-Βελτιώσεις:
1) Βελτίωση στο αναδυόμενου μενού επιλογών στον διορθωτή και στο στοιχείο ελέγχου Κείμενο (EditBox). Σε περίπτωση που ανοίγουμε το μενού στην κάτω ή και στην δεξιά πλευρά της οθόνης, τότε έρχεται πιο μέσα το μενού για να φαίνεται (δούλευε ο κώδικας αλλά είχε ένα λάθος και δεν έρχονταν αρκετά πιο μέσα το μενού).

2) Τα μενού στις φόρμες χρήστη κλείνουν αν επιλέξουμε μια άλλη εφαρμογή/εικονίδιο στην επιφάνεια εργασίας, με το ποντίκι ή με το ALT+TAB (πριν έκλειναν μόνο αν επιλέγαμε κάτι άλλο από τις φόρμες της εφαρμογής αλλά όχι από αλλαγή εφαρμογής). Επίσης και το αναδυόμενο μενού επιλογών, λειτουργεί έτσι, καθώς και δικές μας φόρμες που τις ανοίγουμε σαν αναδυόμενο μενού, δηλαδή με έξοδο αν χάσει την εστίαση. Παραμένει να μην κλείνει η λίστα επιλογών που βγαίνει με το Μενού (υπάρχει λόγος), στην κονσόλα, αν αλλάξουμε εφαρμογή, ενώ το ίδιο συμβαίνει και στην φόρμα Ρυθμίσεις.
Δικές μας φόρμες μπορούμε να ανοίγουμε ως "modal" (γίνονταν) αλλά τώρα μπορούμε να ορίσουμε το πώς θα συμπεριφέρεται το σύστημα σε περίπτωση που χαθεί η εστίαση από τη φόρμα, βάζοντας Αληθές ή Ψευδές σε δυο ιδιότητες της φόρμας, το "IamPopUp" και το "PopUpMenuVal". Το πρώτο με Αληθές και το δεύτερο με Ψευδές κλείνει η φόρμα μόνο αν επιλέξουμε κάτι άλλο από την εφαρμογή μας. Με το δεύτερο αληθές τότε κλείνει η φόρμα και όταν επιλέξουμε μια άλλη εφαρμογή.
(Στην Μ2000 οι φόρμες "κλείνουν" χωρίς να "διαγραφούν", μέχρι να το κάνουμε μέσω κώδικα, με την Όρισε, να ορίσουμε το όνομα της φόρμας να είναι Τίποτα, ή να αφήσουμε να γίνει αυτόματα με το τερματισμό του τμήματος που δημιούργησε τη φόρμα).

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

4) Στη Λίστα (ListBox) υπάρχει ένα γεγονός Color το οποίο ζητάει (περνάει με αναφορά μεταβλητή), το χρώμα του επιλεγμένου στοιχείου. Τώρα βελτιώθηκε  για να μην ζητάει σε κάθε ορατή γραμμή το χρώμα, αλλά μόνο στην αρχή πριν την επανάληψη για την εμφάνιση (σχεδιασμό) των ορατών στοιχείων της λίστας, δηλαδή στέλνοντας μόνο μία φορά το γεγονός.
Τα γεγονότα που ζητάνε επιστροφή τιμής (ουσιαστικά την αλλαγή τιμής θέλουν, αλλά μπορεί να μην πάρουν, ίσως γιατί απλά δεν έχουμε μια συνάρτηση για να ικανοποιήση το γεγονός), καλούνται άμεσα, δηλαδή αν υπάρχει συνάρτηση για να εξυπηρετήσει το γεγονός τότε αυτό πρέπει να γίνει γρήγορα για να "συνεχίσει" το σύστημα να δέχεται γεγονότα. Τα γεγονότα που απλά δίνουν στοιχεία μπορούν να μαζευτούν σε ουρά και να εκτελεστούν πιο μετά. Στις φόρμες μπορούμε να ορίσουμε αντικείμενο γεγονός που θα καλείται από αυτά τα γεγονότα (αλλά όχι από τα "άμεσα", αυτά με επιστροφή τιμής).


Γενικά περί γεγονότων του γραφικού περιβάλλοντος.
Εξ ορισμού ένα γεγονός δεν μπορεί να κληθεί αν ήδη έχει κληθεί και δεν έχει "επιστρέψει". Γεγονότα που δεν ικανοποιούνται επειδή δεν υπάρχει συνάρτηση εξυπηρέτησης βγαίνουν "εκτός" μετά την πρώτη ζήτηση, βάσει ενός "μαυροπίνακα". Όταν επιλέγουμε μια φόρμα (δηλαδή δεν ήταν επιλεγμένη, ή επειδή πρώτη φορά εμφανίστηκε είτε γιατί είχαμε ήδη επιλέξει μια άλλη), τότε ο μαυροπίνακας καθαρίζει. Αυτό συμβαίνει γιατί ενδέχεται να έχει προστεθεί συνάρτηση εξυπηρέτησης κατά την εκτέλεση (γίνεται αυτό στην Μ2000).
Μπορούμε να έχουμε πίνακες φορμών και πίνακες στοιχείων στις φόρμες, οπότε σε μια τέτοια περίπτωση ένα γεγονός θα επιστρέφει πρώτα δείκτες για τους πίνακες αντίστοιχα, και στο τέλος μετά τα στοιχεία που στέλνει, ακολουθεί και ένας δείκτης στη φόρμα, για δύο λόγους, πρώτα για να μην "διαλυθεί" η φόρμα πριν τερματίσει η εξυπηρέτηση (ο δείκτης κρατάει τη φόρμα σε ζωή), και δεύτερον για να χειριστούμε με εντολές για COM αντικείμενα, την φόρμα, αν θέλουμε κάτι παραπάνω (οι φόρμες χρήστη είναι τέτοια αντικείμενα, ιδιωτικά όμως). Κάτι παραπάνω είναι να προσθέσουμε στοιχεία ελέγχου.


Αν έχουμε νήματα στο ίδιο τμήμα με τις συναρτήσεις εξυπηρέτησης, δεν έχουμε πρόβλημα "σύγκρουσης", επειδή τα γεγονότα "μπαίνουν" σφήνα σε οποιοδήποτε κώδικα, εκτελούνται, και μετά ο κώδικας συνεχίζει. Και τα νήματα δουλεύουν με εξωτερικό γεγονός, έναν χρονιστή του User32 (βιβλιοθήκη ρουτινών συστήματος), με τις SetTimer και KillTimer. Και τα νήματα, και οι συναρτήσεις εξυπηρέτησης τρέχουν σε δικά τους αντικείμενα εκτέλεσης, αλλά "βλέπουν" τις μεταβλητές του τμήματος (σαν να είναι κώδικας στο τμήμα) εκείνου στο οποίο τα μεν νήματα δημιουργήθηκαν, και για τις συναρτήσεις εξυπηρέτησης εκεί όπου τα αντικείμενα του γραφικού περιβάλλοντος δημιουργήθηκαν (είναι ουσιαστικά μεταβλητές του τμήματος). Στα νήματα δημιουργούμε στατικές μεταβλητές (για όσο το νήμα υπάρχει), και χρησιμοποιούμε τον ιδιωτικό σωρό τιμών, για να κρατάμε κατάσταση, ή μέσω αυτών να χρησιμοποιούμε αντικείμενα του τμήματος (στα νήματα αν δημιουργήσουμε κάτι, μένει στο τμήμα. Στις συναρτήσεις εξυπηρέτησης μπορούμε να δημιουργήσουμε μεταβλητές με την εντολή Τοπικό ή Τοπική ή Τοπικές, ώστε να "σκιάσουν" τυχόν τοπικές του τμήματος με το ίδιο όνομα, ή τοπική άλλου γεγονότος που ακόμα δεν ικανοποιήθηκε πλήρως. Όπως και να έχει το πράγμα, εκτελείται κώδικας από ένα σημείο! Οπότε πρώτα θα τερματίσει η πιο πρόσφατη συνάρτηση εξυπηρέτησης, μετά η αμέσως προηγούμενη, μετά τα νήματα, και τέλος ο κώδικας, του τμήματος, Μπορεί ένα νήμα να έχει "μπλοκαριστεί", για παράδειγμα να ζητάει εισαγωγή αριθμού. Τα νήματα "θυμούνται" το επίπεδο που εξάγουν γράμματα και γραφικά. Κάθε φόρμα έχει και αυτή Επίπεδο για γραφικά και κείμενο όπως η κονσόλα. Οι εντολές εισαγωγής δεν λειτουργούν στις φόρμες χρήστη. Εκεί για εισαγωγή χρησιμοποιούμε τα στοιχεία ελέχγου. Η κονσόλα έχει επιπλέον 32 επίπεδα (Χρησιμοποιούνται και ως "παίκτες" για παιχνίδια), καθώς και άλλα δυο, ένα το Περιθώριο πίσω από την οθόνη (το βασικό επίπεδο), και ένα μη φανερό, τη σελίδα του επιλεγμένου εκτυπωτή.

Στη Μ2000 εκτός από τα γεγονότα που παράγονται από το γραφικό περιβάλλον έχουμε άλλα δυο είδη, το αντικείμενο Γεγονός και τον ορισμό αντικειμένων COM με γεγονότα. Το αντικείμενο γεγονός που το φτιάχνουμε ως λίστα συναρτήσεων (μπορούν να είναι και συναρτήσεις αντικειμένων), ώστε να στέλνουμε με μια εντολή Κάλεσε Γεγονός σε ένα γεγονός τιμές (και με αναφορά αν θέλουμε) χωρίς να μας νοιάζει αν θα εξυπηρετηθούν, με το "γέμισμα" με συναρτήσεις να γίνεται με έλεγχο, με προσθήκη και με αφαίρεση καθώς και με αδρανοποίηση του αντικειμένουν όταν χρειαστεί (να μην λειτουργεί χωρίς να αφαιρέσουμε τις συναρτήσεις). Τέλος και σε εξωτερικά αντικείμενα τύπου COM, μπορούμε να χειριστούμε γεγονότα. Πχ μπορούμε να ξεκινήσουμε τον επεξεργαστή κειμένου Word και να παίρνουμε αντικείμενα με έλεγχο γεγονότων κατ΄απαίτηση. Οι συναρτήσεις εξυπηρέτησης για COM αντικείμενα έχουν το όνομα της μεταβλητής που δείχνει στο αντικείμενο, μετά ακολουθεί κάτω παύλα και μετά το όνομα του γεγονότος.  Οφείλουμε να έχουμε με μια Διάβασε Νέο (νέο ώστε αν ήδη υπάρχει το όνομα της μεταβλητής να βγει μια φορά ακόμα, και μέχρι να τερματίσει το γεγονός). Στην Μ2000 οι μεταβλητές (εκτός από τις στατικές) μπορούν να ορίζονται ξανά, σκιάζοντας τις υπάρχουσες, και διαγράφονται με τον ανάποδο τρόπο από αυτόν που ορίστηκαν, με το πέρας του τμήματος/συνάρτησης/ρουτίνας/ μπλοκ προσωρινών ορισμών, που τα όρισε. Οι στατικές μεταβληρές (χωρίς ονόματα με παρενθέσεις, απλές μεταβλητές, και δείκτες σε αντικείμενα) ανήκουν στο αντικείμενο εκτέλεσης και έχουν δικό τους κατάλογο με συνάρτηση κατακερματισμού. Ενώ οι μεταβλητές ανήκουν σε ένα γενικό "κατάλογο" που λειτουργεί με συνάρτηση κατακερματισμού. Τις μεταβλητές μπορούμε να τις περάσουμε με αναφορά, επειδή ανήκουν σε αυτήν την γενική λίστα. Μια μεταβλητή που είναι αναφορά άλλης έχει στην ουσία μια δική της θέση στο κατάλογο, αλλά έχει ένα δείκτη στο ίδιο στοιχείο που δείχνει η "Αρχική". Η διαφορά σε κάθε αναφορά είναι ότι υπάρχει μια σημαία που λέει "είμαι αναφορά". Μια αναφορά δεν μπορεί να πάρει νέα αναφορά. Και στη διαγραφή μεταβλητών, το σύστημα χρησιμοποιεί τις σημαίες για να μην "μηδενίσει" την μνήμη τους (που στην ουσία είναι αυτή της αρχικής, αναφερόμενης τιμής)