intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java...

44
intro. to Java (FEU.faa) ในบทนี้เราจะมาดูถึงวิธีการวาดรูปทรงสองมิติตาง ดวย method ที่มีอยูใน class Graphics และ class Graphics2D รวมไปถึงการเคลื่อนยายภาพ การหมุนภาพ การใชลูกเลนตาง กับ ภาพที่เราตองการแสดงออกทางหนาจอ หลังจากจบบทเรียนนี้แลวผูอานจะไดทราบถึง o การสราง frame o การสงขอความลงบน frame o การวาดรูปทรงตาง เชน สี่เหลี่ยม (rectangle) วงรี หรือวงกลม (ellipse) เสนตรง (line) o การกําหนดสีในรูปทรงตาง o การเคลื่อนยายภาพ (translation) o การหมุนภาพ (rotation) o การปรับเปลี่ยนรูป (scale และ shear) o การสรางภาพเคลื่อนไหว (animation) 10.1 Simple Window หนาตาง (window) ที่เราเห็นกันอยูในโปรแกรมทั่วไปมีชื่อเรียกวา frame ใน Java เราจะเริ่มตน สราง frame ตัวแรกของเราที่มีเพียงแค title ดังที่เห็นนีภาพที10.1 หนาตาง (top-level window) และ code ของการสรางหนาตางตัวอยางมีดังนีwidth = 300 height = 200 title

Transcript of intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java...

Page 1: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

ในบทนเราจะมาดถงวธการวาดรปทรงสองมตตาง ๆ ดวย method ทมอยใน class Graphics และ class Graphics2D รวมไปถงการเคลอนยายภาพ การหมนภาพ การใชลกเลนตาง ๆ กบภาพทเราตองการแสดงออกทางหนาจอ หลงจากจบบทเรยนนแลวผอานจะไดทราบถง

o การสราง frame o การสงขอความลงบน frame o การวาดรปทรงตาง ๆ เชน สเหลยม (rectangle) วงร หรอวงกลม (ellipse) เสนตรง

(line) o การกาหนดสในรปทรงตาง ๆ o การเคลอนยายภาพ (translation) o การหมนภาพ (rotation) o การปรบเปลยนรป (scale และ shear) o การสรางภาพเคลอนไหว (animation)

10.1 Simple Window หนาตาง (window) ทเราเหนกนอยในโปรแกรมทวไปมชอเรยกวา frame ใน Java เราจะเรมตนสราง frame ตวแรกของเราทมเพยงแค title ดงทเหนน

ภาพท 10.1 หนาตาง (top-level window)

และ code ของการสรางหนาตางตวอยางมดงน

width = 300

heig

ht =

200

title

Page 2: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

300

1: /** 2: Simple frame 3: */ 4: 5: import javax.swing.*; 6: 7: class TestSimpleFrame { 8: public static void main(String[] args) { 9: SimpleFrame frame = new SimpleFrame(); 10: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 11: frame.setVisible(true); 12: } 13: } 14: 15: class SimpleFrame extends JFrame { 16: private static final int WIDTH = 300; 17: private static final int HEIGHT = 200; 18: 19: public SimpleFrame() { 20: setTitle("Simple Frame"); 21: setSize(WIDTH, HEIGHT); 22: } 23: }

โปรแกรมสรางหนาตางทเราเขยนขนใช frame ของ Swing ดงนนเราจงตอง import class ตาง ๆ ทมอยใน Swing package ทเราตองการใชเขาสโปรแกรม ดวยคาสง import javax.Swing.* โดยการกาหนดแลว frame ใน Java มขนาดเปน 0 x 0 pixels เราจงตองกาหนดให frame ทเราสรางขนมขนาดเปน 300 x 200 pixels ผอานจะเหนวาเราม class อยสอง class คอ TestSimpleFrame และ SimpleFrame Class SimpleFrame เปน subclass ทเราสรางขนจาก class JFrame ซงหนาตางทกบานทเราตองการสราง จะตองมาจาก class น และเราไดกาหนดให frame ของเราม title เปน Simple Frame ดวยการเรยกใช setTitle() สวนขนาดของ frame กถกกาหนดดวยคาสง setSize() ดงทแสดงในบรรทดท 20 และ 21 เราสราง frame ใน class TestSimpleFrame ดวยคาสง SimpleFrame frame = new SimpleFrame();

หลงจากนนเรากกาหนดใหโปรแกรมยตการทางานถาผใชกดปมเพอปดหนาตาง (มมขวาบน) ดวยคาสง frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

หนาตางเมอมการสรางเสรจแลวจะไมแสดงตวเองออกมา เราตองบงคบให frame แสดงตวดวยการเรยกใช method setVisible() ของ class JFrame หนาตางทเราสรางขนนเปนหนาตางทถกสรางขนจากระบบปฏบตการ (Windows) ไมใชการสรางจาก Swing เพราะฉะนนถาเรา run โปรแกรมตวนบนระบบปฏบตการอน เรากจะไดหนาตางทมหนาตาแปลกออกไป ตามขอกาหนดของระบบปฏบตการนน ๆ (look and feel) แตถาเราตองการใหหนาตางของเรามขอกาหนดของ Java look and feel เรากสามารถทาไดดงน

1: /** 2: Simple frame 3: */ 4: 5: import javax.swing.*; 6: 7: class TestSimpleFrame { 8: public static void main(String[] args) { 9: //thread safe app 10: javax.swing.SwingUtilities.invokeLater(new Runnable() { 11: public void run() { 12: new SimpleFrame(); 13: } 14: });

Page 3: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

301

15: } 16: } 17: 18: class SimpleFrame extends JFrame { 19: private static final int WIDTH = 300; 20: private static final int HEIGHT = 200; 21: 22: public SimpleFrame() { 23: //make sure we have nice Java's look and feel window 24: setDefaultLookAndFeelDecorated(true); 25: 26: JFrame frame = new JFrame(); 27: frame.setTitle("Simple Frame"); 28: frame.setSize(WIDTH, HEIGHT); 29: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30: frame.setVisible(true); 31: } 32: }

เราเปลยนตว method main() ใหทาการสราง object จาก class SimpleFrame ผานทาง method run() และ method invokeLater() เพอไมใหเกดปญหาของการเรยกใช thread (เราเรยกการเรยกแบบนวาเปนการเรยกผาน event-dispatching thread) สวนสาคญอกตวหนงกคอคาสงในบรรทดท 24 ซงเปนคาสงใหกบ Java ใหเลอกหนาตางทถกตองตามทเราตองการ และผลลพธทเราไดคอ

ภาพท 10.2 หนาตางในรปแบบของ Java

10.2 การวางตาแหนงของหนาตางบนจอ การกาหนดตาแหนงของหนาตางทเราสรางขนเพอใหปรากฏบนจอนน ตองเรยกใช method ทเกยวของหลายตวพอสมควร เชน ถาเราตองการวางหนาตางตรงกลางจอ เรากตองรขนาดของจอวามขนาดเทาใด ขนาดของหนาตางทเราสรางขนมสดสวนเปนเทาใดของจอ หนาตางสามารถทจะเปลยนแปลงขนาดจากผใชไดหรอไม เราจะลองเขยนโปรแกรมททางานอยางทวาด

1: /** 2: Another simple frame 3: */ 4: 5: import java.awt.*; 6: import java.awt.event.*; 7: import javax.swing.*; 8: 9: class TestAnotherFrame { 10: public static void main(String[] args) { 11: AnotherFrame frame = new AnotherFrame("Another Frame"); 12: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13: frame.setVisible(true); 14: } 15: } 16: 17: class AnotherFrame extends JFrame {

Page 4: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

302

18: public AnotherFrame(String title) { 19: //set title via super class 20: super(title); 21: 22: //get screen size 23: Toolkit kit = Toolkit.getDefaultToolkit(); 24: Dimension screenSize = kit.getScreenSize(); 25: int height = screenSize.height; 26: int width = screenSize.width; 27: 28: //set frame width and height 29: setSize(width / 2, height / 2); 30: 31: //set position of the frame 32: setLocation(width / 4, height / 4); 33: 34: //set icon 35: Image img = kit.getImage("990.gif"); 36: setIconImage(img); 37: } 38: }

ผลลพธทเราไดจากการ run โปรแกรมกคอหนาตางทมขนาดเทากบหนงในสของจอ และอยกงกลางของจอ แตทเปลยนแปลงอกอนหนงกคอ icon ของตวหนาตาง

ภาพท 10.3 สวนหนงของหนาตางทถกเปลยน icon

Constructor ของ class AnotherFrame เปนททเรากาหนดรปแบบของหนาตางทเราตองการแสดง โดยเราเปลยนการกาหนด title ของ frame จากการเรยกใช setTitle() มาเรยกใช constructor ของ super class ของ JFrame ใหทาหนาทแทน และเราหาขนาดของจอดวยการเรยกใช getDefaultToolkit() ของ class Toolkit ซงเมอไดแลวเราจะเกบขนาดไวใน screenSize (object จาก class Dimension – ดบรรทดท 23 และ 24) หลงจากนนเรากดงเอาความกวางและความสงของหนาตางมาเกบไวในตวแปร width และ height ตามลาดบ ในการกาหนดตาแหนงของหนาตาง เรากเรยกใช method setLocation() ดวยคาของ width / 4 และ height / 4 สวน icon ทอยในมมบนซายของหนาตางกถกเปลยนดวยการเรยกใช setIconImage() หลงจากทเราไดทาการเกบ icon ทตองการแสดงไวในรปแบบของ GIF ไฟล (บรรทดท 35)

Icon ทถกเปลยนจากเดม

Page 5: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

303

10.3 การแสดงขอมลในหนาตางดวยการวาด (Drawing) การแสดงขอความทเราตองการออกทางหนาจอนนมหลายวธ วธทเราจะแสดงใหดคอ การเขยนลงในหนาตางทตองการแสดงผานทาง Panel เราจะเรมตนดวยการเขยนโปรแกรมแสดงผลกอนทเราจะอธบายถงวธการ

1: /** 2: Drawing onto window 3: */ 4: 5: import java.awt.*; 6: import javax.swing.*; 7: 8: class WelcomeWindow { 9: public static void main(String[] args) { 10: WelcomeFrame frame = new WelcomeFrame(); 11: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 12: frame.setVisible(true); 13: } 14: } 15: 16: //frame contains message panel 17: class WelcomeFrame extends JFrame { 18: private static final int WIDTH = 300; 19: private static final int HEIGHT = 200; 20: 21: public WelcomeFrame() { 22: setTitle("Welcome Window"); 23: setSize(WIDTH, HEIGHT); 24: 25: //add to panel 26: WelcomePanel panel = new WelcomePanel(); 27: add(panel); 28: } 29: } 30: 31: //panel for message to be drawn on 32: class WelcomePanel extends JPanel { 33: private static final int X = 75; 34: private static final int Y = 100; 35: 36: public void paintComponent(Graphics g) { 37: super.paintComponent(g); 38: g.drawString("Welcome to Java Window", X, Y); 39: } 40: }

สงทเราทาแตกตางจากตวอยางกอนหนาน กคอเราไดสราง panel สาหรบการเขยนขอความขนมาหนงอน จาก class WelcomePanel โดยตงชอวา panel ในบรรทดท 26 และเราทาการแปะ panel ตวนเขากบ frame ดวยการเรยกใช method add() ขอความทเราเขยนขนเปนการเขยนผาน method paintComponent() ซงเปน method ทมอยใน class JComponent และ paintComponent() ม parameter 1 ตวคอ object ทเปน Graphics และ object ตวนจะมขอมลทเกยวของกบการวาดภาพทเปนขอความ หรอรป เชน ชนดของตวอกษร สทใช เปนตน การวาดใน Java จะตองทาผาน method ของ object ทมาจาก class Graphics เทานน เชน method drawstring() ทเราใชในบรรทดท 38 g.drawString("Welcome to Java Window", X, Y);

สงทเราสงใหกบ drawString() กคอ ขอความทตองการแสดง (String) และตาแหนงของขอความ (X และ Y) ผอานจะสงเกตเหนวาเราไมไดเรยก paintComponent() โดยตรง ทงนกเพราะวา ทก ๆ ครงทมการรองขอการแสดงหนาตาง ตวควบคมเหตการณ (event handler) จะทาการบอกให component รถงการรองขอดงกลาว ทาให method ตาง ๆ ของ paintComponent() ถกเรยกขนมาทางานโดยอตโนมต การแสดงขอความจงเกดขน

Page 6: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

304

ภาพท 10.4 การวาดขอความลงบนหนาตาง

กระบวนการทจาเปนสาหรบการวาดลงบน panel มขนตอนสาคญดงนคอ

• สราง class ทตองการใช (ใชคาสง extends) จาก class JPanel • Override method paintComponent() ใน class นน

เนองจากวา class ทเราสรางขนเพอทาการวาดนนมาจาก class JPanel ซงมกระบวนการในการจดการกบการวาดภาพพนหลงของ panel เองดงนนเราจงตองเรยก super.paintComponent() ใหทาสวนทตวเองตองทาใหเสรจกอนทเราจะทาการวาดสวนตาง ๆ ของเราเอง (เชนทไดทาในบรรทดท 37 ของโปรแกรม Welcome.java) 10.3.1 การวาดเสน (Line) การวาดเสนใน Java เราใชคาสง drawLine(int x1, int y1, int x2, int y2);

โดยท (x1, y1) เปนจดเรมตนของเสนและ (x2, y2) เปนจดสนสดของเสนดงทแสดงใหดในตวอยางทเหนน

ภาพท 10.5 การวาดเสนตรงสองเสน

เราวาดเสนทแยงมมสองเสนจากการใชคาสง

X

Y

(0, 0)

ตาแหนงเรมตนของ frame จะเรมตนทดานบนซาย (top-left) ของพนท ทเราตองการวาด

X = 75, Y = 100

framepanel

(0, 0)

(getWidth(), getHeight())

(getWidth(), 0)

(0, getHeight()

Page 7: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

305

g.drawLine(0, 0, getWidth(), getHeight()); g.drawLine(0, getHeight(), getWidth(), 0);

10.3.2 การวาดรปสเหลยม การวาดรปสเหลยมม method อยทงหมดหกตว คอ drawRect(int x, int y, int w, int h) fillRect(int x, int y, int w, int h) drawRoundRect(int x, int y, int w, int h, int aw, int ah) fillRoundRect(int x, int y, int w, int h, int aw, int ah) draw3DRect(int x, int y,int w, int h, boolean raised) fill3DRect((int x, int y,int w, int h, boolean raised) ตวอยางผลลพธทเหนน เราใช method 4 ตวแรกในการสราง

ภาพท 10.6 รปทรงสเหลยม

1: /** 2: Draw rectangles 3: */ 4: 5: import java.awt.*; 6: import javax.swing.*; 7: 8: class DrawRectangles { 9: public static void main(String[] args) { 10: RectangleFrame frame = new RectangleFrame(); 11: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 12: frame.setVisible(true); 13: } 14: } 15: 16: class RectangleFrame extends JFrame { 17: private static final int WIDTH = 300; 18: private static final int HEIGHT = 200; 19: 20: public RectangleFrame() { 21: setTitle("Drawing Rectangles"); 22: setSize(WIDTH, HEIGHT); 23: 24: //add to panel 25: DrawingPanel panel = new DrawingPanel(); 26: add(panel); 27: } 28: } 29: 30: class DrawingPanel extends JPanel { 31: public void paintComponent(Graphics g) { 32: super.paintComponent(g);

Page 8: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

306

33: 34: g.drawRect(5, 5, getWidth() / 2 - 10, getHeight() / 2 - 10); 35: 36: g.setColor(Color.gray); 37: g.fillRect(getWidth() / 2 + 5, 5, 38: getWidth() / 2 - 10, getHeight() / 2 - 10); 39: 40: g.setColor(Color.blue); 41: g.fillRoundRect(5, getHeight() / 2 + 5, getWidth() / 2 - 10, 42: getHeight() / 2 - 10, 20, 20); 43: 44: g.setColor(Color.red); 45: g.drawRoundRect(getWidth() / 2 + 5, getHeight() / 2 + 5, 46: getWidth() / 2 - 10, getHeight() / 2 - 10, 20, 20); 47: } 48: }

การกาหนดสทเราตองการใชกทาไดดวยการเรยกใช method setColor() ดวยสทตองการจากทกาหนดไวใน class Color เชน Color.black หรอ Color.BLACK Color.blue หรอ Color.BLUE Color.cyan หรอ Color.CYAN Color.darkGray หรอ Color.DARK_GRAY Color.gray หรอ Color.GRAY Color.green หรอ Color.GREEN Color.lightGray หรอ Color.LIGHT_GRAY Color.magenta หรอ Color.MAGENTA Color.orange หรอ Color.ORANGE Color.pink หรอ Color.PINK Color.red หรอ Color.RED Color.white หรอ Color.WHITE Color.yellow หรอ Color.YELLOW การใช drawRect() และ fillRect() เปนการวาดรปสเหลยม และการระบายรปสเหลยม สวนการใช drawRoundRect() และ fillRoundRect() นนเปนการวาดรปสเหลยม และการระบายรปสเหลยมทมมมเปนรปโคง (aw และ ah) คา aw เปนความกวาง คา ah เปนความสงของรปวงรทเปนตวกาหนดความโคงดงกลาว ผอานควรทดลองคาความโคงทตางกนเพอใหเหนถงมมทเกดขน Method ทเหลอสองตวคอ draw3DRect() และ fill3DRect() เปนการวาดรปสเหลยม และการระบายรปสเหลยมทเปนรปสามมต parameter ตวสดทายทมอยใน method ทงสองตวเปนตวกาหนดวารปสเหลยมทสรางขนนน จะนน (raised) หรออยลก (etched) ลงไปในภาพ 10.3.3 การวาดรปหลายเหลยม (Polygon) Class Polygon เปน class ทเออใหเราวาดรปหลายเหลยมไดงายขน class นม constructor อยสองตวใหเราเรยกใช คอ Polygon() และ Polygon(int[] xpoints, int[] ypoints, int[] npoints) เราจะลองสรางรปหลายเหลยมจาก class Polygon ด หลงจากทเราสราง object จาก class Polygon แลวเรากกาหนดจดตาง ๆ ทมอยใน polygon นนดวยการเรยกใช method addPoints() ดงทเหนน Polygon poly = new Polygon(); poly.addPoint(75, 50); poly.addPoint(150, 0); poly.addPoint(225, 50); poly.addPoint(225, 150); poly.addPoint(150, 200); poly.addPoint(75, 150); เมอเรากาหนดเสรจเรากเรยก drawPolygon() เพอทาการวาด g.drawPolygon(poly);

Page 9: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

307

ผลลพธทเราไดคอ

ภาพท 10.7 การวาดรปหลายเหลยมดวย drawPolygon()

Polygon ทเราเหนนสรางขนดวยการกาหนดจดใหกบ object จาก class Polygon แตเราสามารถสราง polygon ไดอกแบบหนงคอ กาหนดจดตาง ๆ ทตองการใน array หลงจากนนกสงจดเหลานใหกบ method drawPolygon() ดงทเหนน int[] x = {75, 150, 225, 225, 150, 75}; int[] y = {50, 0, 50, 150, 200, 150}; g.drawPolygon(x, y, x.length);

parameter ตวสดทายจะเปนจานวนของจดทงหมดทมอยใน polygon ทเราสราง ซงในกรณตวอยางของเรา เราจะใช x.length หรอ y.length กได 10.3.4 การวาดรปวงร (Oval) การวาดรปวงร หรอวงกลมทาไดดวยการเรยกใช method drawOval() และ fillOval() ดงน g.drawOval(int x, int y, int w, int h); g.fillOval(int x, int y, int w, int h);

parameter 2 ตวแรกคอจกเรมตน (x, y) ตวทสามเปนความกวาง สวนตวสดทายเปนความสงของรปวงรทตองการวาด (ผอานควรสงเกตวาถา width และ height มคาเทากนเราจะไดรปวงกลม) ผลลพธทเราไดจากการทดลองวาดดวยคาสง g.drawOval(0, 0, getWidth(), getHeight());

(225, 50)

(150, 0)

(75, 50)

(225, 150)

(150, 200)

(75, 150)

Page 10: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

308

ภาพท 10.8 รปวงร

10.4 การสรางรปทรงสองมตจาก Graphics2D การใช method จาก class Graphics นนมขดจากดพอสมควร เชน เราไมสามารถทจะกาหนดความหนาของเสนทเราวาดได ไมสามารถทจะหมนภาพหรอเคลอนยายภาพได ใน Java 2D เราม class Graphics2D ทม method ตาง ๆ ในการทางานกบภาพสองมตในรปแบบตาง ๆ ไดมากขน โปรแกรมตวอยางตอไปนเปนการเรยกใช method ตาง ๆ ในการสรางภาพสองมต

1: /** 2: Draw shapes with Graphics2D 3: */ 4: 5: import java.awt.*; 6: import java.awt.geom.*; 7: import javax.swing.*; 8: 9: class DrawShapes { 10: public static void main(String[] args) { 11: ShapesFrame frame = new ShapesFrame(); 12: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13: frame.setVisible(true); 14: } 15: } 16: 17: class ShapesFrame extends JFrame { 18: private static final int WIDTH = 400; 19: private static final int HEIGHT = 400; 20: 21: public ShapesFrame() { 22: setTitle("Drawing 2D Shapes"); 23: setSize(WIDTH, HEIGHT); 24: 25: //add to panel 26: DrawingPanel panel = new DrawingPanel(); 27: add(panel); 28: } 29: } 30: 31: class DrawingPanel extends JPanel { 32: public void paintComponent(Graphics g) { 33: super.paintComponent(g); 34: Graphics2D g2 = (Graphics2D)g; 35: 36: double x = 100; 37: double y = 100; 38: double width = 200; 39: double height = 150; 40: 41: //draw rectangle 42: Rectangle2D rectangle = new Rectangle2D.Double(x, y, width, height); 43: g2.draw(rectangle); 44:

Page 11: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

309

45: //draw ellipse 46: Ellipse2D ellipse = new Ellipse2D.Double(); 47: ellipse.setFrame(rectangle); 48: g2.draw(ellipse); 49: 50: //draw a circle 51: double centerX = rectangle.getCenterX(); 52: double centerY = rectangle.getCenterY(); 53: double radius = 150.0; 54: 55: Ellipse2D circle = new Ellipse2D.Double(); 56: circle.setFrameFromCenter(centerX, centerY, 57: centerX + radius, centerY + radius); 58: g2.draw(circle); 59: 60: //create line thickness and draw vertical line 61: BasicStroke thickStroke = new BasicStroke(3.0f); 62: g2.setStroke(thickStroke); 63: g2.draw(new Line2D.Double(getWidth()/2, 0, 64: getWidth()/2, getHeight())); 65: 66: //create dashed line and draw horizontal line 67: float dash1[] = {10.0f}; 68: BasicStroke dashed = new BasicStroke(3.0f, 69: BasicStroke.CAP_BUTT, 70: BasicStroke.JOIN_MITER, 71: 10.0f, dash1, 0.0f); 72: g2.setStroke(dashed); 73: g2.draw(new Line2D.Double(0, getHeight()/2, 74: getWidth(), getHeight()/2)); 75: } 76: }

กระบวนการในการเรยกใช method ทมอยใน class Graphcis2D กทาไดไมยาก เพยงแตวาเราตองเปลยน object จาก class Graphics ใหเปน object ของ class Graphics2D กอนดงททาไวในบรรทดท 34 และในบรรทดท 42 และ 43 เปนการสรางรปสเหลยมทจดเรมตน (x, y) ดวยความกวางและสงเทากบ width และ height ตามลาดบ เราเรยกใช method draw() ดวยการสง object ทเกดจาก class Shape ไปให บรรทดท 46 ถง 48 เปนการวาดรปวงรทใชขอมลของรปสเหลยมทวาดขนกอนหนานเปนตวกาหนด ซงทาใหรปวงรนอยภายในรปสเหลยม บรรทดท 51 ถง 53 เปนการหาจดกงกลางของรปสเหลยม และการกาหนดรศมของวงกลมทเราตองการวาด และในบรรทดท 55 ถง 58 เปนการกาหนดกรอบของวงกลมจากจดกงกลางทเราหาไดกอนหนาน พรอมกบการวาดวงกลมดงกลาว บรรทดท 61 ถง 62 เปนการกาหนดขนาดหรอความหนา (thickness) ของเสนทเราใชวาด ซงเรากาหนดใหมขนาดเทากบ 3 (เราตองกาหนดใหเปน float) เมอกาหนดเสรจเรากวาดเสนตรงดวยการสราง object จาก class Line2D โดยใหเปนเสนกงกลางจากบนลงลาง บรรทดท 67 ถง 73 เปนการกาหนดใหเสนทจะวาดเปนเสนประทมความหนาเทากบ 3 พรอมกบการวาดเสนตรง (ประ) ดงกลาว คาสงในการกาหนดเสนประดจะยงเยงนดหนอย ทงนกเพราะวาเราตองกาหนดคาทเสนประนจะตองแสดง ซงมคาตาง ๆ ดงน Parameter ตวทหนงเปนความหนาของเสน ตวทสองเปนตวกาหนดรปรางของจดจบของเสน (end) ตวทสามเปนตวกาหนดการรวมกนเมอเสนมาเจอกน (join) ตวทสเปนตวกาหนดการ trim ของ miter join ตวทหาเปน array กาหนด pattern ของเสนประ และตวสดทายเปน offset ทเปนตวเรมตนของเสนประ ผลลพธทเราไดจากการ run โปรแกรม DrawShape.java คอ

Page 12: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

310

ภาพท 10.9 การวาดรปทรงตาง ๆ ดวย Graphics2D

Class ทอยใน package java.awt.geom

Arc2D Ellipse2D QuadCurve2D Area GeneralPath Rectangle2D CubicCurve2D Line2D RectangularShape Dimension2D Point2D RoundRectangle2D

Method ทใชหาจดกงกลาง คาตาสด คาสงสดของ (x, y) ของรปสเหลยม

• double getCenterX() • double getCenterY() • double getMinX() • double getMinY() • double getMax() • double getMaxY()

method ทใชหาความกวาง และความสงของรปสเหลยม

• double getWidth() • double getHeight()

method ทใชหาคา x และคา y ทอยมมบนซายของรปสเหลยม

• double getX()

Page 13: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

311

• double getY() method ทใชวาดรปทรงตาง ๆ

• Rectangle2D.Double(double x, double y, double w, double h) • Rectangle2D.Float(float x, float y, float w, float h) • Ellipse2D.Double(double x, double y, double w, double h)

Method ทใชสรางจด และเสนตรง

• Point2D.Double(double x, double y) • Line2D.Double(Point2D start, Point2D end) • Line2D.Double(double startX, double startY, double endX, double endY)

ในการเปลยนสของปากกาทใชวาดเรากเรยกใช method setPaint() ดวยคาสตาง ๆ ทไดพดไวกอนหนาน เชน ถาเราตองการใหเสนประมสแดงในโปรแกรมของเรา เรากเรยกใชคาสง g2.setPaint(Color.red) แทรกระหวางบรรทดท 72 และ 73 แตถาเราตองการสทอยนอกเหนอสทกาหนดเหลานเรากตองสรางขนใหม จาก class Color เชน g2.setPaint(new Color(0, 128, 128)); ซงเปนการกาหนดคาสทอยระหวาง 0 – 255 (parameter ทงสามตวแสดงถงคาโทนสของ สแดง (r) สเขยว (g) และสฟา (b) ตามลาดบ) เพราะฉะนนถาอยากไดสขาวเรากใช (255, 255, 255) เปนตน แตถาเราตองการใหมโทนสในภาพทตองการวาด (fill pattern) เรากตองสรางโทนสจาก class GradientPaint ดงตวอยางนเรากาหนดใหเกดสจากแดงไปเหลองโดยมความเปนโทนสอยระหวางสทงสอง GradientPaint gradient = new GradientPaint(0, 0,

Color.red, 300, 200, Color.yellow); g2.setPaint(gradient);

ผลลพธทไดจากการกาหนดสดงกลาวในการวาดรปวงรคอ

ภาพท 10.10 การใชโทนสในการวาดภาพ

[การกาหนดรปแบบ (style) ของเสน] เรากาหนด style ของเสนจาก class BasicStroke โดยสราง object จาก class นแลวจงสงไปให method setStroke() ของ class Graphics2D ดงทเราไดแสดงใหดกอนหนาน object จาก class BasicStroke จะมขอมลทเกยวกบรปทตองการวาด เชน ขนาดของเสน (line width) style ของการพบกนของเสน (join style) style ของการสนสดของเสน (end-cap) และ style ของเสนประทกาหนดขน (dash style)

Page 14: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

312

Join style มทงหมดอย 3 ตวคอ

1. JOIN_BEVEL

2. JOIN_MITER

3. JOIN_ROUND สวน end-cap มอยสามตวเชนกนคอ

1. CAP_BUTT 2. CAP_ROUND 3. CAP_SQUARE

การกาหนด dash style นนเราใช dash array และ dash phase โดยท dash array จะเปน array ทเกบลกษณะของเสนประ คาตาง ๆ ใน array จะเปนตวกาหนดความยาวของเสนประ และชองวางระหวางเสน เชน คาในตาแหนง 0 จะเปนความยาวของเสนประตวแรก คาในตาแหนง 1 จะเปนความยาวของชองวางตวแรก เปนตน (สลบกนไปในลกษณะน) จากภาพท 10.6 เราใชคา dash array เพยงคาเดยวคอ {10,0f} ดงนนเสนประของเราจงมขนาดเทากนทงเสนทบและชองวาง แตถาเราเปลยนใหเปนคาอน เชน {5, 2, 5, 2} เรากจะไดชองวางทเลกกวาเสนทบ 10.4.1 การสรางเสนโคง (Quadratic and Cubic Curves) การสรางเสนโคงใน Java ทาไดดวยการเรยกใช class QuadCurve2D และ class CubicCurve2D Class QuadCurve2D เปนการสรางเสนโคงทมชอเรยกวา Quadratic Parametric Curve โดยเราตองกาหนดจดสองจดทเปน จดเรมตนและจดจบของเสน (end points) และอกจดหนงทเปนตวกาหนดความโคงของเสน (control point) QuadCurve2D.Double quad = new QuadCurve2D.Double(); Point2D.Double start, end, control; start = new Point2D.Double(); end = new Point2D.Double(); control = new Point2D.Double(); Dimension d = getSize(); int w = d.width; int h = d.height; start.setLocation(w/2-50, h/2); end.setLocation(w/2+50, h/2); control.setLocation((int)(start.x)+50, (int)(start.y)-50); quad.setCurve(start, control, end); g2.draw(quad);

code ทเหนดานบนนเรมดวยการสรางเสนโคง (quad), จดเรมตน (start), จดจบ (end) และจดควบคม (control) จาก constructor ทเกยวของทงสตว เรากาหนดตาแหนงของจดทงสามใหมความสมพนธกบขนาดของจอภาพดวยการใช method setLocation() ซงเมอไดจดแลวเรากสรางเสนโคงดวยการเรยกใช method setCurve() ดวยจดทงสาม Class CubicCurve2D เปนการสรางเสนโคงทมชอเรยกวา Cubic Parametric Curve โดยเราตองกาหนดจด endpoint สองจด และจด control point อกสองจด code ของการสรางเสนโคงแบบนกคลาย ๆ กบแบบแรก เพยงแตเพมจดควบคมอกหนงตว เราคงไมแสดงใหดแตจะนาเอา code ทงหมดของการสรางเสนโคงแบบแรกมาใหด

1: /** 2: Draw Quadratic parametric curve 3: */ 4:

Page 15: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

313

5: import java.awt.*; 6: import java.awt.Rectangle; 7: import java.awt.geom.*; 8: import javax.swing.*; 9: 10: class ParametricCurves { 11: public static void main(String[] args) { 12: CurveFrame frame = new CurveFrame(); 13: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14: frame.setVisible(true); 15: } 16: } 17: 18: class CurveFrame extends JFrame { 19: private static final int WIDTH = 300; 20: private static final int HEIGHT = 200; 21: 22: public CurveFrame() { 23: setTitle("Drawing Curves"); 24: setSize(WIDTH, HEIGHT); 25: 26: //add to panel 27: DrawingPanel panel = new DrawingPanel(); 28: panel.setBackground(Color.white); 29: add(panel); 30: } 31: } 32: 33: class DrawingPanel extends JPanel { 34: QuadCurve2D.Double quad = new QuadCurve2D.Double(); 35: Point2D.Double start, end, control; 36: Rectangle sPoint, ePoint, ctrlPoint; 37: 38: public DrawingPanel() { 39: start = new Point2D.Double(); 40: end = new Point2D.Double(); 41: control = new Point2D.Double(); 42: sPoint = new Rectangle(0, 0, 8, 8); 43: ePoint = new Rectangle(0, 0, 8, 8); 44: ctrlPoint = new Rectangle(0, 0, 8, 8); 45: } 46: 47: public void paintComponent(Graphics g) { 48: super.paintComponent(g); 49: Graphics2D g2 = (Graphics2D)g; 50: Dimension d = getSize(); 51: int w = d.width; 52: int h = d.height; 53: BasicStroke thickStroke = new BasicStroke(3.0f); 54: g2.setStroke(thickStroke); 55: 56: start.setLocation(w/2-50, h/2); 57: end.setLocation(w/2+50, h/2); 58: control.setLocation((int)(start.x)+50, (int)(start.y)-50); 59: 60: sPoint.setLocation((int)(start.x)-4, (int)(start.y)-4); 61: ePoint.setLocation((int)(end.x)-4, (int)(end.y)-4); 62: ctrlPoint.setLocation((int)(control.x)-4, (int)(control.y)-4); 63: 64: quad.setCurve(start, control, end); 65: 66: g2.setPaint(Color.black); 67: g2.draw(quad); 68: g2.setPaint(Color.red); 69: g2.fill(sPoint); 70: g2.setPaint(Color.yellow); 71: g2.fill(ePoint); 72: g2.setPaint(Color.blue); 73: g2.fill(ctrlPoint); 74: } 75: }

ผลลพธทไดจากโปรแกรมคอ

Page 16: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

314

ภาพท 10.11 เสนโคง

code ในบรรทดท 55 – 58 เปนการกาหนดจดทงสามของเสนโคง code ในบรรทดท 60 – 62 เปนการกาหนดรปสเหลยมเพอใชแสดงจดทงสามของเสนโคงนน หลงจากทกาหนดเสนโคงดวย setCurve() แลวเรากวาดเสนโคงพรอมทงสเหลยมทอย ณ จดทงสาม 10.4.2 การแสดงผลของพนทททบซอนกน (Area) Java มกระบวนการในการแสดงผลเมอพนทของรปทรงเรขาวางซอนกนอยสตวคอ add จะเปนการรวมเอาพนททงสองเขาดวยกน โดยพนททเกดขนใหมจะรวมจดทงหมดของพนทของตวแรกหรอของพนทตวทสอง subtract พนททเกดขนใหมจะรวมจดทงหมดทอยในสวนของพนทตวแรก ไมนบตวทสอง intersect พนททเกดขนรวมจดทงหมดของทงสองพนท exclusiveOr พนททเกดขนใหมจะรวมจดของพนทตวแรกหรอตวทสองเทานน แตไมใชทงสอง ภาพท 10.12 และ 10.13 แสดงการใชกระบวนการทงสของ Area

ภาพท 10.12 การใช add() และ subtract()

Page 17: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

315

ภาพท 10.13 การใช intersect() และ exclusiveOr()

Code ทงหมดของ AreaTest.java

1: /** 2: Areas 3: */ 4: 5: import java.awt.*; 6: import java.awt.geom.*; 7: import javax.swing.*; 8: 9: class AreaTest { 10: public static void main(String[] args) { 11: JFrame frame = new AreaFrame(); 12: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13: frame.setVisible(true); 14: } 15: } 16: 17: class AreaFrame extends JFrame { 18: private static final int WIDTH = 400; 19: private static final int HEIGHT = 400; 20: 21: public AreaFrame() { 22: setTitle("Area Test"); 23: setSize(WIDTH, HEIGHT); 24: 25: //add to panel 26: JPanel panel = new AreaPanel(); 27: panel.setBackground(Color.white); 28: add(panel); 29: } 30: } 31: 32: class AreaPanel extends JPanel { 33: private Area area, area1, area2; 34: private JPanel panel; 35: 36: public AreaPanel() { 37: area = new Area(); 38: area1 = new Area(new Ellipse2D.Double(100, 100, 150, 100)); 39: area2 = new Area(new Rectangle2D.Double(150, 150, 150, 100)); 40: 41: //perform operations: using each of these, then re-compile 42: //add, subtract, intersect, exclusiveOr 43: area.add(area1); 44: area.exclusiveOr(area2); 45: //you actually don't need the following two lines 46: //panel = new JPanel(); 47: //add(panel); 48: } 49: 50: public void paintComponent(Graphics g) { 51: super.paintComponent(g); 52: Graphics2D g2 = (Graphics2D)g;

Page 18: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

316

53: g2.draw(area1); 54: g2.draw(area2); 55: g2.setPaint(new GradientPaint(0, 0, Color.red, 300,

100, Color.yellow)); 56: if(area != null) g2.fill(area); 57: } 58: }

10.4.3 การยายภาพ (Translation) การยายภาพไปยงตาแหนงใหม เราตองอาศย class AffineTransform และ method translate(), transform() ดงทแสดงใหดในสวนของ code ทวาดรปสเหลยมน Rectangle2D rectangle = new Rectangle2D.Double(x, y, width, height); g2.draw(rectangle); AffineTransform save = g2.getTransform(); AffineTransform at = new AffineTransform(); at.translate(50, 50); g2.transform(at); g2.setPaint(Color.blue); g2.draw(rectangle); g2.setTransform(save); หลงจากทเราวาดรปสเหลยมตวแรกแลว เรากาหนดให at (object จาก class AffineTransform) เปนเสมอนหนาตางใหมสาหรบการวาด เรากทาการยายหนาตางของการวาดภาพใหมดวยคา (x=50, y=50) หลงจากนนเรากเรยก method transform() เพอกาหนดให Gaphics2D ใชหนาตางใหมน (เราเรยกขนตอนการทางานนวา Coordinate Transformation) และเมอเราเปลยนสใหเปนสนาเงนแลวเรากวาดใหมดวยคาเดมของสเหลยม

ภาพท 10.14 การยายภาพ

เรารวาจดเรมตนของพนทในการวาดภาพนนอยท (0, 0) และเราวาดรปสเหลยมทมมมซายบนอยท (100, 100) เราตองการทจะยายรปสเหลยมนใหไปอยในตาแหนงใหมท (150, 150) เรากอาจทาไดดวยการวาดรปสเหลยมใหมดวยตาแหนงเรมตนท (150, 150) กได แตสงททาไดงายกวากคอ ยายพนทการวาดภาพออกไปท (50, 50) แลวทาการวาดรปสเหลยมตวเดมโดยมจดเรมตนท (100, 100) เชนเดม ซงทาใหเกดภาพเสมอนวารปสเหลยมของเราเกดการยายท (เราไมไดลบรปสเหลยมตวเดมออก เพอใหผอานเหนตาแหนงทงสอง) ผอานอาจสงสยวาทาไมเราถงตองมคาสง AffineTransform save = new AffineTransform() กอนการวาดภาพ และคาสง g2.setTransfrom(save) หลงจากทวาดภาพไปยงตาแหนงใหมแลว ทงนกเพราะวา ถาเราตองการวาดรปอน ๆ ในตาแหนงทมความสมพนธกบรปสเหลยมตว

(100, 100)

(150, 150)

Page 19: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

317

แรก (พนทการวาด – graphics space) เราตองจาคาเกาไวกอน เพอใหสามารถกลบไปใชตาแหนงของการวาดภาพเกานนได ภาพท 10.11 แสดงถงเหตการณทวาน รปทรงอน ๆ จะถกวาดใน graphics space ของสเหลยมตวแรก สวนรปสเหลยมตวทถกยายอยใน graphics space ของตวเอง

ภาพท 10.15 Graphics space

10.4.4 การหมนภาพ (Rotate) ขนตอนการหมนภาพทเราทากไมซบซอนอะไรนก หลงจากทเราวาดวงกลมเสรจเรากยายจดเรมตน (origin) ไปทจดกงกลางของวงกลมดวยคาสง g2.translate(centerX, centerY);

หลงจากนนเรากสรางรปสเหลยมทมขนาดเลกลง (จากรปสเหลยมในตวอยางกอนหนาน) ดวยคาสง Rectangle2D rec = new Rectangle2D.Double(x-50, y-50, width/4, height/3);

ขนตอนตอไปกเปนการวาดรปสเหลยมน โดยเราจะกาหนดใหมการใชปากกาอยสองสคอ สนาเงนและสเหลอง ซงเราจะเกบไวใน array colors Color[] colors= {Color.blue, Color.yellow};

เราจะวาดรปสเหลยมจานวน 32 รปรอบ ๆ จดกงกลางของวงกลม เชนเดยวกบการเคลอนภาพกอนหนาน เราตองทาการหมนพนทการวาด ตามองศาทเราตองการ (ในทน 15 องศา) หลงจากนนเรากเลอกสพรอมกบวาดรปสเหลยม for(int i = 0; i < 32; i++) { AffineTransform at = new AffineTransform(); at.rotate(Math.toRadians(15)); g2.transform(at); g2.setPaint(colors[i % 2]); g2.draw(rec); }

สวนจดกงกลางของวงกลมเรากวาดวงกลมอกวงดวยคาสง Ellipse2D c = new Ellipse2D.Double(); c.setFrameFromCenter(centerX, centerY, centerX + 1, centerY + 1);

Page 20: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

318

g2.draw(c);

แตวงกลมวงนตองวาดกอนทเราจะวาดรปสเหลยมสามสบสองตว (กอนการยาย origin) เพราะไมเชนนนแลววงกลมวงนกจะไปอยใน graphics space ทเราไดกาหนดใหม code ทงหมดของการหมนภาพมดงน

ภาพท 10.16 การหมนภาพ

1: /** 2: Rotation with Graphics2D 3: */ 4: 5: import java.awt.*; 6: import java.awt.geom.*; 7: import javax.swing.*; 8: 9: class Rotate { 10: public static void main(String[] args) { 11: ShapesFrame frame = new ShapesFrame(); 12: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13: frame.setVisible(true); 14: } 15: } 16: 17: class ShapesFrame extends JFrame { 18: private static final int WIDTH = 400; 19: private static final int HEIGHT = 400; 20: 21: public ShapesFrame() { 22: setTitle("Rotation"); 23: setSize(WIDTH, HEIGHT); 24: 25: //add to panel 26: DrawingPanel panel = new DrawingPanel(); 27: panel.setBackground(Color.white); 28: add(panel); 29: } 30: } 31: 32: class DrawingPanel extends JPanel { 33: public void paintComponent(Graphics g) { 34: super.paintComponent(g); 35: Graphics2D g2 = (Graphics2D)g; 36: 37: double x = 100; 38: double y = 100; 39: double width = 200; 40: double height = 150;

Page 21: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

319

41: 42: //create a rectangle 43: Rectangle2D rectangle = new Rectangle2D.Double(x, y, width, height); 44: 45: //create line thickness 46: BasicStroke thickStroke = new BasicStroke(3.0f); 47: g2.setStroke(thickStroke); 48: 49: double centerX = rectangle.getCenterX(); 50: double centerY = rectangle.getCenterY(); 51: double radius = 100.0; 52: 53: //draw a circle 54: Ellipse2D circle = new Ellipse2D.Double(); 55: circle.setFrameFromCenter(centerX, centerY, 56: centerX + radius, centerY + radius); 57: g2.draw(circle); 58: 59: //draw small cicle 60: Ellipse2D c = new Ellipse2D.Double(); 61: c.setFrameFromCenter(centerX, centerY, centerX + 1, centerY + 1); 62: g2.draw(c); 63: 64: //translate origin to center of the circle 65: g2.translate(centerX, centerY); 66: 67: //create a smaller rectangle 68: Rectangle2D rec = new Rectangle2D.Double(x-50,

y-50, width/4, height/3); 69: Color[] colors= {Color.blue, Color.yellow}; 70: 71: //draw rectangles around origin of the circle 72: for(int i = 0; i < 32; i++) { 73: AffineTransform at = new AffineTransform(); 74: at.rotate(Math.toRadians(15)); 75: g2.transform(at); 76: g2.setPaint(colors[i % 2]); 77: g2.draw(rec); 78: } 79: } 80: }

10.4.5 การปรบเปลยนขนาด (Scale) และการเปลยนรป (Shear) การปรบขนาดเราเรยกใช method scale() ดวยคาทเราตองการปรบสองคา โดยทคาแรกจะเปนตวกาหนดการเปลยนขนาดบนแกน x สวนคาทสองจะเปนตวกาหนดการเปลยนขนาดบนแกน y การเรยกใช method scale() ตองทากบ object ทมาจาก class AffineTransform เชน สมมตวาเราม object จาก class AffineTransform ชอ at เรากเรยก method scale() ดงน at.scale(0.5, 05);

การเปลยนรป (shear) นนเรากเรยกใช method shear() เชน at.shear(0.5, 0.0);

การเปลยนรปดวยการเรยกใช method shear() นนกตองกาหนดคาสองตวเชนเดยวกน คาแรกเปนตวกาหนดการเปลยนรปทางแกน x สวนคาทสองเปนตวกาหนดการเปลยนรปทางแกน y

Page 22: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

320

ภาพท 10.17 การใช scale() และ shear()

โปรแกรม TransformShape.java ไดรวมเอาการหมน การปรบขนาด (scale) และการเปลยนรป (shear) ไวในโปรแกรมเดยวกนโดยใหผใชเปนผเลอกวาจะทาอะไรกบรปสเหลยมทอยบนจอ

1: /** 2: Shape transformation 3: */ 4: 5: import java.awt.*; 6: import java.awt.event.*; 7: import java.awt.geom.*; 8: import javax.swing.*; 9: 10: class TransformShape { 11: public static void main(String[] args) { 12: TransformFrame frame = new TransformFrame(); 13: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14: frame.setVisible(true); 15: } 16: } 17: 18: class TransformFrame extends JFrame implements ActionListener, ItemListener { 19: private static final int WIDTH = 300; 20: private static final int HEIGHT = 300; 21: DrawingPanel panel; 22: JButton doit; 23: JComboBox trans; 24: 25: public TransformFrame() { 26: setTitle("Shape Transformation"); 27: setSize(WIDTH, HEIGHT); 28: 29: //list of transformations 30: trans = new JComboBox(new Object[] {"identity",

"rotate", "scale", "shear"}); 31: trans.addItemListener(this); 32: 33: //activation button 34: doit = new JButton("Transform Now"); 35: doit.addActionListener(this); 36: 37: //panel for list and button 38: JPanel top = new JPanel(); 39: top.add(trans); 40: top.add(doit); 41: add(top, BorderLayout.NORTH); 42: 43: //drawing panel 44: panel = new DrawingPanel(); 45: panel.setBackground(Color.white); 46: add(panel, BorderLayout.CENTER); 47: } 48: 49: //when button is hit, get item in the list and repaint 50: public void actionPerformed(ActionEvent e) { 51: panel.setTrans(trans.getSelectedIndex()); 52: panel.render(); 53: }

เรยก method scale() ดวยคา 0.5 และ 0.5

เรยก method shear() ดวยคา 0.5 และ 0.0

รปสเหลยมกอนการ transform

Page 23: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

321

54: 55: //do nothing 56: public void itemStateChanged(ItemEvent e) {} 57: } 58: 59: //drawing panel 60: class DrawingPanel extends JPanel { 61: AffineTransform at = new AffineTransform(); 62: Rectangle2D rectangle; 63: boolean firstTime = true; 64: int width = 100, height = 100; 65: int w, h; 66: 67: //create a rectangle 68: public DrawingPanel() { 69: rectangle = new Rectangle2D.Double(0, 0, width, height); 70: } 71: 72: //repaint graphics 73: public void render() { 74: repaint(); 75: } 76: 77: //get transformation 78: public void setTrans(int index) { 79: switch(index) { 80: case 0: at.setToIdentity(); 81: at.translate(w/2, h/2); break; 82: case 1: at.rotate(Math.toRadians(45)); break; 83: case 2: at.scale(0.5, 0.5); break; 84: case 3: at.shear(0.5, 0.0); break; 85: } 86: } 87: 88: public void paintComponent(Graphics g) { 89: super.paintComponent(g); 90: Graphics2D g2 = (Graphics2D)g; 91: Dimension d = getSize(); 92: w = d.width; 93: h = d.height; 94: 95: //create line thickness 96: BasicStroke thickStroke = new BasicStroke(3.0f); 97: g2.setStroke(thickStroke); 98: 99: //first running 100: if(firstTime) { 101: at.setToIdentity(); 102: at.translate(w/2, h/2); 103: firstTime = false; 104: } 105: //save setting 106: AffineTransform save = g2.getTransform(); 107: //get the center of the panel 108: AffineTransform toCenter = new AffineTransform(); 109: //concatenate center to "at" 110: toCenter.concatenate(at); 111: toCenter.translate(-width/2, -height/2); 112: g2.transform(toCenter); 113: g2.draw(rectangle); 114: 115: //return to previous setting 116: g2.setTransform(save); 117: } 118: }

สงทผอานจะเหนจากการ run โปรแกรม TransformShape.java กคอหนาตางทม drop-down list ใหเลอกอยสตวคอ identity, rotate, scale, และ shear ซงเปนตวเลอกในการเปลยนรปของสเหลยมทอยในหนาตาง เมอ user กดปม Transform Now1

1 เราจะพดถงการสราง GUI ในบทตอไป

Page 24: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

322

ภาพท 10.18 การ run โปรแกรม TransformShape.java

10.4.6 การกาหนดความโปรงแสง (Transparency) การทาใหภาพใดภาพหนงทอยบนอกภาพหนงใหสามารถมองเหนภาพทอยดานหลงไดเราตองใช class AlphaComposite ชวย ดงเชนทเราแสดงใหดในสวนของ code ทเราไดดดแปลงมาจากการหมนภาพกอนหนาน int k = 1; for(int i = 0; i < 32; i++) { Composite original = g2.getComposite(); AffineTransform at = new AffineTransform(); at.rotate(Math.toRadians(15)); g2.transform(at); g2.setComposite(AlphaComposite.getInstance(

AlphaComposite.SRC_OVER, k*0.1f)); k++; if(k > 10) k = 1; g2.setPaint(colors[i % 2]); g2.fill(rec); g2.setComposite(original); }

ขนตอนทเราตองทากอนกคอ เกบ composite ของ graphics2D ไวกอน (เพอจะไดกลบมาเรยกใชทหลง) ดวยการเรยก Composite original = g2.getComposite();

หลงจากนนเรากกาหนดคา composite ใหมทเราตองการดวยการเรยกใช g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, k*0.1f));

โดยทเราตองสงคา SRC_OVER ซงเปนกฎ (mixing rule designator) กาหนดความโปรงแสง พรอมทงคาความโปรงแสง (alpha value) ซงอยระหวาง 0.0f ไปจนถง 1.0f โดยทคาศนยหมายถงความโปรงเตมท (transparent) และคาหนงหมายถงความไมโปรง (opaque) เมอเราวาดเสรจเรากกาหนดคา composite กลบไปสคาเดมดวยคาสง

Page 25: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

323

G2.setComposite(original);

ภาพท 10.19 แสดงถงผลลพธของการ run โปรแกรม TransparencyDemo.java

ภาพท 10.19 การกาหนดคา transparency

10.5 การใช Font ในการกาหนดใหมการวาดตวอกษรดวย font พเศษนนเราจะตองสราง object จาก class Font ดวยชอของ font, style ของ font และขนาดของ font นน ๆ โดยการกาหนดแลว font ท Java กาหนดใหเปน font ทดแทน font ทมอยในเครองตาง ๆ (ซงอาจเปน font ทมากบเครองนน ๆ ในระบบปฏบตการตาง ๆ เชน font ทชอ Helvetica กมชอเปน Arial ใน Windows) มอยทงหมดหาตวคอ

• SansSerif • Serif • Monospaced • Dialog • DialogInput

Java จะจดการกาหนด font ทดแทนเหลานใหกบ font ทมอยในเครองนน ๆ เชน SansSerif แทน Arial เปนตน ตวอยางการกาหนด font เชน Font serif = new Font("Serif", Font.BOLD, 36); Parameter ในการเรยกใช constructor ของ class Font มอยสามตวคอ ชอของ font, style ทใช และขนาดทใช โดย Java ม style ทใชอย เชน Font.PLAIN Font.BOLD Font.ITALIC เราอาจเรยกใช style เหลานรวมกนได เชน Font.BOLD + Font.ITALIC เมอเราสราง font เสรจเรากกาหนดใหพนทการวาดของเราใช font น เชน

Page 26: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

324

Font serif = new Font("Serif", Font.BOLD, 36); g2.setFont(serif); g2.drawString("Hello Chiang Mai", x, y);

เนองจากวาผใชอาจกาหนด font ขนใชเองดงนนเพอใหการแสดงขอความเปนไปอยางด (สวยงาม เชน อยกงกลางของพนทการวาด) เราตองหาคณลกษณะของ font ทใช ซงเราทาไดดวยการสราง object จาก class FontRenderContext เชน FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = serif.getStringBounds(message, context); เมอเราได context ของ font แลวเรากสงขอความ และ context ดงกลาวไปให method getStringBounds() ทมอยใน class Font ซง method ตวนจะใหคาของกรอบสเหลยมทลอมรอบขอความดงกลาว เรากสามารถใชขอมลนในการวาดขอความใหไปปรากฏอยในหนาตางได ในการวาดขอความนนเราจาเปนทจะตองรจกกบกรอบสเหลยมดงกลาววาเกบขอมลอะไรไวบาง baseline เสนสมมตทอยใตตวอกษร ascent ระยะจาก baseline ไปจนถงดานบนสดของตวอกษร เชน ดานบนสดของตวอกษร 'b' descent ระยะจาก baseline ไปจนถงดานลางสดของตวอกษร เชน ดานลางสดของ 'g' leading ระยะหางระหวางแถว height ความสงจาก baseline ถง baseline (ascent + leading + descent)

ภาพท 10.20 ขอมลเกยวกบ font

ในการวาดขอความใหไปอยตรงกลางหนาตางนนเราตองหาจดบนซายของขอความ และหา baseline (หาคา ascent บวกกบคา y) เชน double x = (getWidth() - bounds.getWidth()) / 2; double y = (getHeight() - bounds.getHeight()) / 2; double ascent = -bounds.getY(); double baseY = y + ascent; g2.drawString(message, (int)x, (int)baseY);

ถาเราตองการหาคา leading และคา descent เราตองใช class LineMetrics ชวย เชน LineMetrics metrics = serif.getLineMetrics(message, context); float descent = metrics.getDescent(); float leading = metrics.getLeading();

ผลลพธทเราไดจากการ run โปรแกรม DrawingFont.java คอ

p o c k e t

descent

ascent

baseline leading

height

Page 27: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

325

ภาพท 10.21 ผลลพธของโปรแกรม DrawingFont.java

และ code ของโปรแกรมมดงน

1: /** 2: Drawing special font 3: */ 4: 5: import java.awt.*; 6: import java.awt.font.*; 7: import java.awt.geom.*; 8: import javax.swing.*; 9: 10: class DrawingFont { 11: public static void main(String[] args) { 12: FontFrame frame = new FontFrame(); 13: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14: frame.setVisible(true); 15: } 16: } 17: 18: //frame contains message panel 19: class FontFrame extends JFrame { 20: private static final int WIDTH = 300; 21: private static final int HEIGHT = 200; 22: 23: public FontFrame() { 24: setTitle("Drawing Font"); 25: setSize(WIDTH, HEIGHT); 26: 27: //add to panel 28: FontPanel panel = new FontPanel(); 29: add(panel); 30: } 31: } 32: 33: //panel for message to be drawn on 34: class FontPanel extends JPanel { 35: 36: public void paintComponent(Graphics g) { 37: super.paintComponent(g); 38: Graphics2D g2 = (Graphics2D)g; 39: String message = "Hello Chiang Mai"; 40: 41: //set font 42: Font serif = new Font("Serif", Font.BOLD, 36); 43: g2.setFont(serif); 44: 45: //calculate size of message 46: FontRenderContext context = g2.getFontRenderContext(); 47: Rectangle2D bounds = serif.getStringBounds(message, context); 48: 49: //set top-left corner of message 50: double x = (getWidth() - bounds.getWidth()) / 2;

Page 28: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

326

51: double y = (getHeight() - bounds.getHeight()) / 2; 52: 53: //add ascent to y to get baseline 54: double ascent = -bounds.getY(); 55: double baseY = y + ascent; 56: 57: //draw the message 58: g.drawString(message, (int)x, (int)baseY); 59: } 60: }

ถาหากวาเราตองการรวาเครองทเราใชอยม font อะไรบางเรากเขยน code เพอแสดง font เหลานนดงน String[] names = GraphicsEnvironment

.getLocalGraphicsEnvironment()

.getAvailableFontFamilyNames(); for(String fontName : names) System.out.println(fontName);

[การใช class FontMetrics ในการแสดงขอความ] วธการอกอนหนงทเราสามารถนามาใชในการแสดงขอความ กคอการใช class FontMetrics วธการกคลาย ๆ กบการใช class FontRenderContext ทเราทากอนหนาน FontMetrics fm = g2.getFontMetrics(); int width = fm.stringWidth(message); int ascent = fm.getAscent(); int x = getWidth() / 2 - 2 - width / 2; int y = getHeight() / 2 + ascent / 2; g.drawString(message, x, y);

ผลลพธทเราไดกเหมอนกบทเราไดในโปรแกรม DrawFont.java 10.6 การแสดง Image ในการแสดงภาพทอยในรปแบบตาง ๆ เชน GIF, JPG และอน ๆ นนเราสามารถทจะทาไดดวยการอานไฟลทเกบ image นนดวย method จาก class Image เชน Image image = ImageIO.read(new File("cross.gif"));

หรอถาไฟลอยบน Internet เรากใช String URLname = "…"; Image image = ImageIO.read(new URL(URLname));

โปรแกรม DisplayImage.java แสดงภาพของไฟล cross.gif ในรปแบบทเรยกวา tile (เชนการแสดงภาพ background ของ Windows)

1: /** 2: Displaying and image 3: */ 4: 5: import java.awt.*; 6: import java.io.*; 7: import javax.imageio.*; 8: import javax.swing.*; 9: 10: class DisplayImage { 11: public static void main(String[] args) { 12: ImageFrame frame = new ImageFrame(); 13: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14: frame.setVisible(true); 15: }

Page 29: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

327

16: } 17: 18: //frame contains message panel 19: class ImageFrame extends JFrame { 20: private static final int WIDTH = 300; 21: private static final int HEIGHT = 200; 22: 23: public ImageFrame() { 24: setTitle("Display Image"); 25: setSize(WIDTH, HEIGHT); 26: 27: //add to panel 28: ImagePanel panel = new ImagePanel(); 29: add(panel); 30: } 31: } 32: 33: //panel for image 34: class ImagePanel extends JPanel { 35: private Image image; 36: 37: public ImagePanel() { 38: try { 39: image = ImageIO.read(new File("cross.gif")); 40: } 41: catch(IOException e) { 42: e.printStackTrace(); 43: } 44: } 45: 46: public void paintComponent(Graphics g) { 47: super.paintComponent(g); 48: Graphics2D g2 = (Graphics2D)g; 49: 50: if(image == null) return; 51: 52: //calculate width and height of this image 53: int width = image.getWidth(this); 54: int height = image.getHeight(this); 55: 56: //display image once at (0, 0) 57: g2.drawImage(image, 0, 0, null); 58: 59: //copy that image over the entire window 60: for(int i = 0; i * width <= getWidth(); i++) 61: for(int j = 0; j * height <= getHeight(); j++) 62: if(i + j > 0) 63: g2.copyArea(0, 0, width, height, i*width, j*height); 64: } 65: }

หลงจากทเราอานไฟล cross.gif ไดแลวในบรรทดท 39 เรากสง image นไปให method drawImage() ในบรรทดท 57 ซงเปนการแสดง image นทตาแหนง (0, 0) และเพอใหรป image ตวเดยวกนนแสดงจนเตมหนาตางเรากเรยก method copyArea() ในบรรทดท 63 ผลลพธทเราไดคอ

Page 30: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

328

ภาพท 10.22 การแสดง image ออกทางหนาตาง

Method copyArea() ม parameter อยหกตวคอ สองตวแรก (x, y) เปนจดพกดบนซายของ image ทมอย ตวทสามเปนความกวางของ image ตวทสเปนความสงของ image ตวทหาและหกเปนระยะทางจาก image ไปยงกรอบของหนาตาง (หรอพนท) ทตองการวาด 10.7 การตดภาพ (Clipping) การตดภาพใน Java นนเราเรยกใชคาสง clip() ของ Graphics2D เชน g2.clip(clipShape);

ภาพตวอยางของการ run โปรแกรม Clipping.java ในครงแรกกอนการเรยก clip()

ภาพท 10.23 ภาพแสดงขอความกอนการ clip

การหา outline ของขอความใน Java เราจะใช font render context ชวยดวยการเรยก FontRenderContext context = g2.getFontRenderContext();

เมอกาหนด font ไดแลว (Font f = new Font("Serif", Font.PLAIN, 80);) เรากสราง TextLayout object จาก context, font และ String ทเกบขอความทเราตองการแสดง TextLayout layout = new TextLayout("Chiang Mai", f, context);

หลงจากทได layout แลวสงทเราตองทาตอไปคอ การหา outline ของตวอกษรทอยใน layout นน เนองจากวา method getOutline() สง object ทมาจาก class Shape ดวยตาแหนง (0, 0) ซงเปนตาแหนงทไมเหมาะสมสาหรบการวาดดวย method ตาง ๆ ดงนนเราจงตองยายจดเรมตนไปท (0, 80) แทน (เราไมตองยายกไดแตภาพทไดอาจไมเปนไปตามทตงใจไว)

Page 31: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

329

AffineTransform t = AffineTransform.getTranslateInstance(0, 80); Shape outline = layout.getOutline(t);

ขนตอนสดทายทเราตองทากคอการนาเอา outline ไปแปะไวกบ clipping shape นน clipShape.append(outline, false);

กระบวนการดงกลาวทงหมดเราเขยนอยภายใน method makeClip() ซงเราจะเรยกใชใน method paintComponent() ซงมสวนประกอบดงน public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; if(clipShape == null) clipShape = makeClip(g2); g2.draw(clipShape); //clip activated with this command g2.clip(clipShape); //draw simple line pattern p = new Point2D.Double(0, 0); for(int i = 0; i < LINES; i++) { double x = (2 * getWidth() * i) / LINES; double y = (2 * getHeight() * (LINES - 1 - i)) / LINES; q = new Point2D.Double(x, y); g2.draw(new Line2D.Double(p, q)); } }

ภาพทไดจากการ run ครงแรกนนเราไมไดเรยก g2.clip(clipShape) ดงทเหนดานบนน หลงจากทเรา compile ใหมดวยการเรยก method ดงกลาวผลลพธทเราไดคอ

ภาพท 10.24 ภาพแสดงขอความหลงจากการเรยก g2.clip(clipShape)

สวนของ code ทสราง line pattern กอยใน for/loop ทอยในสวนสดทายของ method paintComponent() ซงเปนลายงาย ๆ ทใชการแสดงเสนจานวนเทากบหาสบเสนเปนหลก Code ทงหมดของ Clipping.java กมดงน

1: /** 2: Clipping 3: */ 4: 5: import java.awt.*; 6: import java.awt.geom.*; 7: import java.awt.font.*; 8: import javax.swing.*; 9: 10: class Clipping { 11: public static void main(String[] args) { 12: JFrame frame = new ClipFrame(); 13: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Page 32: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

330

14: frame.setBackground(Color.black); 15: frame.setVisible(true); 16: } 17: } 18: 19: class ClipFrame extends JFrame { 20: private static final int WIDTH = 400; 21: private static final int HEIGHT = 150; 22: 23: public ClipFrame() { 24: setTitle("Clip Test"); 25: setSize(WIDTH, HEIGHT); 26: JPanel panel = new ClipPanel(); 27: panel.setBackground(Color.black); 28: add(panel); 29: } 30: } 31: 32: class ClipPanel extends JPanel { 33: private Point2D p, q; 34: private Shape clipShape; 35: private final int LINES = 50; 36: 37: public void paintComponent(Graphics g) { 38: super.paintComponent(g); 39: Graphics2D g2 = (Graphics2D)g; 40: 41: if(clipShape == null) clipShape = makeClip(g2); 42: g2.draw(clipShape); 43: 44: //clip activated with this command 45: g2.clip(clipShape); 46: 47: //draw simple line pattern 48: p = new Point2D.Double(0, 0); 49: for(int i = 0; i < LINES; i++) { 50: double x = (2 * getWidth() * i) / LINES; 51: double y = (2 * getHeight() * (LINES - 1 - i)) / LINES; 52: q = new Point2D.Double(x, y); 53: g2.draw(new Line2D.Double(p, q)); 54: } 55: } 56: 57: //create clip shape 58: private Shape makeClip(Graphics2D g2) { 59: //create font render context and gradient paint 60: FontRenderContext context = g2.getFontRenderContext(); 61: g2.setPaint(new GradientPaint(0, 0, Color.red, 300,

100, Color.yellow)); 62: Font f = new Font("Serif", Font.PLAIN, 80); 63: //shape to return 64: GeneralPath clipShape = new GeneralPath(); 65: 66: //create TextLayout object with font and context provided above 67: TextLayout layout = new TextLayout("Chiang Mai", f, context); 68: //translate base point to (0, 80) and set outline 69: AffineTransform t = AffineTransform.getTranslateInstance(0, 80); 70: Shape outline = layout.getOutline(t); 71: //append outline to the clipping shape 72: clipShape.append(outline, false); 73: 74: return clipShape; 75: } 76: }

10.8 การแสดงภาพเคลอนไหวอยางงาย (Simple Animation) การสรางภาพเคลอนไหวใน Java นนทาไดสองวธคอ 1) ใช Thread และ 2) ใช Timer เราจะเรมกนดวยการใช Timer เพราะวาเปนการทาทงายทสด

Page 33: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

331

10.8.1 การใช class Timer ควบคมการเคลอนทของภาพ โปรแกรมตวอยางทเราทาเปนการแสดงขอความทวงจากดานหนงของ frame ไปยงอกดานหนง ซงในการทาดงกลาวเราตองใชเครองมอท Java เรยกวา Action Event เปนตวควบคม ลองมาด code กน

1: /** 2: Moving text to the right 3: */ 4: 5: import java.awt.*; 6: import java.awt.Font.*; 7: import java.awt.event.*; 8: import javax.swing.*; 9: 10: class MovingText extends JFrame { 11: private static final int WIDTH = 300; 12: private static final int HEIGHT = 100; 13: 14: public MovingText() { 15: //add to panel 16: FontPanel panel = new FontPanel(); 17: add(panel); 18: 19: //create timer for panel 20: Timer timer = new Timer(50, panel); 21: timer.start(); 22: } 23: 24: public static void main(String[] args) { 25: MovingText frame = new MovingText(); 26: frame.setTitle("Moving Text"); 27: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 28: frame.setSize(WIDTH, HEIGHT); 29: frame.setVisible(true); 30: } 31: } 32: 33: //panel for message to be drawn on 34: class FontPanel extends JPanel implements ActionListener { 35: private String message = "Hello"; 36: private int x = 0; 37: private int y = 40; 38: private Font serif = new Font("Serif", Font.BOLD, 24); 39: 40: //handle event 41: public void actionPerformed(ActionEvent e) { 42: repaint(); 43: } 44: 45: //paint message 46: public void paintComponent(Graphics g) { 47: super.paintComponent(g); 48: Graphics2D g2 = (Graphics2D)g; 49: 50: //set font style 51: g2.setFont(serif); 52: 53: //reset x when message passes the right border 54: if(x > getWidth()) x = 0; 55: 56: //incrementing step 57: x += 3; 58: 59: //draw the message 60: g2.drawString(message, x, y); 61: } 62: }

Page 34: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

332

หลงจากทเราสราง panel สาหรบการวาดขอความแลว เรากสราง object จาก class Timer ทเปนตวควบคม panel ทก ๆ ครงทเวลาหมดไป 1/25 วนาท (บรรทดท 20 – 21) panel จะถกวาดใหมดวยระยะเวลาทหางกนดงกลาว การวาดใหมทกครงเกดขนจากการเรยก method repaint() ใน method actionPerformed() ซงจะถกเรยกทก ๆ 1/25 วนาทดงทกลาวไวแลวและทกครงของการวาดใหมเรากาหนดใหคา x เพมขนสามหนวย (บรรทดท 57) และจะกลบไปเรมทจดเรมตนใหมเมอคา x มากกวาคาสงสดของความกวางของหนาตาง (บรรทดท 54) โปรแกรม MovingText.java ทเราเขยนขนเปนโปรแกรมอยางงายทไมซบซอนมากมายนก แตถาผอานตองการทจะใหการเคลอนไหวของภาพดขน กตองใชวธการอน เชน การใช Thread กบ การสราง off-screen image โดยสรปแลวกระบวนการทเกยวของกบการสรางภาพเคลอนไหวทดนน จะมขนตอนตาง ๆ ดงน

• กระบวนการสราง loop สาหรบภาพเคลอนไหว • กระบวนการสรางภาพ graphics • กระบวนการกาจดการสน (flashing, flicker) ของภาพ • กระบวนการเคลอนยายภาพบนหนาจอ

โปรแกรม MovingTextApp.java และโปรแกรม BouncingCrossBall.java จะเปนโปรแกรมตวอยางททากระบวนการสรางภาพเคลอนไหวดงกลาว เราจะเรมดวยโปรแกรม MovingTextApp.java 10.8.2 การสราง Off-screen Image และการสรางภาพเคลอนไหวดวย Thread การวาดภาพทซบซอนหรอซากนหลาย ๆ หนนน (เชนภาพการเคลอนทของตวหนงสอ การเคลอนทของ object ในหนาตาง) วธการทดทสดในการรกษาความคมชด และไมมการสนของภาพ (flashing หรอ flicker) เมอมการเคลอนไหว กคอการสรางภาพไวในทใดทหนงกอนนามาแปะไวในจอภาพ ซงทนยมกนกคอการสราง off-screen image หรอทเรยกวา buffered image 10.8.2.1 การเคลอนยายขอความ โปรแกรม MovingTextApp.java ทเราเขยนขนนใช interface Runnable เปนตวสราง thread ควบคมการเคลอนทของขอความทถกาหนดไว โดยม class หลก ๆ อยสอง class คอ class MovingTextApp และ class MovingTextPanel ซงตวหลงจะเปนตวสาคญของการสราง animation ลองมาด code ทงหมดกน

1: /** 2: Move string both directions, starting on the top-left 3: then back from bottom-right, repeatedly. 4: */ 5: 6: import java.awt.*; 7: import java.awt.font.*; 8: import java.awt.geom.*; 9: import javax.swing.*; 10: 11: public class MovingTextApp extends JFrame { 12: private final int WIDTH = 300; 13: private final int HEIGHT = 210; 14: MovingTextPanel panel; 15: 16: public MovingTextApp(String text) { 17: setTitle("Moving Text"); 18: setSize(WIDTH, HEIGHT); 19: setBackground(Color.black); 20: 21: //add animation panel to frame 22: panel = new MovingTextPanel(text); 23: add(panel); 24: 25: //start animation

Page 35: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

333

26: panel.start(); 27: } 28: 29: public static void main(String[] args) { 30: JFrame frame = new MovingTextApp("Hello, Chiang Mai"); 31: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 32: frame.setVisible(true); 33: } 34: } 35: 36: class MovingTextPanel extends JPanel implements Runnable { 37: protected Thread thread; //running thread 38: protected Image image; //image 39: protected Graphics offScreen; //off-screen image 40: protected String text; //string to display 41: protected Font font; //font used 42: protected int x, y; //position of string 43: protected int delay = 8; //default delay time 44: protected int offset = 1; //incremental moving step 45: protected Dimension d; //panel's size 46: boolean moveRight; //control moving direction 47: 48: //setup attributes 49: public MovingTextPanel(String message) { 50: setSize(300, 200); 51: font = new Font("Sans-serif", Font.BOLD, 24); 52: this.text = message; 53: 54: //set initial position of the text 55: d = getSize(); 56: x = -d.width; 57: y = font.getSize(); 58: moveRight = true; 59: } 60: 61: //paint image 62: public void paintComponent(Graphics g) { 63: update(g); 64: } 65: 66: //update image 67: public void update(Graphics g) { 68: super.paintComponent(g); 69: Graphics2D g2 = (Graphics2D)g; 70: 71: //create off-screen image if this is the first time 72: if(image == null) { 73: image = createImage(d.width, d.height); 74: offScreen = image.getGraphics(); 75: } 76: 77: //use FontRenderContext to get text's size 78: offScreen.setFont(font); 79: FontRenderContext context = g2.getFontRenderContext(); 80: Rectangle2D bounds = font.getStringBounds(text, context); 81: 82: //adjust the position of the text from previous frame 83: if(moveRight) 84: x += offset; 85: else 86: x -= offset; 87: 88: //if the text is completely off to the right end 89: //move the position to the lower right corner 90: if(x > d.width) { 91: x = d.width; 92: y = d.height - (int)bounds.getHeight(); 93: moveRight = false; 94: } 95: //if the text is completely off to the left end 96: //move the position back to the upper left corner 97: if(x < (int)-bounds.getWidth()) { 98: x = (int)-bounds.getWidth(); 99: y = font.getSize();

Page 36: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

334

100: moveRight = true; 101: } 102: 103: //set the pen color and draw the background 104: offScreen.setColor(Color.black); 105: offScreen.fillRect(0, 0, d.width, d.height); 106: 107: //set the pen color and draw the text 108: offScreen.setColor(Color.green); 109: offScreen.drawString(text, x, y); 110: 111: //copy the off-screen image to the screen 112: g2.drawImage(image, 0, 0, null); 113: } 114: 115: //start the thread 116: public void start() { 117: thread = new Thread(this); 118: thread.start(); 119: } 120: 121: //stop the thread 122: public void stop() { 123: thread = null; 124: } 125: 126: //run current thread 127: public void run() { 128: while(Thread.currentThread() == this.thread) { 129: try { 130: Thread.currentThread().sleep(delay); 131: } 132: catch(InterruptedException e) {} 133: 134: //update image 135: repaint(); 136: } 137: } 138: }

Class MovingTextApp เปน class ทเรากาหนด frame ทเราตองการแสดงผลของการเคลอนทของขอความทเรากาหนดไว (ผานทาง constructor) ซงภายใน frame นเราจะทาการ add panel การทางานของ animation เขาไป เรากาหนดใหจดเรมตนของขอความอยท (-d.width, font.getSize() – บรรทดท 56 และ 57) ทงนกเนองจากวาเรายงไมสามารถเรยกใช FontRenderContext ใน constructor ไดเราจงกาหนดจดเรมตนไวทตาแหนงน ผอานตองคานงวา (x, y) เปนจดเรมตนของขอความ (บน-ซาย) เพราะฉะนนเราจงตองใหตาแหนงนเปนตาแหนงทอยนอกกรอบของ panel หลงจากท x เปลยนคาตาม step ทกาหนดไวตวอกษรทอยหลงสดของขอความกจะคอย ๆ แสดงใหเราเหนภายใน panel (ในบรรทดท 84 หรอ 86) สวนการตรวจสอบคาของ x ทงทออกนอกกรอบทางขวา และทางซายเราทาดงน if(x > d.width) { x = d.width; y = d.height - (int)bounds.getHeight(); moveRight = false; } if(x < (int)-bounds.getWidth()) { x = (int)-bounds.getWidth(); y = font.getSize(); moveRight = true; }

เรารวา d.width เปนคาสงสดทางขวาดงนนถาคา x ของขอความมากกวา d.width เรากกาหนดให x มคาเปน d.width พรอมกบกาหนดใหคา y เปนคาทมาจาก คาของ bounds.getHeight() ลบออกจาก d.height แตถา x นอยกวาความยาวของขอความ (-

Page 37: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

335

bounds.getWidth()) เรากกาหนดให x เปน -bounds.getWidth() พรอมกบกาหนดคาของ y ใหเปน font.getSize() ซงเปนคาทหาไดงายทสด (มวธการอนทดกวา) สวนคาของ moveRight จะเปนตวกาหนดทศทางการเคลอนทของขอความเมอการเคลอนททางใดทางหนงสนสดลง การสราง off-screen image กทาไดดวยการเรยก method drawImage() ซงกอนทจะเรยกใชนนเราตองสราง off-screen image ดวยคาสง if(image == null) { image = createImage(d.width, d.height); offScreen = image.getGraphics(); }

เราสราง image ดวย method createImage() ดวยขนาดของ panel และสราง off-screen image ดวย image ทเราสรางผานทาง method getGraphics() off-screen image จะเปนท ๆ เราเขยนขอความตามทกาหนดไว รวมไปถงคาตาง ๆ ทเราตองการแสดง เชน สของพนหลง และสของปากกา เปนตน เมอเราได image แลวเรากสง image ทไดไปให method drawImage() ของ graphics device ทาการแสดงใหเรา offScreen.setColor(Color.black); offScreen.fillRect(0, 0, d.width, d.height); offScreen.setColor(Color.green); offScreen.drawString(text, x, y); g2.drawImage(image, 0, 0, null); ภาพท 10.19 แสดงผลลพธทเกดขนจากการ run โปรแกรม

ภาพท 10.25 ผลลพธบางสวนของโปรแกรม MovingTextApp.java

10.8.2.2 การเคลอนยาย image (image animation) ภาพเคลอนไหวเกดจากการทเรานาเอาภาพทไดรบการเปลยนแปลงในรปแบบตาง ๆ มาแสดงในเวลาทตางกน ทาใหดเสมอนวาภาพเกดการเคลอนท ดงทเราแสดงใหดในโปรแกรม MovingTextApp.java การแสดงภาพเคลอนไหวของ image กคลายกน เพยงแตเราแทนขอความดวย image ทเราตองการใช กระบวนการทเราทาในโปรแกรม BouncingCrossBall.java คอ หลงจากทเราไดภาพจากไฟลแลว xball = ImageIO.read(new File("cross.gif"));

เรากสราง off-screen graphics (offscreen) จาก buffered image (bi) ผอานควรสงเกตวาเราสราง buffered image ดวยขนาดของพนทการวาด ซงคานวณมาจากขนาดทถกกาหนดไว

Page 38: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

336

(getSize()) ตวแปรตวทสามใน constructor ของ BufferedImage() เปนคาของส (alpha value) [กระบวนการนตางจากการสราง off-screen image ในโปรแกรม MovingTextApp.java กอนหนานเราสราง image ดวยการเรยกใช createImage() หลงจากนนกกาหนด off-screen image จาก image ทสรางดวยการเรยก getGraphics()] สวนกระบวนการทเหลอกคลาย ๆ กน Dimension d = getSize(); bi = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB); offscreen = bi.createGraphics();

หลงจากนนเรากสง image ทตองการวาดไปให off-screen graphics context ดวยคาสง offscreen.drawImage(xball, at, this) โดยท at จะเปนพนทการวาดภาพใหมทเราไดคานวณขนดง code ทแสดงใหดน x += dx; y += dy; if(x < 0 || x > d.width - width) dx = -dx; if(y < 0 || y > d.height - height) dy = -dy; AffineTransform at = new AffineTransform(); at.setToIdentity(); at.translate(x, y); offscreen.drawImage(xball, at, this);

คา dx และ dy เปนระยะทางการเปลยนตาแหนงของ image บนแกน x และแกน y โดยเราตองตรวจสอบดวาคาทเปลยนไปนนอยในกรอบของพนททเราไดกาหนดไว ถาเกนไปทางใดทางหนงเรากเปลยนทศทางการเคลอนทของ image ไปในทางตรงกนขาม เราจะใชคา x และ y ทหาไดใหมนเปนคาสาหรบการยายพนทของการวาดออกไป (เหมอนทเราทากอนหนานในเรองของการยายภาพ) โดยการสราง object จาก class AffineTransform หลงจากยายเสรจเรากวาด image ลงบนพนทดงกลาว หลงจากนนเรากสง object ไปให graphics context เพอแสดงผล Graphics2D g2 = (Graphics2D)g; g2.drawImage(bi, 0, 0, null);

และเพอเปนการชวยคนหนวยความจาใหกบระบบเรากเรยกใช method dispose() กบ off-screen image น offscreen.dispose();

อกครงหนง ขนตอนการทาให image ของเราเคลอนทนนเกดขนจากการยายจอภาพดวยการใช method translate() เหมอนกบทเราไดทามากอนหนา ภาพท 10.26 แสดงขนตอนการเรยก method ทเกดขนในโปรแกรม BouncingCrossBall.java

Page 39: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

337

ภาพท 10.26 ขนตอนการแสดงภาพเคลอนไหว

การทาให flashing หมดไปจากการแสดงผลนนทาไดสองวธคอ 1) เรยกใช update() และ 2) ใช double buffering (off-screen image) การ override method update() จาเปนเพราะวาการเรยก method repaint() จะไปเรยก method update() ซงจะทาใหเกดการ clear พนหลงของพนทในการวาด ดงนนการเขยน update() ขนใหมจงทาใหกระบวนการทไมจาเปน เชน clear พนหลงดงทกลาวมาแลวหมดไป แตกยงไมการนตวา repaint() จะไปเรยก update() โดยตรง(อาจไปเรยก paintComponent() กได) ดงนนวธการทจะใหเกดการเรยก update() กคอให paintComponent() เรยก update() แทน กระบวนการอกอนหนงทจะชวยลดความไมสวยงามของภาพเคลอนไหวกคอการใช double buffering ซงโปรแกรม BouncingCrossBall.java กไดนามาชวยใชเหมอนกน วธการกคอวาด frame ทงหมดใหมใน buffer แลวจงนามาแปะไวใน graphics context ดงทไดอธบายไวในขนตอนของการสราง image กอนหนาน code ของโปรแกรม BouncingCrossBall.java มดงน

1: /** 2: Bouncing cross-ball image 3: */ 4: 5: import java.awt.*; 6: import java.awt.event.*; 7: import java.io.*; 8: import java.awt.image.*; 9: import java.awt.geom.*; 10: import javax.imageio.*; 11: import javax.swing.*; 12: 13: class BouncingCrossBall extends JFrame { 14: private final int WIDTH = 300; 15: private final int HEIGHT = 200; 16: CrossBallCanvas canvas; 17: 18: public BouncingCrossBall() { 19: setTitle("Bouncing ball"); 20: setSize(WIDTH, HEIGHT); 21: 22: //add animation canvas to frame 23: canvas = new CrossBallCanvas(); 24: canvas.setBackground(Color.white);

canvas.start(); Thread thread = new Thread(this); thread.start();

run()

repaint()

paintComponent()

update()

stop()

Page 40: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

338

25: add(canvas); 26: 27: //start animation 28: canvas.start(); 29: } 30: 31: public static void main(String[] args) { 32: JFrame frame = new BouncingCrossBall(); 33: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 34: frame.setVisible(true); 35: } 36: } 37: 38: //animation canvas 39: class CrossBallCanvas extends JPanel implements Runnable { 40: Thread thread; //animation control thread 41: BufferedImage bi; //buffer image 42: Image xball; //image used 43: Graphics2D offscreen; //off screen graphics 44: int x, y; //coordinates 45: int dx, dy; //increment amount on x and y 46: int width, height; //width and height of image 47: long delay = 100; //sleep time 48: 49: public CrossBallCanvas() { 50: //get the image 51: try { 52: xball = ImageIO.read(new File("cross.gif")); 53: } 54: catch(IOException e) {} 55: 56: //incremental units on x and y directions 57: dx = dy = 10; 58: } 59: 60: //paint graphics 61: public void paintComponent(Graphics g) { 62: super.paintComponent(g); 63: update(g); 64: } 65: 66: //update graphics 67: public void update(Graphics g) { 68: super.paintComponent(g); 69: if(xball == null) { 70: System.out.println("no image file"); 71: return; 72: } 73: 74: //calculate size of image 75: width = xball.getWidth(this); 76: height = xball.getWidth(this); 77: 78: //get the size of the panel 79: Dimension d = getSize(); 80: //create a buffered image 81: bi = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB); 82: //get graphics context 83: offscreen = bi.createGraphics(); 84: 85: //update incremental amount 86: x += dx; 87: y += dy; 88: 89: //restrict image within the boundary of the canvas 90: if(x < 0 || x > d.width - width) 91: dx = -dx; 92: if(y < 0 || y > d.height - height) 93: dy = -dy; 94: 95: //transform the image 96: AffineTransform at = new AffineTransform(); 97: at.setToIdentity();

Page 41: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

339

98: at.translate(x, y); 99: offscreen.drawImage(xball, at, this); 100: 101: //draw buffered image to graphics context 102: Graphics2D g2 = (Graphics2D)g; 103: g2.drawImage(bi, 0, 0, null); 104: 105: offscreen.dispose(); //return memory 106: } 107: 108: //start the thread 109: public void start() { 110: thread = new Thread(this); 111: thread.start(); 112: } 113: 114: //stop the thread 115: public void stop() { 116: if(thread != null) 117: thread.interrupt(); 118: thread = null; 119: } 120: 121: //run the thread 122: public void run() { 123: long start = System.currentTimeMillis(); 124: while(Thread.currentThread() == thread) { 125: try { 126: start += delay; 127: Thread.currentThread().sleep(

Math.max(0, start-System.currentTimeMillis())); 128: } 129: catch(InterruptedException ie) {} 130: 131: //update canvas 132: repaint(); 133: } 134: } 135: }

การกาหนดคา delay ภายใน loop ของการแสดงภาพในแตละ frame อาจไมอยในชวงเวลาทเทากน วธการแกกคอ จาเวลาเรมตนของ loop ไว ใชคานบวกกบคา delay แลวนาเอาคาของเวลาทหาไดทกครงท loop ประมวลผลมาหกออก ดงทไดแสดงไวใน method run() ผลลพธทไดจากโปรแกรมคอ

ภาพท 10.27 การเคลอนไหวของ image

ถาเราไมตองการทจะเรยกใช method translate() ของ class AffineTransform ในการยายจดวาดภาพเรากสราง off-screen image ของภาพดวยตาแหนง (0, 0) ใน method drawImage()

Page 42: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

340

ดงน offscreen.drawImage(xball, 0, 0, this); หลงจากนนกสง off-screen image ตวนไปให graphics context พรอมกบตาแหนงของ (x, y) ดงน g2.drawImage(bi, x, y, null); เชนทเราแสดงใหดในสวนของ code น Dimension d = getSize(); bi = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB); offscreen = bi.createGraphics(); offscreen.drawImage(xball, 0, 0, this); x += dx; y += dy; if(x < 0 || x > d.width - width) dx = -dx; if(y < 0 || y > d.height - height) dy = -dy; Graphics2D g2 = (Graphics2D)g; g2.drawImage(bi, x, y, null);

การใช AffineTransform นนทาใหเราสามารถทาการเปลยนรป (transform) ของสงทเราตองการแสดงออกทางหนาจอไดดและมลกเลนมากขน เชน การทาใหเกดความโปรงแสง การยอหรอขยายภาพ แตถาเราตองการเพยงแคภาพทเคลอนไหวแตไมเปลยนรป การใช off-screen image กนาจะเพยงพอแลว [การใช mouse เคลอนยายภาพ] การยายภาพดวย mouse ทาไดดวยการคอยฟงเหตการณ (event listener) ของ mouse วาเคลอนทไปอย ณ ตาแหนงใด เมอเราหาตาแหนงทวาไดแลวเรากทาการวาดใหม ณ ตาแหนงนซงกคลายกบโปรแกรม BouncingCrossBall.java ทเราทากอนหนาน ตางกนกเพยงแตเราใช mouse เปนตวลากภาพไปสตาแหนงทเราตองการเทานนเอง

1: /** 2: Bouncing cross-ball image 3: */ 4: 5: import java.awt.*; 6: import java.awt.event.*; 7: import java.io.*; 8: import java.awt.image.*; 9: import java.awt.geom.*; 10: import javax.imageio.*; 11: import javax.swing.*; 12: 13: class MovingCrossBall extends JFrame { 14: private final int WIDTH = 300; 15: private final int HEIGHT = 200; 16: CrossBallCanvas canvas; 17: 18: public MovingCrossBall() { 19: setTitle("Bouncing ball"); 20: setSize(WIDTH, HEIGHT); 21: 22: //add animation canvas to frame 23: canvas = new CrossBallCanvas(); 24: canvas.setBackground(Color.white); 25: add(canvas); 26: } 27: 28: public static void main(String[] args) { 29: JFrame frame = new MovingCrossBall(); 30: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 31: frame.setVisible(true); 32: } 33: } 34: 35: //animation canvas 36: class CrossBallCanvas extends JPanel { 37: BufferedImage bi; //buffer image

Page 43: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

บทท 10: Graphics Programming

341

38: BufferedImage xball; //image used 39: Graphics2D offscreen; //off screen graphics 40: int x, y; //coordinates 41: int width, height; //width and height of image 42: 43: public CrossBallCanvas() { 44: //get the image 45: try { 46: xball = ImageIO.read(new File("cross.gif")); 47: } 48: catch(IOException e) {} 49: 50: addMouseMotionListener(new MouseMotionHandler()); 51: 52: //calculate size of image 53: width = xball.getWidth(this); 54: height = xball.getHeight(this); 55: } 56: 57: //paint graphics 58: public void paintComponent(Graphics g) { 59: super.paintComponent(g); 60: update(g); 61: } 62: 63: //update graphics 64: public void update(Graphics g) { 65: if(xball == null) { 66: System.out.println("no image file"); 67: return; 68: } 69: 70: //get the size of the panel 71: Dimension d = getSize(); 72: //create a buffered image 73: bi = new BufferedImage(d.width, d.height,

BufferedImage.TYPE_INT_ARGB); 74: //get graphics context 75: offscreen = bi.createGraphics(); 76: offscreen.drawImage(xball, 0, 0, this); 77: 78: //control moving area within the canvas 79: if(x < 0) x = 0; 80: if(x > d.width - width) x = d.width - width; 81: if(y < 0) y = 0; 82: if(y > d.height - height) y = d.height - height; 83: 84: //draw buffered image to graphics context 85: Graphics2D g2 = (Graphics2D)g; 86: g2.drawImage(bi, x, y, null); 87: 88: offscreen.dispose(); //return memory 89: } 90: 91: //get new (x, y) and repaint, not sufficient to drag 92: //image across screen but will do the job 93: class MouseMotionHandler extends MouseMotionAdapter { 94: public void mouseDragged(MouseEvent e) { 95: x = e.getX(); 96: y = e.getY(); 97: repaint(); 98: } 99: } 100: }

Method ทสาคญททาใหเกดการวาดภาพใหมกคอ method mouseDragged() ทอยใน inner class MouseMotionHandler กระบวนการทเกดขนเปนกระบวนการงาย ๆ ทเราทาขน นนกคอหาคา (x, y) ณ ตาแหนงท mouse อยดวย method getX() และ getY() ซงเมอาดแลวเรากทาการวาดใหมดวย repaint() แตเราตองบอกใหโปรแกรมรเหตการณทเกดขนกบ mouse ดวยการเรยก addMouseMotionListener(new MouseMotionHandler()); ในบรรทดท 50

Page 44: intro. to Java (FEU.faa)sci.feu.ac.th/faa/java.intro/ch10-graphicsprogramming.pdfintro. to Java (FEU.faa) ในบทน เราจะมาด ถ งว ธ การวาดร

intro

. to

Java

(FE

U.fa

a)

เรมตนการเขยนโปรแกรมดวย Java

342

วธการเคลอนยายภาพดวย mouse วธนอาจไมใชวธทดทสด ทงนกเพราะวาเราไมไดตรวจสอบวา ในขณะทผใชกดปมซายของ mouse นน cursor อยบนภาพทเราตองการเคลอนยายหรอไมเราเพยงแคตรวจสอบวามการกดหรอไมเทานน ซงจะทาใหเกดการวาดใหมทกครงทมการกด อยางไรกตามวธการนเปนวธทงายทสด สรป ในบทนเราไดพดถงกระบวนของการสรางภาพในรปทรงเรขาตาง ๆ รวมไปถงการเปลยนรปแบบของภาพ การเคลอนยายภาพ และการสรางภาพเคลอนไหวอยางงาย โดยรวมแลวเราไดพดถง

การสรางรปทรงจาก class Graphics การสรางรปทรงจาก class Groahics2D การปรบเปลยนรป เชน scale, rotate, shear, และ translate การสรางภาพเคลอนไหวดวย Timer และ Thread การเคลอนยายภาพดวย mouse

แบบฝกหด 1. จงปรบปรงโปรแกรม TransparencyDemo.java ใหแสดงภาพทเกดขนในรปแบบของ

animation (รปตาง ๆ ทวาดจะเคลอนทพรอมกบเปลยนคาความโปรงแสง) 2. จงออกแบบโปรแกรมททาการยายภาพไปยงตาแหนงทกาหนดใหจากผใช โดยตาแหนงท

กาหนดใหจะอยในรปแบบของคา (x, y) โปรแกรมจะแสดงขอความไปยงผใชถาตาแหนงดงกลาวไมอยในขอบเขตของหนาตาง

3. จงออกแบบโปรแกรมทเชอมตอจดตาง ๆ ทผใชกาหนด เชนถาผใชเลอกตาแหนงใด

ตาแหนงหนงในหนาตาง โปรแกรมจะแสดงจด ณ ตาแหนงนนและเมอผใชกาหนดตาแหนงทสองโปรแกรมกจะทาการเชอมจดทงสองดวยการวาดเสนระหวางจดทงสองนน

4. จงออกแบบโปรแกรมทแสดงคาความโปรงแสงของรปสเหลยมทกาหนดไวในโปรแกรม จาก

คาเรมตนทกาหนดไวไปจนถงคาสนสดทกาหนดไว เมอผใชกดปม Enter โดยกาหนดใหคาความโปรงแสงเพมขนทละหนวย (ตามความเหมาะสม)

5. จงออกแบบโปรแกรมทแสดงการเคลอนทของ image หรอภาพสองมต เชน รปทรงกลม

สองรป โดยมขอกาหนดวา ถารปทรงกลมทงสองชนกนจะตองวงยอนกลบ (สะทอนออก) เชนทแสดงไวในตวอยางเมอรปวงชนขอบหนาตาง

6. จงออกแบบโปรแกรมทขยายภาพสองมตเมอผใชกดปมซายของ mouse และยอขนาดลง

เมอปมขวาถกกด