מבוא ל- JavaFx

1. הקדמה

JavaFX היא ספרייה לבניית יישומי לקוח עשירים עם Java. הוא מספק API לעיצוב יישומי GUI שרצים כמעט בכל מכשיר עם תמיכה בג'אווה.

במדריך זה, אנו נתמקד בכיסוי חלק מהיכולות והפונקציונליות העיקריות שלו.

2. JavaFX API

ב- Java 8, 9 ו- 10 אין צורך בהתקנה נוספת כדי להתחיל לעבוד עם ספריית JavaFX. הפרויקט יוסר מה- JDK החל מ- JDK 11.

2.1. ארכיטקטורה

JavaFX משתמשת בצינור גרפי מואץ חומרה לצורך העיבוד, המכונה פּרִיזמָה. יתרה מכך, כדי להאיץ באופן מלא את השימוש בגרפיקה, הוא ממנף תוכנה או מנגנון טיוח חומרה על ידי שימוש פנימי DirectX ו OpenGL.

ל- JavaFX יש תלות בפלטפורמה זכוכית שכבת ערכת כלים חלונות לחיבור למערכת ההפעלה המקורית. היא משתמשת בתור האירועים של מערכת ההפעלה כדי לתזמן את השימוש בשרשור. כמו כן, הוא מטפל בצורה לא סינכרונית בחלונות, אירועים, טיימרים.

ה כְּלֵי תִקְשׁוֹרֶת ו אינטרנט מנועי מאפשרים הפעלת מדיה ותמיכה ב- HTML / CSS.

בואו נראה איך נראה המבנה העיקרי של יישום JavaFX:

כאן אנו מבחינים בשני מכולות עיקריות:

  • שלב הוא המכולה הראשית ונקודת הכניסה של היישום. הוא מייצג את החלון הראשי והועבר כטיעון של הַתחָלָה() שיטה.
  • סְצֵינָה הוא מיכל להחזקת אלמנטים של ממשק המשתמש, כגון תצוגות תמונה, לחצנים, רשתות, TextBoxes.

ה סְצֵינָה ניתן להחליף או להחליף לאחר סְצֵינָה. זה מייצג גרף של אובייקטים היררכיים, המכונה a סְצֵינָה גרָף. כל אלמנט באותה היררכיה נקרא צומת. לצומת יחיד יש מזהה, סגנון, אפקטים, מטפלים באירועים, מצב.

בנוסף, ה- סְצֵינָה מכיל גם את מיכלי הפריסה, התמונות, המדיה.

2.2. חוטים

ברמת המערכת, ה- JVM יוצר שרשורים נפרדים להפעלת היישום ולעיבודו:

  • פּרִיזמָה חוט טיוח - אחראי על עיבוד תרשים סצנה לְחוּד.
  • חוט יישום - הוא החוט העיקרי של כל יישום JavaFX. כל הצמתים והרכיבים החיים מצורפים לשרשור זה.

2.3. מעגל החיים

ה javafx.application.Application בכיתה יש את השיטות הבאות במחזור החיים:

  • init () - נקרא לאחר יצירת מופע היישום. בשלב זה, ה- API של JavaFX עדיין לא מוכן, ולכן איננו יכולים ליצור כאן רכיבים גרפיים.
  • התחלה (שלב הבמה) - כל המרכיבים הגרפיים נוצרים כאן. גַם, החוט המרכזי לפעילויות הגרפיות מתחיל כאן.
  • תפסיק() - נקרא לפני כיבוי היישום; לדוגמא, כאשר משתמש סוגר את החלון הראשי. כדאי לבטל שיטה זו לניקוי כלשהו לפני סיום היישום.

הסטטי לְהַשִׁיק() השיטה מפעילה את יישום JavaFX.

2.4. FXML

JavaFX משתמשת בשפת סימון FXML מיוחדת ליצירת ממשקי התצוגה.

זה מספק מבנה מבוסס XML להפרדת התצוגה מההיגיון העסקי. XML מתאים יותר כאן, מכיוון שהוא מסוגל לייצג באופן טבעי את תרשים סצנה הִיֵרַרכִיָה.

לבסוף, כדי להעמיס את .fxml קובץ, אנו משתמשים ב- FXMLLoader מחלקה, המביאה לגרף האובייקטים של היררכיית הסצנה.

3. תחילת העבודה

כדי לקבל מעשי, ו בואו לבנות יישום קטן המאפשר חיפוש ברשימת אנשים.

ראשית, בואו נוסיף a אדם מחלקת מודלים - לייצג את התחום שלנו:

אדם בכיתה ציבורית {מזהה פרטי SimpleIntegerProperty; שם פרטי SimpleStringProperty; פרטי SimpleBooleanProperty הוא מועסק; // גטרים, סטרים}

שימו לב איך, לעטוף את int, מחרוזת ו בוליאני ערכים, אנו משתמשים ב- SimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty שיעורים ב javafx.beans.property חֲבִילָה.

לאחר מכן, בואו ניצור את רָאשִׁי כיתה המרחיבה את יישום שיעור מופשט:

מחלקה ציבורית ראשי מאריך את היישום {@Override Public void start (Stage primaryStage) זורק חריג {FXMLLoader loader = FXMLLoader new (Main.class.getResource ("/ SearchController.fxml")); עמוד AnchorPane = (AnchorPane) loader.load (); סצנת סצנה = סצנה חדשה (עמוד); primaryStage.setTitle ("הכותרת הולכת לכאן"); primaryStage.setScene (סצנה); primaryStage.show (); } ראשי ריק סטטי ציבורי (String [] args) {launch (args); }}

המעמד העיקרי שלנו עוקף את הַתחָלָה() שיטה, שהיא נקודת הכניסה לתוכנית.

אז ה FXMLLoader טוען את היררכיית גרף האובייקטים מ- SearchController.fxml לתוך ה AnchorPane.

לאחר התחלת חדש סְצֵינָה, הגדרנו אותו לראשוני שלב. הגדרנו גם את הכותרת לחלון שלנו ו- הופעה() זה.

שים לב שכדאי לכלול את ה- רָאשִׁי() שיטה כדי להיות מסוגל להריץ את קובץ ה- JAR ללא משגר JavaFX.

3.1. תצוגת FXML

בואו נצלול עמוק יותר לתוך ה SearchController קובץ XML.

ליישום החיפוש שלנו, נוסיף שדה טקסט להזנת מילת המפתח ולחצן החיפוש:

AnchorPane הוא מיכל השורש כאן, והצומת הראשון בהיררכיית הגרפים. בזמן שינוי גודל החלון, הוא ימקם את הילד מחדש לנקודת העיגון שלו. ה fx: בקר תכונה מחווטת את מחלקת Java עם הסימון.

יש כמה פריסות מובנות אחרות:

  • BorderPane - מחלק את הפריסה לחמישה חלקים: עליון, ימין, תחתון, שמאל, מרכז
  • HBox - סדר את רכיבי הילד בלוח אופקי
  • VBox - צמתי הילד מסודרים בטור אנכי
  • GridPane - שימושי ליצירת רשת עם שורות ועמודות

בדוגמה שלנו, בתוך האופקי HBox פאנל, השתמשנו ב- תווית למקם טקסט, שדה טקסט עבור הקלט, ו לַחְצָן. עם fx: id אנו מסמנים את האלמנטים כדי שנוכל להשתמש בהם בהמשך בקוד Java.

ה VBox החלונית היא המקום בו נציג את תוצאות החיפוש.

ואז, כדי למפות אותם לשדות Java - אנו משתמשים ב- @FXML ביאור:

מחלקה ציבורית SearchController {@FXML searchField פרטית TextField; @FXML כפתור פרטי searchButton; @FXML פרטי נתונים VBox Container; @FXML פרטית TableView tableView; @FXML חלל פרטי לאתחל () {// searchButton.setText בחלונית החיפוש ("חיפוש"); searchButton.setOnAction (אירוע -> loadData ()); searchButton.setStyle ("- fx-background-color: # 457ecd; -fx-text-fill: #ffffff;"); initTable (); }}

לאחר שאכלס את @FXML שדות מסומנים, לְאַתחֵל() ייקרא אוטומטית. כאן אנו יכולים לבצע פעולות נוספות על רכיבי ממשק המשתמש - כמו רישום מאזינים לאירועים, הוספת סגנון או שינוי מאפיין הטקסט.

בתוך ה initTable () שיטה ניצור את הטבלה שתכיל את התוצאות, עם 3 עמודות, ונוסיף אותה ל- dataContainer VBox:

initTable () ריק ריק () {tableView = TableView חדש (); TableColumn id = חדש TableColumn ("מזהה"); TableColumn name = TableColumn new ("NAME"); TableColumn מועסק = TableColumn חדש ("מועסק"); tableView.getColumn (). addAll (id, שם, מועסק); dataContainer.getChildren (). הוסף (tableView); }

לבסוף, כל ההיגיון המתואר כאן יפיק את החלון הבא:

4. ממשק API מחייב

כעת, לאחר הטיפול בהיבטים הוויזואליים, נתחיל להסתכל על נתונים מחייבים.

ממשק ה- API המחייב מספק כמה ממשקים המודיעים לאובייקטים כאשר מתרחש שינוי ערך של אובייקט אחר.

אנו יכולים לאגד ערך באמצעות ה- לִקְשׁוֹר() שיטה או על ידי הוספת מאזינים.

כריכה חד כיוונית מספקת כריכה לכיוון אחד בלבד:

searchLabel.textProperty (). bind (searchField.textProperty ());

כאן, כל שינוי בשדה החיפוש יעדכן את ערך הטקסט של התווית.

לשם השוואה, כריכה דו-כיוונית מסנכרנת את הערכים של שני מאפיינים בשני הכיוונים.

הדרך האלטרנטיבית לכריכת השדות היא ChangeListeners:

searchField.textProperty (). addListener ((נצפה, oldValue, newValue) -> {searchLabel.setText (newValue);});

ה נצפה ממשק מאפשר התבוננות בערך האובייקט לצורך שינויים.

כדי להדגים זאת, היישום הנפוץ ביותר הוא javafx.collections.ObservableList מִמְשָׁק:

ObservableList masterData = FXCollections.observableArrayList (); תוצאות ObservableList = FXCollections.observableList (masterData);

כאן, כל שינוי במודל כמו הכנסה, עדכון או הסרה של האלמנטים, יודיע על בקרות ממשק המשתמש באופן מיידי.

ה קובץ מקור הרשימה תכיל את הרשימה הראשונית של אדם אובייקטים, ורשימת התוצאות תהיה הרשימה שנציג עם החיפוש.

עלינו גם לעדכן את initTable () שיטה לאגד את הנתונים בטבלה לרשימה הראשונית, ולחבר כל עמודה ל- אדם שדות כיתה:

initTable (ריק) initTable () {tableView = TableView חדש (FXCollections.observableList (masterData)); TableColumn id = חדש TableColumn ("מזהה"); id.setCellValueFactory (PropertyValueFactory חדש ("id")); TableColumn name = TableColumn new ("NAME"); name.setCellValueFactory (PropertyValueFactory חדש ("שם")); TableColumn מועסק = TableColumn חדש ("מועסק"); employ.setCellValueFactory (PropertyValueFactory חדש ("הוא עובד")); tableView.getColumn (). addAll (id, שם, מועסק); dataContainer.getChildren (). הוסף (tableView); }

5. מקביליות

עבודה עם רכיבי ממשק המשתמש בגרף סצנה אינה בטיחותית הברגה, מכיוון שניתן לגשת אליה רק ​​משרשור היישום. ה javafx.concurrent החבילה כאן כדי לסייע ברב-הברגה.

בואו נראה כיצד נוכל לבצע את חיפוש הנתונים בשרשור הרקע:

חלל ריק פרטי () {מחרוזת searchText = searchField.getText (); מְשִׁימָה משימה = משימה חדשה() {@Override מוגן בשיחת ObservableList () זורק Exception {updateMessage ("טוען נתונים"); להחזיר FXCollections.observableArrayList (masterData .stream () .filter (ערך -> value.getName (). toLowerCase (). מכיל (searchText)) .collect (Collectors.toList ())); }}; }

כאן אנו יוצרים משימה חד פעמית javafx.concurrent.Task להתנגד ולדרוס את שִׂיחָה() שיטה.

ה שִׂיחָה() השיטה פועלת כולה על שרשור הרקע ומחזירה את התוצאה לשרשור היישום. פירוש הדבר שכל מניפולציה של רכיבי ממשק המשתמש בשיטה זו תביא למעט חריג בזמן ריצה.

למרות זאת, updateProgress (), updateMessage () ניתן להתקשר לעדכון פריטי שרשור היישום. כאשר מדינת המשימה עוברת למצב מוצלח, onSucceeded () מטפל באירועים נקרא משרשור היישום:

task.setOnSucceeded (אירוע -> {תוצאות = task.getValue (); tableView.setItems (FXCollections.observableList (תוצאות));}); 

באותו שיחה חוזרת, עדכנו את tableView נתונים לרשימת התוצאות החדשה.

ה מְשִׁימָה הוא ניתן לרוץאז כדי להתחיל בזה אנחנו צריכים רק להתחיל חדש פְּתִיל עם ה מְשִׁימָה פָּרָמֶטֶר:

Thread Th = Thread חדש (משימה); th.setDaemon (נכון); th.start ();

ה setDaemon (נכון) דגל מציין שהחוט יסתיים לאחר סיום העבודה.

6. טיפול באירועים

אנו יכולים לתאר אירוע כפעולה שעשויה להיות מעניינת ליישום.

לדוגמא, פעולות משתמש כמו לחיצות עכבר, לחיצות מקשים, שינוי גודל החלון מטופלות או מתבצעות על ידי javafx.event.Event מחלקה או כל אחת משתי קבוצות המשנה שלה.

כמו כן, אנו מבחינים בשלושה סוגים של אירועים:

  • InputEvent - כל סוגי פעולות המפתח והעכבר כמו KEY_PRESSED, KEY_TYPED, KEY_RELEASED אוֹ MOUSE_PRESSES, MOUSE_RELEASED
  • ActionEvent - מייצג מגוון פעולות כמו ירי א לַחְצָן או גימור א KeyFrame
  • WindowEventWINDOW_SHOWING, WINDOW_SHOWN

להדגים, שבר הקוד שלמטה תופס את אירוע הלחיצה על להיכנס מקש מעל שדה חיפוש:

searchField.setOnKeyPressed (אירוע -> {אם (event.getCode (). שווה (KeyCode.ENTER)) {loadData ();}});

7. סגנון

אנו יכולים לשנות את ממשק המשתמש של יישום JavaFX על ידי יישום עיצוב מותאם אישית עליו.

כברירת מחדל, JavaFX משתמש modena.css כמשאב CSS לכל היישום. זה חלק מה- jfxrt.jar.

כדי לעקוף את סגנון ברירת המחדל, אנו יכולים להוסיף גיליון סגנונות לסצנה:

scene.getStylesheets (). הוסף ("/ search.css");

אנו יכולים גם להשתמש בסגנון מוטבע; לדוגמא, כדי להגדיר מאפיין סגנון עבור צומת ספציפי:

searchButton.setStyle ("- fx-background-color: slateblue; -fx-text-fill: white;");

8. מסקנה

כתיבה קצרה זו מכסה את היסודות של JavaFX API. עברנו את המבנה הפנימי והצגנו יכולות מפתח בארכיטקטורה, מחזור החיים והרכיבים שלו.

כתוצאה מכך למדנו וכעת אנו יכולים ליצור יישום GUI פשוט.

וכמו תמיד, קוד המקור המלא של ההדרכה זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found