פרק 5 - ממשקי משתמש
תוכן הפרק:
חבילות הספריה הגרפית רכיבים כפתור תווית רכיבי טקסט תיבת סימון בחירה רשימה פעולות על הרכיבים תפריטים תפריט צף מודל הארועים ארועים שכיחים ומאזיניהם ממשקים שכיחים סוגי ארועים שכיחים מתאמים תיבות דו שיח
חבילות (packages)
הספריות בג'אווה מאורגנות בחבילות (packages), כשכל חבילה היא אוסף של מחלקות. כל מחלקה יכולה לקרוא אוטומטית למחלקות ולפונקציות של מחלקות שנמצאות באותה חבילה כמוה. בהגדרת התוכנית ניתן לשייך את המחלקות שלה לחבילה מסויימת, ע"י שימוש במילה השמורה package ונתינת שם לחבילה. לדוגמא:
כל המחלקות שבקובץ שיצרנו, a ו b במקרה שלנו, תהיינה שייכות לחבילה newpack. אם לא נגדיר שום חבילה יגדיר המהדר את החבילה לחבילה חסרת שם כרצונו.
שימוש במחלקות מחבילות אחרות
כדי לנצל את המחלקות שהוכנו כבר בשפה, ניתן ליבא את החבילה ע"י שימוש במילה import וכתיבת שם המחלקה המפורש שבה נרצה להשתמש. אחת החבילות הפופולריות ביותר תהיה חבילת awt - חבילת הספריה הגרפית (ראה להלן). שימוש במחלקות מתוך החבילה הנ"ל יעשה כך:
|
כלומר: ייבאנו את המחלקה Frame, שבספרייה הגרפית, שנמצאת במחלקת הבסיס java. אם נרצה להשתמש בכמה מחלקות מהספריה הגרפית, נוכל בקיצור לכתוב:
|
|
כלומר: ייבאנו את כל המחלקות שיש בתת הספריה הגרפית של הספריה הראשית. שימוש אפשרי בתוכנית במחלקות יעשה, למשל, ע"י ירושת התכונות של המחלקה, או קריאה לעצמים מסוג המחלקה תוך כדי התוכנית. לדוגמא:
|
|
פה יבאנו את הספריה הגרפית על מחלקותיה, בנינו מחלקה a שמרחיבה את מחלקת Frame ובתוכה הצהרנו על עצם p מסוג panel.
חבילות לדוגמא שקיימות בג'אווה
יצירת תוכניות מבוססות אינטרנט
|
java.applet
|
|
הספריה הגרפית, לציור גרפיקה וממשקי משתמש
|
java.awt
|
|
לפונקציות של קלט פלט
|
java.io
|
|
תמיכה כללית (מיובאת אוטומטית)
|
java.lang
|
|
פונקציות מתמטיות
|
java.math
|
|
הספריה הגרפית
ג'אווה מספקת למשתמש ממשקי גרפיקה מובנים בשפה, דבר המקנה יתרון עצום לתוכנית, מכיוון שכך הממשק הגרפי אינו תלוי במחשב שבו עובדים ובמערכת ההפעלה. ספריית הגרפיקה נקראת abstract window toolkit) awt), ובעזרת שימוש בה המתכנת יוכל ליצור חלונות, לצייר צורות גיאומטריות שונות, ליצור כפתורים למיניהם, תפריטים נוחים וכו'.
הרכיבים היסודיים בספריה הם:
- Component - רכיב. כל סוגי הרכיבים שמאפשרים ממשק עם המשתמש. למשל: כפתור, כפתור רדיו, תיבות גלילה, רשימה שאפשר לבחור ממנה.
- Container - מיכל. רכיב שמכיל רכיבים אחרים (למשל מהסוג הקודם) למשל: חלון מסגרת - frame, תיבת דו שיח.
- Menu - תפריטים. השורה בראש החלון, המכילה פקודות כמו: קובץ, עריכה, עזרה וכו'.
כמו כן קיים מודל הארועים (event model) - המנגנון ששולט על דרך תגובת התוכנית לארוע שהתרחש. כלומר אם בנינו מסגרת המכילה שני כפתורים, בעזרת מודל הארועים נשלוט במה שיקרה בלחיצה על כל אחד מהכפתורים האלה. העיקרון בבנית התוכנית יהיה "הכלה": נגדיר מיכל (container) כלשהו, למשל מסגרת חלון, שבו "נשים" כל מיני רכיבים (Components) כמו כפתורים למשל, ע"י שימוש בפונקצית ()add שמוגדרת במחלקה שלו, ולבסוף נגדיר מאזין לרכיב - listener, כלומר קשר בין הרכיב לתוכנית, כך שפעולה על הרכיב, כמו הקלקה עליו באמצעות העכבר, תעשה משהו ספציפי בתוכנית. נראה תוכנית לדוגמא:
|
הסבר לתוכנית:
יבאנו את הספריה הגרפית (ע"י import). הצהרנו על המחלקה App, שבה הצהרנו על עצם f, מיכל מסוג Frame. המחרוזת שהועברה לקונסטרקטור של העצם היא תווית הזיהוי שתתנוסס מעל החלון: first application. בקונסטרקטור של המחלקה עצמה הצהרנו בהתחלה על צורת ההכנסה של הרכיבים לתוך החלון ע"י שימוש ב setLayout, כך:
קיימים מספר סוגים של סידורים אוטומטיים של החלון:
- FlowLayout - היא אחת מהאפשרויות לסידור הרכיבים במיכל. הרכיבים יונחו לפי הסדר משמאל לימין.
- BorderLayout - ברירת המחדל לחלון, הרכיבים יונחו לפי סדר "גאוגרפי": צפון (למעלה),דרום (למטה), מזרח (ימין), מערב (שמאל), מרכז.
- GridLayout - המסגרת תחולק לשורות וטורים.
דוגמא:
הסבר: קבענו את מספר השורות ל - 2 ומספר העמודות ל - 0, כלומר הרכיבים יסודרו בשתי שורות, ומספר העמודות יקבע עפ"י מספר הרכיבים. בהמשך נראה פונקציות שבעזרתן ניתן לקבוע גם מיקום מדויק של עצם בחלון ולא ע"פ סידור אוטומטי. בנוסף, הגדרנו שני כפתורים:
המחרוזת שבהגדרת הכפתור היא התווית שתכתב עליו. אחרי הגדרת 2 הכפתורים הוספנו אותם לחלון עצמו ע"י שימוש בפונקציה add:
סיימנו את יצירת החלון, שבו יהיו 2 כפתורים. נשאר לנו רק לגרום לחלון להופיע ואת זה נעשה ע"י פקודת setVisible כך:
עכשיו כל יצירת עצם מסוג App תיצור אוטומטית חלון ובו 2 כפתורים על המסך, וזה בדיוק מה שעשינו בפונקציה הראשית של המחלקה (main) - יצרנו מופע שלה. עדיין לא הגדרנו שום פעולה שתעשה ע"י הכפתורים שהגדרנו, כך שהם בעצם "חופשיים".
רכיבים - components
קיימים מספר סוגים של רכיבים שכיחים:
כפתור - Button
כפתור, שלחיצה עליו תיצור ארוע. ניתן לתת לכפתור ערך אמת או שקר: בערך שקר הכפתור יהיה לא פעיל, ויהיה אפשר בשלב כלשהו להפעיל אותו. נראה את הקוד שלו, כפי שכתבנו בתוכנית, ונוסיף "ניטרול" של אחד הכפתורים:
יצרנו שני כפתורים, את השני הפכנו לכפתור לא פעיל, והוספנו אותם למסגרת f.
תווית - Label
תוית תשמש לכתיבת טקסט שאינו משתנה בחלון. בקונסטרקטור של התוית יופיע הטקסט הרצוי בתוית. נוסיף גם תוית לתוכנית:
הוספנו לחלון תוית, שעליה יהיה כתוב my first label.
רכיבי טקסט - text components
קיימים שני סוגי רכיבי טקסט בסיסיים: שדה טקסט, TextField, שבו ניתן למשתמש לכתוב שורת טקסט אחת אחרי שהחלון כבר הופעל, ואזור טקסט, TextArea, שבו ניתן למשתמש לכתוב כמה שורות טקסט בחלון. נוסיף רכיבים כאלה לתוכנית:
הוספנו שדה טקסט באורך 20 תוים, ואזור טקסט בגודל 10 שורות ובאורך 20 תוים.
תיבת סימון - Checkbox
תיבה שאפשר לסמן בה בחירות שונות. אפשר ליצור תיבות בודדות, או ליצור כמה תיבות שיושבות בתוך "קבוצת תיבות", CheckboxGroup, כך שרק אחת מכל הקבוצה תוכל להיות מסומנת בזמן נתון. נוסיף רכיבים לתוכנית:
הצהרנו על 3 תיבות סימון ועל קבוצת תיבות סימון אחת. את אחת מתיבות הסימון השארנו חופשיה, ואת השתים האחרות איגדנו יחד תחת הקבוצה, כשאת הראשונה קבענו לתיבה שנבחרה.
בחירה - Choice
בחירת אפשרות אחת מתוך "רשימה קופצת" (popup) של אפשרויות. נוסיף לתוכנית:
הוספנו רשימה, שבה יופיעו ימי השבוע, ויהיה ניתן לבחור אחד מביניהם.
רשימה - List
בדומה לבחירה, אבל ניתן יהיה לבחור מספר אפשרויות:
הוספנו רשימה, שממנה יהיה ניתן לבחור מספר ספרות.
לסיום התוכנית, נקבע את גודל החלון, ע"מ שבעת ההרצה נראה את תוכנו, וזאת ע"י הפקודה:
נראה שוב כיצד תיראה התוכנית בשלמותה:
|
התוצאה תראה בדומה לזו:
|
|
פעולות על הרכיבים
לכל אחד מהרכיבים מוגדרות גם פעולות רבות (פונקציות במחלקה Component), שמאפשרות לשנות הגדרות רבות שלו, למשל מיקום וגודל, עדכון וציור הרכיב וכו'. להלן טבלה של הפעולות העיקריות:
קטגוריה
|
פונקציה
|
תיאור
|
מיקום הרכיב וגודלו
|
( )get/setBounds
|
קבלת/קביעת מיקום וגודל הרכיב
|
|
( )get/setFont
|
קבלת /קביעת הגופן של הרכיב
|
|
( )get/setSize
|
קבלת/קביעת גודל הרכיב
|
|
( )contains
|
האם הרכיב מכיל נקודה נתונה
|
עידכון ציור והדפסת הרכיב
|
( )invalidate
|
הפיכת הרכיב ללא תקף. צביעה מחדש
|
|
( )paint
|
צביעת הרכיב לחלון
|
|
( )repaint( ) ,update
|
עדכון תצוגת הרכיב ,קורא ל paint
|
|
( )print
|
הדפסת הרכיב
|
פרמטרי תצוגה
|
( )get/setCursor
|
קבלת/קביעת הסמן שיוצג במעבר כל רכיב
|
|
( )get/setLocation
|
קבלת/קביעת המיקום של הרכיב
|
|
( )get/setName
|
קבלת/קביעת שם הרכיב
|
|
( )is/setVisible
|
קריאת/קביעת הרכיב כנראה
|
טיפול בארועים
|
( )addMouseListener
|
הוספת מאזין לארועי העכבר (למשל לחיצה)
|
|
( )addKeyListener
|
הוספת מאזין לארועי מקלדת (הקשת מקש)
|
|
( )addFocuseListener
|
הוספת מאזין לארועי פוקוס (קבלה, איבוד)
|
הערה: אפשר לדמות יצירת עצם מסוג שדה טקסט ליצירת מעבד תמלילים פרימיטיבי.
מיכלים - containers
מיכלים הם רכיבים שמכילים רכיבים אחרים (כולל מיכלים נוספים).
סוגי מיכלים שימושיים
- מסגרת - Frame: חלון רגיל עם מסגרת, כפתורי סגירה הגדלה והקטנה ותפריטים.
- חלון - Window: כמו Frame, ללא מסגרת.
- תיבת דו שיח - Dialog: שטח שישמש לדו שיח.
- פנל - Panel: שטח שעליו יורכבו כמה מרכיבים גרפיים, בד"כ נשתמש בו בתוך מסגרת אחרת.
- אפלט - Applet: מיוחד לשפת html בעיקר לישומי אינטרנט.
פונקציות עקריות לשימוש במיכל
- ( )add - הוספת רכיב למיכל.
- ( )getComponentCount - קבלת מספר הרכיבים במיכל.
- ( )getComponent - קבלת מערך הרכיבים במיכל.
- ( )get/setLayout - קבלת/קביעת סגנון סידור הרכיבים.
- ( )removeAll - הסרת כל הרכיבים המוכלים.
דוגמא לשימוש במיכלים
לדוגמא לשימוש במיכלים, נוסיף לתוכנית שכתבנו עוד כמה שורות:
|
|
|
במקום להוסיף את הכפתורים לחלון מיידית, נבנה פנל חדש, נוסיף את הכפתורים אליו, ואת הפנל עצמו נוסיף לחלון:
|
|
|
בדומה, נוסיף את התוית לפנל נפרד. ההבדל הוא שפה לא קבענו את סידור הנתונים בפנל, אלא נתנו לברירת המחדל לעבוד. התוצאה בשני המקרים שווה.
|
|
|
את שדות הכתיבה ותיבות הבחירה השארנו על המסגרת עצמה:
|
|
|
את הקריאה לתיבות הסימון נעשה בצורה קצת שונה, ע"י פונקציה שנגדיר בהמשך ופה רק נקרא לה:
|
|
|
נשאר רק להצהיר על ציור החלון:
|
|
|
הפונקציה לציור תיבות הסימון תקבל כפרמטר עצם מסוג container, שהוא מחלקת הבסיס לכל המכלים, וכך לא נהיה מוגבלים לעצם מסוג Panel בלבד כמו שהגדרנו בתוכנית.
|
|
|
נצהיר על הסידור כסידור חמדני, שיצור שתי עמודות, ונוסיף אל הפנל את תיבות הסימון:
|
|
|
השתמשנו בכמה מיכלים על המכל הראשי, כשהתוצאה הוויזואלית שונה רק במקצת מהתוצאה למעלה:
|
|
|
|
תפריטים - Menus
התפריטים היא אותה רשימת אפשרויות שנמצאת בחלקו העליון של החלון, שבעזרתה ניתן לבצע פעולות שונות על היישום, בקלות ופשטות.
סוגי התפריטים
- תיבת התפריטים (MenuBar) - הכותרת בראש החלון עם רשימת קבוצת התפריטים (קובץ, עריכה, תצוגה...).
- תפריט (Menu) - רשימת התפריטים מתחת לכותרת הראשית, מוכל בתיבת התפריטים הראשית. ניתן ליצור תפריט בתוך תפריט וכו'.
- פריט (MenuItem) - פריט ספציפי מתוך התפריט, אשר יצור את הארוע המבוקש ע"י לחיצה עליו (קיים גם פריט מסוג תיבת סימון - CheckboxMenuItem).
- תפריט צץ (PopupMenu) - תפריט ש"קופץ" ממקום כלשהו בחלון עפ"י הלחיצה.
דוגמא:
נבנה תוכנית לדוגמא שבה כמה תפריטים.
נייבא, חוץ מהספריה הגרפית, גם את ספריית הארועים, בה נדון בהמשך.
|
|
|
נשתמש במנגנון חדש/ישן: נגדיר את המחלקה שלנו כיורשת של המחלקה Frame וכך נחסוך את הצורך ליצור עצם מסוג Frame במחלקה עצמה.
|
|
|
ניצור את התפריטים בפונקציה ()init:
|
|
|
נקבע את גודל החלון, וניצור את תפריט "קובץ" עם תתי התפריטים המתאימים:
|
|
|
ניצור את תפריט "עריכה":
|
|
|
ניצור את תפריט "options", ולו ניצור שני תתי תפריטים: "settings" ו “colors”:
|
|
|
ניצור את תפריט ה "help", ונקבע את התפריט כתפריט של החלון, באמצעות הפונקציה setMenuBar:
|
|
|
נבנה את הקונסטרקטור: נתן כותרת ע"י קריאה לקונסטרקטור האבא, ונקרא לפונקציה init:
|
|
|
לסיום, נבנה עצם מסוג Menus בפונקציה הראשית:
|
|
|
התוצאה תראה בדומה לזו:
|
|
|
הוספת מקשי קיצור - shortcuts
אם נרצה להוסיף מקשי קיצור לתפריטים שהגדרנו, שלחיצה עליהם תפתח את התפריט המתאים, נגדיר בפונקציה להוספת התפריט, גם עצם מסוג MenuShortcut. לדוגמא, נוסיף מקשי קיצור לתפריט file:
|
ונקבל:
|
|
|
הוספנו מקש קיצור ל new ע"י לחיצה על Ctrl+N וכו'. KeyEvent.VK_N - הקוד של המקש N.
תפריט צף - PopupMenu
נרצה שכל לחיצה על המקש הימני תקפיץ לנו תפריט תמיכה במקום הלחיצה, כמקובל בהרבה תוכנות. כדי לעשות זאת נאלץ להשתמש בפונקציות של ספריית הארועים, אותה נראה בהמשך. נוסיף לתוכנית עצם מסוג PopupMenu ונאתחל גם אותו בפונקציה ()init, ובנוסף נוסיף פונקציה שתציג את התפריט הקופץ בכל אירוע לחיצה ימנית על העכבר. התוכנית (המבוססת על הקודמת) תראה כך:
הפונקציה processMouseEvent קשורה למודל הארועים, ועוד נדבר עליו.
מודל הארועים
אמנם כבר הגדרנו עצמים גרפיים שונים (כפתור, רשימה וכו'), אבל עדיין לא נתנו שום משמעות לפעולות שנעשות בהם. כלומר, לא הגדרנו מה יקרה - איזו פעולה, פונקציה וכיו"ב - בעת לחיצה על כפתור, או בחירת פריט מרשימה. המנגנון שמטפל בזה נקרא מודל הארועים. השיטה: בכל ארוע יזום שקשור לעצם גרפי, למשל לחיצה על כפתור, נוצר עצם עקב הארוע. נגדיר "מאזין", עצם כלשהו מסוג ActionEvent ש"יקשיב" לארוע שהתרחש וע"י ממוש של הממשק המתאים (למשל ActionListener במקרה של לחיצה) יקבע מה תהיה התוצאה של הארוע (ע"י קריאה לפונקציה המתאימה במחלקת העצם, פונקציה שתהיה חייבת להיות ממומשת ע"י המחלקה, כי היא מממשת את הממשק [תזכורת: ממשק = מחלקה וירטואלית טהורה, שחייבים לממש את כל הפונקציות שלה] ).
דוגמא:
הסבר: יצרנו שתי מחלקות, הראשית היא מחלקת Active, בה הרחבנו את מחלקת Frame: בפונקציית האתחול של המחלקה (init) הצהרנו על מאזין מסוג MyActionListener (המחלקה השניה), ובנינו שני כפתורים, שלשניהם נתנו את המאזין al (השתמשנו באותו מצביע b לבניית שני הכפתורים, אבל ההבדל בין הכפתורים יהיה עפ"י תכונת ה ActionCommand שלהם, כלומר שורת הפקודה שתועבר בעת יצירת עצם מסוג ארוע, שלא חייב להיות דווקא מחרוזת, אך במקרה שלנו הוא כזה). המחלקה השניה, MyActionListener, מממשת את הממשק ActionListener ע"י "דריסת" הפונקציה actionPerformed. קבענו פעולה שונה ללחיצה על כל אחד משני הכפתורים (הדפסת הודעה מתאימה). נוכל לקצר את כתיבת התוכנית אם באותה מחלקה גם נרחיב את Frame וגם נממש את ממשק ActionListener (חסכנו גם עוד שורה בקריאה מקוצרת לפונקציה add שמוסיפה את הכפתור ל Frame). נראה איך התוכנית תראה:
השתמשנו במצביע this, שמצביע על העצם עצמו, כדי לקבוע את המסגרת עצמה כמאזינה לארוע. הפעולה שתינקט בארוע הוגדרה בפונקציה actionPerformed, כמו מקודם, אלא שכעת הפונקציה היא חלק מהמחלקה.
טבלת ארועים שכיחים והמאזינים שלהם:
מקור ארוע
|
מאזין
|
Window
|
WindowListener
|
Button
|
ActionListener
|
List
|
MenuItem
|
TextField
|
Choice
|
ItemListener
|
Checkbox
|
CheckboxMenuItem
|
List
|
טבלת ממשקים שכיחים והמחלקות שלהם:
תזכורת: בממשק חייבים לממש כל מתודה:
ממשק
|
מתודות בממשק והעצמים שהן מקבלות
|
ActionListener
|
(actionPerformed (ActionEvent e
|
FocusListener
|
(focusGained(FocusEvent e
|
(focusLost(FocusEvent e
|
ItemListener
|
(itemStateChanged(ItemEvent e
|
KeyListener
|
(keyPressed (KeyEvent e
|
(keyReleased (KeyEvent e
|
(keyTyped(KeyEvent e
|
MouseListener
|
(mouseClicked(MouseEvent e
|
(mouseEntered(MouseEvent e
|
(mouseExited(MouseEvent e
|
(mousePressed(MouseEvent e
|
(mouseReleased(MouseEvent e
|
MouseMotionListener
|
(mouseDragged(MouseEvent e
|
(mouseMoved(MouseEvent e
|
WindowListener
|
(windowActivated(WindowEvent e
|
(windowClosed(WindowEvent e
|
(windowClosing(WindowEvent e
|
(windowDeactivated(WindowEvent e
|
(windowDeiconified (WindowEvent e
|
(windowIconified(WindowEvent e
|
(windowOpened(WindowEvent e
|
טבלת סוגי ארועים שכיחים:
סוג מרכיב
|
ארוע
|
ComponentEvent
|
( )getID
|
( )getComponent
|
MouseEvent
|
( )getX
|
( )getY
|
( )getPoint
|
KeyEvent
|
( )getKeyCode
|
( )getKeyChar
|
FocusEvent
|
( )getID
|
ContainerEvent
|
( )getChild
|
( )getContainer
|
WindowEvent
|
( )getID
|
מתאמים (adapters)
ע"מ לקצר את התוכנית, קיים בג'אווה מנגנון מתאמים (adapters). עד עכשיו, בהגדרת ממשק, נאלצנו לממש את כל הפונקציות שלו, וכך כתבנו "סתם" פונקציות ריקות, בשביל למלא את מנגנון הממשק. כדי לשפר זאת הגדירו בג'אווה מתאמים, שהן מחלקות מוכנות מראש שמממשות את כל הפונקציות בממשק, באופן ריק. מעכשיו ע"מ להגדיר ממשק נשתמש ישר במתאם שלו, וכך נוכל לדרוס רק את הפונקציות הדרושות לנו, כאשר שאר הפונקציות ימומשו ע"י המתאם. לדוגמא:
- MouseAdapter מתאם לממשק MouseListener
- MouseMotionAdapter מתאם לממשק MouseMotionListener
כעת, במקום להצהיר על מחלקה כמממשת ממשק כלשהו, נשתמש בתוכנית רק במתאם למחלקה.
|
תיבות דו שיח - Dialog
תיבות דו שיח הן כלי פשוט ליצירת קשר עם המשתמש. דרכן המשתמש יכול להכניס קלט לתוכנית, לקבוע ערכים שונים, שבעזרתם תרוץ התוכנית, לאשר הודעות וכיו"ב. תיבות דו שיח הנן חלק ממחלקות המיכל, ובעצמן מוכלות בחלון ראשי - Frame.
תיבות מודוליות
תיבות דו-שיח מודוליות הנן תיבות שלא מאפשרות לעשות פעולה נוספת, בחלון שיצר אותן, כל זמן שהתיבה לא נסגרה. דוגמא לתיבת דו שיח שתקבל פרמטרים של חלפים לרכב: המחלקה Dia תירש את Dialog ותממש את ActionListener.
|
נוסיף משתנים אליהם יועתקו הנתונים:
|
|
הקונסטרקטור, אשר קורא לזה של Dialog. הפרמטר השלישי (true) קובע אם חלון הדיאלוג יהיה מודולי או לא. ואח"כ נקרא לפונקציית האתחול init:
|
|
פונקצית האתחול של המחלקה, בה גם נוסיף את כל הרכיבים לתיבת הדו שיח:
|
|
לסיום, הפונקציה שמטפלת באירועים שנוצרו ע"י לחיצה על הכפתורים ok ו delete.
|
|
כעת נכתוב דוגמא לתוכנית שתשתמש בתיבת הדו-שיח שהגדרנו. במחלקה הראשית, Garage, נקרא לעצם מסוג המחלקה Dia שהגדרנו, ונוסיף גם מאזין לארוע לחיצה על הכפתור, שיציג את תיבת הדו שיח:
|
|
אחרי הפעלת התוכנית, לחיצה על כפתור "look for part" תציג את תיבת הדו-שיח, ואחרי האישור יוצגו הערכים, שמולאו בתיבה, בחלון הראשי.
|