Trong phần này chúng ta tìm hiểu về một số đối tượng hình học cao cấp hơn và cách sử dụng màu sắc, ảnh texture…
Đa giác
Đầu tiên chúng ta vẽ một số đa giác cơ bản.
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Ellipse2D; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { private void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setPaint(new Color(150, 150, 150)); RenderingHints rh = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHints(rh); g2d.fillRect(30, 20, 50, 50); g2d.fillRect(120, 20, 90, 60); g2d.fillRoundRect(250, 20, 70, 60, 25, 25); g2d.fill(new Ellipse2D.Double(10, 100, 80, 100)); g2d.fillArc(120, 130, 110, 100, 5, 150); g2d.fillOval(270, 130, 50, 50); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class BasicShapesEx extends JFrame { public BasicShapesEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Basic shapes"); setSize(350, 250); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { BasicShapesEx ex = new BasicShapesEx(); ex.setVisible(true); } }); } }
Trong ví dụ trên chúng ta vẽ 6 đa giác là hình vuông, hình chữ nhật, hình chữ nhật có góc tròn, hình elip, hình quạt và hình tròn.
g2d.setPaint(new Color(150, 150, 150));
Các đa giác sẽ được vẽ màu xám.
g2d.fillRect(20, 20, 50, 50); g2d.fillRect(120, 20, 90, 60);
Chúng ta dùng phương thức fillRect()
để vẽ hình chữ nhật và hình vuông. Hai tham số đầu tiên là tọa độ góc trái-trên của hình chữ nhật, 2 tham số cuối cùng là chiều dài và chiều rộng của hình chữ nhật.
g2d.fillRoundRect(250, 20, 70, 60, 25, 25);
Phương thức fillRoundRect()
dùng để vẽ hình chữ nhật có góc tròn, tham số cũng tương tự như fillRect()
ngoại trừ 2 tham số cuối cùng là số đo độ cong của 2 đường ngang và 2 đường dọc. Bạn có thể thay đổi giá trị 2 tham số này để thấy sự khác biệt.
g2d.fill(new Ellipse2D.Double(10, 100, 80, 100));
Ở dòng code trên chúng ta dùng phương thức fill()
để vẽ một đa giác cho trước là một elip.
g2d.fillArc(120, 130, 110, 100, 5, 150);
Phương thức fillArc()
vẽ một hình quạt, 4 tham số đầu tiên là tọa độ góc trái-trên và góc phải-dưới của hình quạt. Tham số thứ 5 là hướng mà quạt quay tới, tham số thứ 6 là độ lớn của quạt.
g2d.fillOval(270, 130, 50, 50);
Phương thức fillOval()
vẽ một hình tròn.
Đa giác lồi
Để vẽ các đa giác phức tạp hơn thì chúng ta dùng lớp GeneralPath
. Lớp này vẽ đa giác bằng cách nối đoạn thẳng với tập các điểm cho trước.
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.GeneralPath; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { private final double points[][] = { { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, { 40, 190 }, { 50, 125 }, { 0, 85 } }; private void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setPaint(Color.gray); g2d.translate(25, 5); GeneralPath star = new GeneralPath(); star.moveTo(points[0][0], points[0][1]); for (int k = 1; k < points.length; k++) star.lineTo(points[k][0], points[k][1]); star.closePath(); g2d.fill(star); g2d.dispose(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class StarEx extends JFrame { public StarEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Star"); setSize(350, 250); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { StarEx ex = new StarEx(); ex.setVisible(true); } }); } }
Ở ví dụ trên chúng ta vẽ hình một ngôi sao từ một tập hợp điểm.
GeneralPath star = new GeneralPath();
Khởi tạo đối tượng GeneralPath
.
star.moveTo(points[0][0], points[0][1]);
Đầu tiên chúng ta chuyển vị trí bắt đầu vẽ đến điểm đầu tiên.
for (int k = 1; k < points.length; k++) star.lineTo(points[k][0], points[k][1]);
Tiếp theo chúng ta duyệt qua tập điểm và dùng phương thức lineTo()
để nối các điểm này lại.
star.closePath(); g2d.fill(star);
Sau khi đã nối xong chúng ta gọi phương thức closePath()
để báo rằng việc nối đã hoàn tất và gọi phương thức fill()
để tô màu ngôi sao.
Lớp Area
Lớp Area
cho phép tạo các hình phức tạp hơn bằng cách trộn lẫn các hình có sẵn lại với nhau.
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { public void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g; RenderingHints rh = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHints(rh); g2d.setPaint(Color.gray); Area a1 = new Area(new Rectangle2D.Double(20, 20, 100, 100)); Area a2 = new Area(new Ellipse2D.Double(50, 50, 100, 100)); a1.subtract(a2); g2d.fill(a1); Area a3 = new Area(new Rectangle2D.Double(150, 20, 100, 100)); Area a4 = new Area(new Ellipse2D.Double(150, 20, 100, 100)); a3.subtract(a4); g2d.fill(a3); Area a5 = new Area(new Rectangle2D.Double(280, 20, 100, 100)); Area a6 = new Area(new Ellipse2D.Double(320, 40, 100, 100)); a5.add(a6); g2d.fill(a5); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class AreasEx extends JFrame { public AreasEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Areas"); setSize(450, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { AreasEx ex = new AreasEx(); ex.setVisible(true); } }); } }
Đoạn code trên tạo 3 hình khác nhau.
Area a1 = new Area(new Rectangle2D.Double(20, 20, 100, 100)); Area a2 = new Area(new Ellipse2D.Double(50, 50, 100, 100)); a1.subtract(a2); g2d.fill(a1);
Hai dòng code trên tạo 1 hình chữ nhật và một hình elip rồi cắt một vùng trên hình chữ nhật bằng với hình elip bằng phương thức substract()
.
Area a5 = new Area(new Rectangle2D.Double(280, 20, 100, 100)); Area a6 = new Area(new Ellipse2D.Double(320, 40, 100, 100)); a5.add(a6); g2d.fill(a5);
Đối với 2 hình a5
và a6
thì chúng ta cho chúng nằm đè lên nhau bằng phương thức add().
Tô màu
Lớp Color
là lớp chuyên làm việc với màu. Chúng ta sẽ tìm hiểu về lớp này qua ví dụ sau.
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { public void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setColor(new Color(125, 167, 116)); g2d.fillRect(10, 10, 90, 60); g2d.setColor(new Color(42, 179, 231)); g2d.fillRect(130, 10, 90, 60); g2d.setColor(new Color(70, 67, 123)); g2d.fillRect(250, 10, 90, 60); g2d.setColor(new Color(130, 100, 84)); g2d.fillRect(10, 100, 90, 60); g2d.setColor(new Color(252, 211, 61)); g2d.fillRect(130, 100, 90, 60); g2d.setColor(new Color(241, 98, 69)); g2d.fillRect(250, 100, 90, 60); g2d.setColor(new Color(217, 146, 54)); g2d.fillRect(10, 190, 90, 60); g2d.setColor(new Color(63, 121, 186)); g2d.fillRect(130, 190, 90, 60); g2d.setColor(new Color(31, 21, 1)); g2d.fillRect(250, 190, 90, 60); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class ColoursEx extends JFrame { public ColoursEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Colours"); setSize(360, 300); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { ColoursEx ex = new ColoursEx(); ex.setVisible(true); } }); } }
Để tạo màu thì chúng ta dùng phương thức setColor() và đưa vào một đối tượng Color. Đối tượng này khi được tạo ra nhận 3 tham số là giá trị đỏ (Red), xanh lá (Green) và xanh lam (Blue).
Gradient
Gradient là dải màu từ màu này đến màu khác. Có thể ứng dụng để làm mô phỏng bóng tối và ánh sáng.
import java.awt.Color; import java.awt.EventQueue; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { private void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); GradientPaint gp1 = new GradientPaint(5, 5, Color.red, 20, 20, Color.black, true); g2d.setPaint(gp1); g2d.fillRect(20, 20, 300, 40); GradientPaint gp2 = new GradientPaint(5, 25, Color.yellow, 20, 2, Color.black, true); g2d.setPaint(gp2); g2d.fillRect(20, 80, 300, 40); GradientPaint gp3 = new GradientPaint(5, 25, Color.green, 2, 2, Color.black, true); g2d.setPaint(gp3); g2d.fillRect(20, 140, 300, 40); GradientPaint gp4 = new GradientPaint(25, 25, Color.blue, 15, 25, Color.black, true); g2d.setPaint(gp4); g2d.fillRect(20, 200, 300, 40); GradientPaint gp5 = new GradientPaint(0, 0, Color.orange, 0, 20, Color.black, true); g2d.setPaint(gp5); g2d.fillRect(20, 260, 300, 40); g2d.dispose(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class GradientsEx extends JFrame { public GradientsEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Gradients"); setSize(350, 350); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { GradientsEx ex = new GradientsEx(); ex.setVisible(true); } }); } }
Trong ví dụ này chúng ta tạo 5 hình chữ nhật với 5 gradient khác nhau.
GradientPaint gp4 = new GradientPaint(25, 25, Color.blue, 15, 25, Color.black, true);
Để hiện dải màu thì chúng ta dùng lớp GradientPaint(x1, y1, Color1, x2, y2, Color2, cyclic),
trong đó các tham số có ý nghĩa là tô màu từ điểm (x1
, y1
) với màu Color1
dần dần chuyển sang màu Color2
tại vị trí (x2
, y2
). Tham số cyclic
cho biết các dải màu có được phép lặp lại hay không.
g2d.setPaint(gp4);
Sau khi đã thiết lập màu gradient, chúng ta gọi phương thức setPaint()
để kích hoạt gradient.
Ảnh Texture
Ảnh texture là ảnh dùng để hiện lên trên đa giác. Để sử dụng texture thì chúng ta dùng lớp TexturePaint
.
import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.TexturePaint; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel { private BufferedImage slate; private BufferedImage java; private BufferedImage pane; private TexturePaint slatetp; private TexturePaint javatp; private TexturePaint panetp; public Surface() { loadImages(); } private void loadImages() { try { slate = ImageIO.read(new File("slate.png")); java = ImageIO.read(new File("java.png")); pane = ImageIO.read(new File("pane.png")); } catch (IOException ex) { Logger.getLogger(Surface.class.getName()).log( Level.SEVERE, null, ex); } } private void doDrawing(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); slatetp = new TexturePaint(slate, new Rectangle(0, 0, 90, 60)); javatp = new TexturePaint(java, new Rectangle(0, 0, 90, 60)); panetp = new TexturePaint(pane, new Rectangle(0, 0, 90, 60)); g2d.setPaint(slatetp); g2d.fillRect(10, 15, 90, 60); g2d.setPaint(javatp); g2d.fillRect(130, 15, 90, 60); g2d.setPaint(panetp); g2d.fillRect(250, 15, 90, 60); g2d.dispose(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } } public class TexturesEx extends JFrame { public TexturesEx() { initUI(); } private void initUI() { add(new Surface()); setTitle("Textures"); setSize(360, 120); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { TexturesEx ex = new TexturesEx(); ex.setVisible(true); } }); } }
Trong đoạn code trên chúng ta vẽ 3 hình chữ nhật với 3 texture khác nhau.
slate = ImageIO.read(new File("slate.png"));
Chúng ta dùng lớp ImageIO
để load ảnh vào bộ nhớ.
slatetp = new TexturePaint(slate, new Rectangle(0, 0, 90, 60));
Tiếp theo chúng ta tạo ảnh texture từ lớp TexturePaint.
g2d.setPaint(slatetp); g2d.fillRect(10, 15, 90, 60);
Cuối cùng chúng ta vẽ hình chữ nhật.