- 1 Εισαγωγή
- 2 Δομή του Project
- 3 Δομή της εφαρμογής
- 3.1 class FirstWindow(QMainWindow)
- 3.2 class FlowLayout(QLayout)
- 3.3 class Question(Protocol)
- 3.4 class FillBlankQuestion()
- 3.5 class FillBlankQuestionWidget(QWidget)
- 3.6 class MultipleChoiceQuestion()
- 3.7 class MultipleChoiceQuestion(QWidget)
- 3.8 class QuestionWidget(QWidget)
- 3.9 class OverviewListWidget(QListWidget)
- 3.10 class OverviewQuestionWidget(QWidget)
- 3.11 class ExercisesWidget(QWidget)
- 3.12 class LessonsWidget(QWidget)
- 3.13 class ChaptersWidget(QWidget)
- 3.14 class Statistics(QWidget)
- 4 Διαδικασία Επέκτασης
Σε αυτό το εγχειρίδιο θα αναλυθεί συνοπτικά η δομή της εφαρμογής και του project όπως και η διαδικασία επέκτασης της εφαρμογής. Η δομή της εφαρμογής θα αναλυθεί μέσω από τις αλληλεπιδράσεις των διαφόρων συναρτήσεων και αντικειμένων της. Η δομή του project θα αναλυθεί μέσω των εργαλείων που χρειάζονται για την ανάπτυξη και επέκταση της εφαρμογής. Τέλος θα δοθεί μια καθαρή αρχή για όποιον προτίθεται να επεκτάσει την εφαρμογή.
Το παρόν εγχειρίδιο έχει γραφτεί σε Rmarkdown (Allaire κ.ά. 2021) (Xie, Allaire, και Grolemund 2018) (Xie, Dervieux, και Riederer 2020).
Η διαχείριση πηγαίου κώδικα του πρότζεκτ γίνεται με git (Chacon και Straub 2014). Η διαχείριση των dependencies του πρότζεκτ γίνεται με poetry (Poetry core contributors 2022)
Η βασική δομή των αρχείων του πρότζεκτ είναι η παρακάτω.
education_application
├── app.py
├── resources
│ ├── lessons
│ │ ├── img
│ │ │ └── <εικόνες για html αρχεία μαθημάτων>
│ │ ├── style.css
│ │ └── <αρχεία html μαθημάτων>
│ └── <εικόνες για το UI>
├── style.css
├── results.csv
├── Chapters.py
├── Exercises.py
├── FlowLayout.py
├── Lessons.py
├── MenuButton.py
├── Question.py
├── Statistics.py
├── WrapLabel.py
├── poetry.lock
├── pyproject.toml
├── LICENSE
└── todo.norg
Στο root του φακέλου βρίσκονται τα αρχεία πηγαίου κώδικα python, το css του UI, τα αρχεία του poetry και ο φάκελος resources. Ο φάκελος resources περιέχει όλα τα αρχεία που φορτώνονται από το UI όπως και τον φάκελο lessons. O φάκελος lessons περιέχει όλο το υλικό των μαθημάτων σε HTML μορφή και επιπλέον εικόνες στο φάκελο img.
Σε αυτή την ενότητα θα αναλυθούν οι συναρτήσεις και τα αντικείμενα της εφαρμογής.
Το αρχικό παράθυρο της εφαρμογής. Παρέχει 4 MenuButtons, για Μαθήματα, Ασκήσεις, Στατιστικά και έξοδο. Επίσης παρέχει ένα MenuBar με ένα κουμπί Help (ανοίγει το εγχειρίδιο χρήστη) και ένα About (εμφανίζει έκδοση και πληροφορίες επικοινωνίας).
Κατασκευαστής, δεν παίρνει ορίσματα.
Event handler για κλικ πάνω στο κουμπί Μαθημάτων. Αλλάζει το centralWidget του FirstWindow σε ένα LessonsWidget.
Event handler για κλικ πάνω στο κουμπί Ασκήσεων. Αλλάζει το centralWidget του FirstWindow σε ένα ExercisesWidget.
Event handler για κλικ πάνω στο κουμπί Στατιστικών. Αλλάζει το centralWidget του FirstWindow σε ένα StatisticsWidget.
Event handler για κλικ πάνω στο κουμπί Έξοδος. Ανοίγει ένα διάλογο ναι/όχι και σε περίπτωση ναι, τερματίζει την εφαρμογή.
Event handler για κλικ πάνω στο κουμπί Help. Ανοίγει το εγχειρίδιο χρήστη.
Event handler για κλικ πάνω στο κουμπί About. Εμφανίζει την έκδοση της εφαρμογής και πληροφορίες επικοινωνίας.
Παρέχει ένα QLayout το οποίο εμφανίζει τα widget του σε γραμμές ανάλογα με τον διαθέσιμο χώρο. Σε περίπτωση που ένα widget δεν χωράει στην τελευταία γραμμή, προστίθεται στην επόμενη. Η κώδικας είναι μετάφραση του C++ παραδείγματος που παρέχεται από το documentation του Qt6 σε Python με μια επιπλέον λειτουργία.
Κατασκευαστής.
- margin: int default = -1 Το εσωτερικό κενό του χώρου του Layout και των widget του.
- hSpacing: int default = -1 Το οριζόντιο κενό μεταξύ των widget του Layout.
- vSpacing: int default = -1 Το κάθετο κενό μεταξύ των widget του Layout.
Προσθέτει ένα item στο Layout.
- item: QLayoutItem Το item που θα προστεθεί.
Προσθέτει ένα QSpacerItem μηδενικού μεγέθους. Δεν υπάρχει στην C++ έκδοση του κώδικα. Αναγκάζει τα widget που θα προστεθούν μετά από την κλήση της, να πάνε στην επόμενη σειρά, ανεξαρτήτου εάν χωρούσαν στην τελευταία ή όχι.
Ορίζει ένα Protocol (implicit interface) για το τι πρέπει να περιέχουν οι κλάσεις που θεωρούνται Question.
-
prompt: str Το κείμενο της ερώτησης
-
correct: int | list[str] Η σωστή απάντηση/απαντήσεις της ερώτησης
-
answer: str | list[str] Η απάντηση/απαντήσεις που θα έχει δώσει ο χρήστης
Συνάρτηση που θα πρέπει να επιστρέφει True όταν οι απαντήσεις του χρήστη είναι σωστές, False διαφορετικά.
Υλοποίηση του Question(Protocol). Ορίζει μια ερώτηση τύπου συμπλήρωσε-τα-κενά.
- answer: list[str] Οι απαντήσεις που θα έχει δώσει ο χρήστης
-
prompt: str Το κείμενο της ερώτησης
-
correct: list[str] Οι σωστές απαντήσεις της ερώτησης
-
text: str Το κείμενο της ερώτησης που περιέχει τα κενά που ο χρήστης πρέπει να γεμίσει. Ο χαρακτήρας ᾽&᾽ μέσα στο κείμενο ορίζει ένα κενό προς γέμισμα.
Επιστέφει True εάν η ερώτηση που δεικτοδοτήται από το index έχει απαντηθεί σωστά από τον χρήστη.
- answer: *list[QLineEdit] Λίστα των πεδίων που ο χρήστης θα πρέπει γεμίσει.
- question: FillBlankQuestion Η ερώτηση του widget.
Κατασκευαστής, γεμίζει το answer με τα QLineEdit.
Επιστρέφει την ερώτηση του widget με τις απαντήσεις του χρήστη.
Υλοποίηση του Question(Protocol). Ορίζει μια ερώτηση τύπου επέλεξε-το-σωστό.
- answer: str Η απάντηση που θα δώσει ο χρήστης
- prompt: str Η ερώτηση.
- choices: list[str] Οι επιλογές που δίνονται στον χρήστη
- correct: int Ο δείκτης της σωστής επιλογής στη λίστα των επιλογών
- question: MultipleChoiceQuestion Η ερώτηση του widget.
Επιστρέφει την ερώτηση του widget με τις απαντήσεις του χρήστη.
Widget που εμφανίζει ερωτήσεις και δύο κουμπιά για να προχωράει ο χρήστης στην επόμενη και να πάει πίσω.
- questions: list[Question] Η λίστα των ερωτήσεων που θα παρουσιαστούν στον χρήστη
- question_set: str Αναγνωριστικό για το σύνολο των ερωτήσεων, χρησιμοποιείται για τα στατιστικά.
Event handler για το κουμπί εμφάνισης επόμενης ερώτησης. Στην περίπτωση που ο χρήστης βρίσκεται στην προτελευταία ερώτηση η συνάρτηση επίσης αλλάζει τον Event handler του κουμπιού ώστε να χρησιμοποιεί την συνάρτηση submit().
Event handler για το κουμπί εμφάνισης προηγούμενης ερώτησης.
Event handler για το κουμπί υποβολής. Μαζεύει τις ερωτήσεις με τις απαντήσεις του χρήστη και δημιουργεί ένα OverviewListWidget με αυτές.
Widget που εμφανίζει στον χρήστη τα αποτελέσματα της άσκησής του.
-
questions: list[Question] Λίστα ερωτήσεων που έχουν απαντηθεί (δηλαδή που έχουν προκύψει από μια συνάρτηση getQuestion())
-
question_set: str Αναγνωριστικό για το σύνολο των ερωτήσεων, χρησιμοποιείται για τα στατιστικά.
Για κάθε ερώτηση στη λίστα questions φτιάχνει ένα
OverviewQuestionWidget και το εμφανίζει. Μετά ανακτεί της μονάδες
που κέρδισε ο χρήστης από κάθε OverviewQuestionWidget, εμφανίζει ένα
μήνυμα επιτυχίας/αποτυχίας και γράφει τα αποτελέσματα στο αρχείο
results.csv
με το αναγνωριστικό question_set.
Event handler για το κουμπί επιστροφής στην σελίδα επιλογής ασκήσεων.
Widget που εμφανίζει αν μια ερώτηση είναι σωστά απαντημένη όπως και την σωστή απάντηση σε περίπτωση λάθος απάντησης. Υποστηρίζει MultipleChoiceQuestion και FillBlankQuestion.
Κατασκευαστής.
- question: Question Η ερώτηση του widget.
Widget που εμφανίζει 3 MenuButton για 3 διαφορετικά σετ ασκήσεων και ένα MenuButton που επιστρέφει στην αρχική σελίδα.
3.11.1 Exercises1-3 -> None
Οι συναρτήσεις Exercises[1-3] είναι event handlers των MenuButton και φτιάχνουν ένα σετ ασκήσεων που χρησιμοποιούν για να φτιάξουν ένα QuestionWidget.
Event handler για το κουμπί επιστροφής στην αρχική σελίδα.
Widget που εμφανίζει 3 MenuButton για 3 διαφορετικά σετ θεωρίας και ένα MenuButton που επιστρέφει στην αρχική σελίδα.
Τα κουμπιά έχουν event handler που καλούν την συνάρτηση LoadLessons() με το σωστό αναγνωριστικό κεφάλαιο που τους αντιστοιχεί όπως φαίνεται παρακάτω.
lesson1.clicked.connect(lambda _: self.LoadLessons(1))
lesson2.clicked.connect(lambda _: self.LoadLessons(2))
lesson3.clicked.connect(lambda _: self.LoadLessons(3))
- lessonNumber: int Το αναγνωριστικό του κεφαλαίου που θα ανοίξει.
Η συνάρτηση δημιουργεί ένα ChaptersWidget() χρησιμοποιώντας το lessonNumber και το εμφανίζει.
Event handler για το κουμπί επιστροφής στην αρχική σελίδα.
Widget το οποίο εμφανίζει ένα webview στο οποίο φορτώνουμε τα αρχεία θεωρίας των μαθημάτων. Παρέχει 2 κουμπιά ώστε ο χρήστης να επιλέγει την σελίδα που θέλει να διαβάσει και ένα κουμπί που τον επιστρέφει την σελίδα επιλογής θεωρίας.
- ChapNumber: int Αριθμός κεφάλαιου.
- chapNumber: int Αριθμός κεφάλαιου.
Φορτώνει τα μονοπάτια των αρχείων θεωρίας που βρίσκονται στον φάκελο
/resources/lessons/
και ακολουθούν την κανονική έκφραση
“lesson<chapNumber>.*“1.
Event handlers για τα κουμπιά εμφάνισης επόμενης και προηγούμενης σελίδας. Αλλάζουν το αρχείο που εμφανίζεται στο webview.
Event handler για το κουμπί επιστροφής στην σελίδα επιλογής κεφαλαίου.
Widget που εμφανίζει στατιστικά για τα διαγωνίσματα του χρήστη.
- marks: list[float] Λίστα βαθμών
Ενημερώνει το UI με τους βαθμούς στο marks.
Υπολογίζει τους μέσους όρους των βαθμών και καλεί την setLabels().
Βρίσκει τους πιο πρόσφατους βαθμούς και καλεί την setLabels().
Υπολογίζει τους μέγιστους βαθμούς και καλεί την setLabels().
Η εφαρμογή μπορεί να επεκταθεί με διάφορους τρόπους προς πολλές κατευθύνσεις. Σε αυτή την ενότητα θα δούμε κάποιες από αυτές τις κατευθύνσεις.
Για να επεκταθεί η εφαρμογή υπάρχουν κάποιες προυποθέσεις που πρέπει να τηρηθούν.
- Ανάπτυξη εφαρμογών σε python3
- Γνώσεις χρήσης qt5 gui framework
- Γνώσεις χρήσης pandas (για στατιστικά)
- Εγκατάσταση python >= 3.10
- Εγκατάσταση poetry
- Εγκατάσταση git
Παράγωγα έργα πρέπει να ακολουθούν τους όρους του AGPLv3 όπως ορίζονται στο αρχείο LICENSE.
Επιπλέον υλικό θεωρίας μπορεί να δημιουργηθεί δημιουργώντας κατάλληλα
ονομασμένα αρχεία στον φάκελο resources/lessons/
. Πιο συγκεκριμένα
πρέπει να ακολουθούν το πρότυπο “lesson<αριθμόςΚεφαλαίου>.html” με
προσοχή ότι γίνεται λεξικογραφική ταξινόμηση όπου τα μεγαλύτερα ονόματα
έρχονται πρώτα όταν δηλαδή το αρχείο lesson2.1.html
θα εμφανιστεί πριν
το αρχείο lesson2.html
, έτσι προτείνεται το δεύτερο αρχείο να
μετονομαστεί σε lesson2.0.html
. Τέλος θα πρέπει να προστεθεί το
αντίστοιχο κουμπί στην κλάση LessonWidget
Επιπλέον υλικό ασκήσεων μπορεί να δημιουργηθεί στην κλάση Exercises με παρόμοιο τρόπο όπως οι υπάρχουσες. Προσοχή να δοθεί στο text των FillBlankQuestion όπου οι χαρακτήρες ᾽&᾽ σημαίνουν “κενό προς γέμισμα” και ‘\n’ νέα γραμμή.
Η εφαρμογή έχει σχεδιαστεί με την επεκτασιμότητα στο νου άρα οποιαδήποτε λειτουργία είναι πιθανός υλοποιήσημη λόγω της modular δομής της. Για παράδειγμα είναι πολύ απλό να προστεθεί ένα νέο είδος ερώτησης. Απλά θα χρειαστεί:
- class <New>Question
- class <New>QuestionWidget
- υποστήριξη στην ΟverviewQuestionWidget στο match statement
Allaire, JJ, Yihui Xie, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, Hadley Wickham, Joe Cheng, Winston Chang, και Richard Iannone. 2021. rmarkdown: Dynamic Documents for R. https://github.com/rstudio/rmarkdown.
Chacon, Scott, και Ben Straub. 2014. Pro git. Apress.
Poetry core contributors. 2022. ‘Poetry official website’. https://python-poetry.org.
Xie, Yihui, J. J. Allaire, και Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown.
Xie, Yihui, Christophe Dervieux, και Emily Riederer. 2020. R Markdown Cookbook. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown-cookbook.
Footnotes
-
lesson.*: αρχίζει με τους χαρακτήρες ‘lesson’ και ακολουθείτε από έναν αριθμό n ↩