תחילת העבודה עם Java 2D

ה- Java 2D API הוא ממשק API של פלטפורמת Java 1.2 (ראה משאבים למידע מגוון על ה- API ועל יישומיו). יישומי ה- API זמינים כחלק משיעורי Java Foundation (JFC) במהדורות הבטא הנוכחיות של Sun JDK עבור Windows NT / 95 ו- Solaris. כאשר Java 1.2 מסתיים, Java 2D אמור להיות זמין בפלטפורמות רבות יותר.

שים לב שלמרות שג'אווה 2D פותחה באופן בלתי תלוי בחלקים האחרים של ה- JFC, היא בכל זאת חלק מרכזי ב- 1.2 AWT. נערוך הבחנה ונצביע על תכונות ספציפיות לדו-מימד לדיון, אך עליך לזכור כי פונקציונליות זו מרכזית לא פחות מ -1.2 גרפיקה כמו התמיכה הישנה 1.0 ו- 1.1 AWT.

Java 2D מרחיב את מנגנוני AWT הקודמים לציור גרפיקה דו-ממדית, מניפולציה של טקסט וגופנים, טעינה ושימוש בתמונות, והגדרה והתמודדות עם צבעים ורווחי צבע. אנו נחקור את המנגנונים החדשים בטורים אלה ובעתיד.

הערה על המינוח והמוסכמות

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

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

רישומי קוד המקור יינתנו עם מספרי שורות כלולים. אני מתכנן להשתמש במספרי השורות כדי להצליב את טקסט המאמר ורישומי הקוד לפי הצורך. זה אמור גם להקל עליך בהרבה הערות לטור, אם תבחר להדפיס עותק. שים לב, עם זאת, שקבצי המקור המקושרים מהעמודה יהיו קבצי * .java רגילים (מספרי שורות ללא), כך שתוכל להוריד ולהתפתח איתם.

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

החלק העליון של היררכיית החבילות שלי יהיה:

com.javaworld.media 

לכל API או נושא עליו אני כותב תהיה לפחות חבילת משנה אחת מתחת לרמה העליונה הזו. לדוגמא, כל הקוד עבור מאמר זה של Java 2D יהיה:

com.javaworld.media.j2d 

לכן, כדי להפעיל את יישום הדוגמה הראשון ב- Java 2D, היית מוריד את הקוד, שם אותו בנתיב הכיתה שלך ואז משתמש ב:

java com.javaworld.media.j2d.Example01 

(אם מרחב השמות ארוך מדי לטעמך או מסיבה אחרת שתרצה להשתמש בקוד הדוגמה מבלי שתצטרך להשתמש בשם המוסמך, פשוט הוסף הערה על שורת החבילה בתחילת כל קובץ קוד המקור.)

אני אצור קובץ Java Archive (jar) עבור קוד הדוגמה והקבצים של כל מאמר. ארכיון זה יוצג במשאבים של כל עמודה, אם תרצה להוריד אותו ולבצע את הדוגמאות מתוך הארכיון.

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

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

מספיק לגבי מוסכמות. נתחיל לתכנת עם Java 2D!

Graphics2D: שיעור גרפי טוב יותר

המחלקה המרכזית בממשק ה- API של Java 2D היא java.awt.Graphics2Dהמחלקה המופשטת, שמתעדת java.awt.Graphicsבכדי להרחיב את פונקציונליות העיבוד הדו-ממדית. Graphics2Dמוסיף תמיכה אחידה יותר במניפולציות של מגוון צורות, ובכך הופך טקסט, שורות וכל מיני צורות דו-ממדיות אחרות להשוותות ביכולותיהן ובתועלתן.

נתחיל בדוגמה פשוטה המציגה כיצד אתה מקבל ולהשתמש Graphics2dבהפניה.

001 חבילה com.javaworld.media.j2d; 002 003 יבוא java.awt. *; 004 ייבא java.awt.event. *; 005 006 מחלקה ציבורית דוגמה 01 מרחיבה מסגרת {007 / ** 008 * מייצרת אובייקט לדוגמה 01. 009 ** / 010 סטטי ציבור ציבורי ריק (מחרוזת טוענת []) {011 דוגמא חדשה 01 (); 012} 013 014 / ** 015 * הבנאי דוגמה 01 שלנו מגדיר את גודל המסגרת, מוסיף את הרכיבים החזותיים 016 * ואז הופך אותם לגלויים למשתמש. 017 * היא משתמשת בכיתת מתאם כדי להתמודד עם המשתמש שסוגר 018 * את המסגרת. 019 ** / 020 ציבורי דוגמה 01 () {021 // כותרת המסגרת שלנו. 022 סופר ("Java 2D דוגמה 01"); 023 024 // הגדר את הגודל למסגרת. 025 setSize (400,300); 026 027 // עלינו להפעיל את הנראות של המסגרת שלנו 028 // על ידי הגדרת הפרמטר Visible לאמיתי. 029 setVisible (נכון); 030 031 // עכשיו,אנו רוצים להיות בטוחים שנפטר כראוי את המשאבים 032 // מסגרת זו משתמשת בה כאשר החלון סגור. אנו משתמשים ב- 033 // למתאם מחלקה פנימית אנונימית לשם כך. 034 addWindowListener (חדש WindowAdapter () 035 {חלון חלל ציבוריClosing (WindowEvent e) 036 {dispose (); System.exit (0);} 037} 038); 039} 040 041 / ** 042 * שיטת הצבע מספקת את הקסם האמיתי. כאן אנו 043 * מעבירים את אובייקט הגרפיקה ל- Graphics2D כדי להמחיש 044 * שאנו עשויים להשתמש באותן יכולות גרפיקה ישנות עם 045 * Graphics2D שהיינו רגילים להשתמש בו עם גרפיקה. 046 ** / 047 צבע חלל ציבורי (גרפיקה ז) {048 // כך נהגנו לשרטט ריבוע ברוחב 049 // של 200, גובה 200, והחל מ- x = 50, y = 50. 050 גר 'setColor (צבע.אד); 051 גרם.drawRect (50,50,200,200); 052 053 // בואו 'הגדר את הצבע לכחול ולאחר מכן השתמש באובייקט Graphics2D 054 // כדי לצייר מלבן בקיזוז מהריבוע. 055 // עד כה לא עשינו שום דבר באמצעות Graphics2D ש 056 // לא יכולנו לעשות גם באמצעות Graphics. (אנחנו למעשה 057 // משתמשים בשיטות Graphics2D שעוברות בירושה מ- Graphics.) 058 Graphics2D g2d = (Graphics2D) g; 059 g2d.setColor (Color.blue); 060 g2d.drawRect (75,75,300,200); 061} 062}

כאשר אתה מבצע את דוגמה 01, אתה אמור לראות ריבוע אדום ומלבן כחול, כפי שמוצג באיור למטה. שים לב כי קיימת בעיית ביצועים ידועה בגירסת Windows NT / 95 של JDK 1.2 Beta 3 (גרסת 1.2 העדכנית ביותר נכון לעמודה זו). אם דוגמה זו איטית בכאב במערכת שלך, יתכן שתצטרך לעקוף את הבאג כפי שתועד ב- JavaWorld Java Tip 55 (ראה משאבים למטה לקבלת טיפ זה).

שימו לב שכמו שאתם לא מייצרים ישירות Graphicsאובייקט, גם אתם לא מייצרים Graphics2Dאובייקט. במקום זאת, זמן הריצה של Java בונה אובייקט עיבוד ומעביר אותו אליו paint()(שורה 047 ברישום הקוד של דוגמה 01), ובפלטפורמות Java 1.2 ומעבר לכך, האובייקט הזה מיישם גם את Graphics2Dהמחלקה המופשטת.

עד כה לא עשינו שום דבר מיוחד במיוחד עם יכולות הגרפיקה הדו-ממדי שלנו. בואו נוסיף קצת קוד בסוף paint()שיטת הדוגמה הקודמת ונביא מספר תכונות חדשות ל- Java 2D (דוגמה 02):

001 / ** 002 * כאן אנו משתמשים בתכונות חדשות של Java 2D API כגון affine 003 * transforms ו- Shape אובייקטים (במקרה זה 004 * כללי, GeneralPath). 005 ** / 006 צבע חלל ציבורי (גרפיקה g) {007 g.setColor (Color.red); 008 גרם.drawRect (50,50,200,200); 009 010 Graphics2D g2d = (Graphics2D) g; 011 g2d.setColor (Color.blue); 012 g2d.drawRect (75,75,300,200); 013 014 // כעת, בואו נצייר מלבן נוסף, אך הפעם, בואו 015 // נשתמש ב- GeneralPath כדי לציין אותו קטע אחר קטע. 016 // יתר על כן, אנו הולכים לתרגם ולסובב את המלבן הזה 017 // ביחס למרחב ההתקן (וכך, ל- 018 // שני המרובעים הראשונים) באמצעות AffineTransform. 019 // נשנה גם את צבעו. 020 נתיב GeneralPath = GeneralPath חדש (GeneralPath.EVEN_ODD); נתיב 021. MoveTo (0.0f, 0.0f); 022 path.lineTo (0.0f, 125.0f); 023 path.lineTo (225.0f, 125.0f);024 path.lineTo (225.0f, 0.0f); 025 path.closePath (); 026 027 AffineTransform at = AffineTransform חדש (); 028 at.setToRotation (-Math.PI / 8.0); 029 g2d.transform (at); 030 at.setToTranslation (50.0f, 200.0f); 031 g2d.transform (at); 032 033 g2d.setColor (צבע ירוק); 034 g2d.fill (נתיב); 035}

שים לב שמכיוון GeneralPathשנמצא java.awt.geomבחבילה, עלינו להיות בטוחים שנוסיף גם שורת ייבוא:

ייבא java.awt.geom. *; 

הפלט של דוגמה 02 מוצג באיור הבא.

Java 2D מאפשר מפרט של צורות שרירותיות באמצעות java.awt.Shapeהממשק. מגוון צורות ברירת מחדל כגון מלבנים, מצולעים, קווי דו ממד וכו 'מיישמים ממשק זה. אחד המעניינים שבהם מבחינת גמישות הוא java.awt.geom.GeneralPath.

GeneralPathמאפשרים לך לתאר נתיב עם מספר קצוות שרירותי וצורה מורכבת במיוחד. בדוגמה 02, יצרנו מלבן (שורות 020-025), אך באותה קלות יכולנו להוסיף צד או צדדים נוספים ליצירת מחומש, או משושה, או מצולע רב-צדדי אחר. שים לב גם שבניגוד Graphicsלקוד רגיל , Java 2D מאפשר לנו לציין קואורדינטות באמצעות מספרים צפים במקום מספרים שלמים. ספקי CAD בעולם, שמחו! למעשה, Java 2D תומך integer, double, ו floatingאריתמטי במקומות רבים.

כנראה שמתם לב גם שכשיצרנו את הנתיב העברנו פרמטר GeneralPath.EVEN_ODD,, לבנאי (שורה 020). פרמטר זה מייצג כלל מתפתל שאומר למעבד כיצד לקבוע את פנים הצורה שצוינה על ידי הנתיב שלנו. אנא עיין בתיעוד Java 2D javadoc המוזכר במשאבים לקבלת מידע נוסף על כללי סלילה של Java 2D.

החידוש העיקרי האחר בדוגמא 02 נסוב סביב השימוש ב- java.awt.geom.AffineTransforms (שורות 027-031). אשאיר את הקריטריונים של טרנספורמציות כאלה לקורא (ראה משאבים למאמרים שדנים בכך בפירוט רב יותר), אך די אם אומר ש- AffineTransformמאפשרים לך להפעיל כל גרפיקה של Java 2D כדי לתרגם (להזיז) אותו, לסובב אותו. , קנה מידה, גזירה או ביצוע שילובים של המניפולציות האלה.

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

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

לאחר השינוי הראשון ב- Example02 (שורות 028 ו- 029), מערכת הקואורדינטות של Space Space הסתובבה 22.5 מעלות נגד כיוון השעון ביחס לחלל המכשיר. שניהם עדיין חולקים את אותו מקור. (שימו לב כי סיבובים מוגדרים ברדיאנים, כאשר -PI / 8 רדיאנים שווים -22.5 מעלות, או 22.5 מעלות CCW.) אם היינו עוצרים כאן ומציירים את המלבן, הוא היה מסובב בעיקר מחוץ לשדה הראייה שלנו יישום Frame.

לאחר מכן אנו מיישמים טרנספורמציה שנייה (שורות 030 ו- 031), זו תרגום, לאחר השלמת הסיבוב. פעולה זו מעבירה את מערכת הקואורדינטות של שטח המשתמש ביחס למרחב ההתקנים, ומעבירה אותה למטה ליחידות של 200.0 (float) ויחידות 50.0 ימינה (float).

כאשר אנו ממלאים את המלבן הירוק, הוא מתורגם ומסובב ביחס למרחב ההתקנים.

של בזייה ועקומות מסודרות יותר

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

עקומות משמשות בכל המתמטיקה והגרפיקה הממוחשבת בכדי לקרוב לצורות מורכבות תוך שימוש במספר סופי, מוגדר היטב (ובאופן אידיאלי קטן) של נקודות מתמטיות. בעוד ש- AWT הסטנדרטי לא תמך ישירות בשרטוטים עם עקומות שרירותיות בעבר (פלטפורמות Java 1.0 או 1.1), Java 2D מוסיף תמיכה מובנית לעקומות מסדר ראשון, שני ושלישי. ניתן לצייר עקומות עם שתי נקודות קצה ואפס, אחת או שתי נקודות בקרה . Java 2D מחשב עקומות מסדר ראשון ושני באמצעות נוסחאות ליניאריות ומרובעות ועקומות מעוקבות או מסדר שלישי באמצעות עקומות Bezier.

(עקומות Bezier הן סוג של עקומת פולינום פרמטרית שיש לה כמה תכונות רצויות מאוד הקשורות לחישוב של עקומות ומשטחים סגורים. הם משמשים במספר יישומים גרפיים. עיין במקורות למידע נוסף על השימוש בפולינומים פרמטריים ועקומות Bezier בגרפיקה ממוחשבת.) GeneralPathהשיטות המשרטטות כל אחת מהעקומות הללו הן:

  • lineTo() למקטעים ישרים (ציין רק נקודות קצה)
  • quadTo() עבור עקומות ריבועיות (ציין נקודת בקרה אחת)
  • curveTo() לעקומות מסדר שלישי (ציין שתי נקודות בקרה, משורטטות באמצעות עקומת Bezier מעוקבת)