Java swing lỗi font tiếng việt khi insert năm 2024

Vẽ kí tự lên màn hình là một chủ đề phức tạp, có khi viết nguyên một quyển sách cũng chưa hết, nên trong bài này mình chỉ bàn về một số thao tác cơ bản.

Có hai loại font là font vật lý [Physical Font] và font logic [Logical Font]. Font vật lý là font thật, được lưu trong hệ điều hành, font logic không phải font thật mà thực ra chỉ là 5 hệ font được định nghĩa bởi Java: Serif, SansSerif, Monospaced, Dialog, DialogInput. Khi được gọi thì font logic sẽ được Java map vào font vật lý.

Một Font là một tập hợp các ký tự, một kí tự được gọi là TypeFace, tập hợp các TypeFace giống nhau nhưng khác kiểu font [hoặc các tính chất khác như độ lớn, độ nghiêng…] được gọi là Font-Family.

Font trong hệ điều hành

Đoạn code dưới đây sẽ in ra toàn bộ font chữ hiện được hỗ trợ bởi hệ điều hành của bạn.

AllFontsEx.java

import java.awt.Font; import java.awt.GraphicsEnvironment; public class AllFontsEx {

public static void main[String[] args] {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment[];  
    Font[] fonts = ge.getAllFonts[];
    for [Font font : fonts] {  
        System.out.print[font.getFontName[] + " : "];  
        System.out.println[font.getFamily[]];  
    }  
}  
} Bản thân Java không chứa thông tin về các kiểu font trong hệ điều hành, Java chỉ lấy thông tin về font của hệ điều hành để sử dụng. Mỗi hệ điều hành có bộ font khác nhau. Để lấy thông tin về font chữ trong hệ điều hành thì chúng ta sử dụng các lớp

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 5,

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 6.

Font[] fonts = ge.getAllFonts[]; Phương thức

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 7 trả về danh sách font hiện có trong

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 5.

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; Chúng ta dùng phương thức

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 9 và

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 0để lấy về tên font và tên family.

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ...

In text lên màn hình

Trong ví dụ dưới đây, chúng ta sẽ in một đoạn lyric lên panel.

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} Để thiết lập kiểu font mong muốn thì chúng ta dùng phương thức

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 1.

g2d.setFont[new Font["NewellsHand", Font.PLAIN, 18]]; Để in một đoạn text thì chúng ta dùng phương thức

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 2.

g2d.drawString["Most relationships seem so transitory", 20, 30];

Tạo hiệu dứng đổ bóng cho chữ

import java.awt.Color; import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.TextLayout; import java.awt.image.BufferedImage; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; public class ShadowedTextEx extends JFrame {

private final int width = 300;  
private final int height = 130;
private final String text = "War is hell";  
private TextLayout textLayout;
public ShadowedTextEx[] {
    initUI[];  
}
private void initUI[] {  
    setTitle["Shadowed Text"];  
    BufferedImage image = createImage[];  
    add[new JLabel[new ImageIcon[image]]];  
    setSize[300, 130];  
    setLocationRelativeTo[null];         
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
}
private void setRenderingHints[Graphics2D g] {  
    g.setRenderingHint[RenderingHints.KEY_TEXT_ANTIALIASING,  
                       RenderingHints.VALUE_TEXT_ANTIALIAS_ON];  
    g.setRenderingHint[RenderingHints.KEY_FRACTIONALMETRICS,  
                       RenderingHints.VALUE_FRACTIONALMETRICS_ON];  
}
private BufferedImage createImage[]  {
    int x = 10;  
    int y = 100;
    Font font = new Font["Georgia", Font.ITALIC, 50];  
    BufferedImage image = new BufferedImage[width, height,   
            BufferedImage.TYPE_INT_RGB];  
    Graphics2D g1d = image.createGraphics[];  
    setRenderingHints[g1d];  
    textLayout = new TextLayout[text, font, g1d.getFontRenderContext[]];  
    g1d.setPaint[Color.WHITE];  
    g1d.fillRect[0, 0, width, height];
    g1d.setPaint[new Color[150, 150, 150]];  
    textLayout.draw[g1d, x+3, y+3];  
    g1d.dispose[];
    float[] kernel = {  
      1f / 9f, 1f / 9f, 1f / 9f,   
      1f / 9f, 1f / 9f, 1f / 9f,   
      1f / 9f, 1f / 9f, 1f / 9f   
    };
    ConvolveOp op =  new ConvolveOp[new Kernel[3, 3, kernel],   
            ConvolveOp.EDGE_NO_OP, null];  
    BufferedImage image2 = op.filter[image, null];
    Graphics2D g2d = image2.createGraphics[];  
    setRenderingHints[g2d];  
    g2d.setPaint[Color.BLACK];  
    textLayout.draw[g2d, x, y];  
    g2d.dispose[];
    return image2;  
}        
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {
        @Override  
        public void run[] {  
            ShadowedTextEx ex = new ShadowedTextEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} Để tạo bóng cho một đoạn text thì chúng ta vẽ hai đoạn text, một đoạn text chính và một đoạn text dùng làm bóng, trong đó đoạn text đổ bóng được làm mờ, có vị trí lệch một ít với đoạn text gốc.

textLayout = new TextLayout[text, font, g1d.getFontRenderContext[]]; Chúng ta dùng lớp

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 3 để quy định các tính chất cho đoạn text, lớp này cho phép chúng ta thao tác sâu hơn với font.

textLayout.draw[g1d, x+3, y+3]; Chúng ta vẽ đoạn text lên màn hình có vị trí lệch 3 pixel so với đoạn text gốc.

Font[] fonts = ge.getAllFonts[]; 0

Để tăng thêm hiệu ứng thì chúng ta áp dụng hiệu ứng mờ lên đoạn text.

Font[] fonts = ge.getAllFonts[]; 1

Chúng ta áp dụng hiệu ứng mờ lên đoạn text gốc rồi gán vào đoạn text thứ hai dùng làm đổ bóng.

Font[] fonts = ge.getAllFonts[]; 2

Sau đó chúng ta vẽ đoạn text gốc để đảm bảo đoạn text gốc nằm đè lên đoạn text đổ bóng.

Một số tính chất khác

Font[] fonts = ge.getAllFonts[]; 3

Để thay đổi các tính chất của text thì chúng ta dùng các lớp

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 6,

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 5 và

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 6. Lớp

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 6 quy định kiểu font, lớp

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 5 quy định một số tính chất như màu chữ, màu nền… còn lớp

... .VnArial : .VnArial .VnArial Bold : .VnArial .VnArial Bold Italic : .VnArial .VnArial Italic : .VnArial .VnArial Narrow : .VnArial Narrow .VnArial Narrow Bold : .VnArial Narrow .VnArial Narrow Italic : .VnArial Narrow .VnArial NarrowH : .VnArial NarrowH .VnArialH : .VnArialH .VnArialH Bold Italic : .VnArialH ... 9 lưu thông tin về đoạn text và các tính chất của nó.

Font[] fonts = ge.getAllFonts[]; 4

Đầu tiên chúng ta tạo một đối tượng

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 0

Font[] fonts = ge.getAllFonts[]; 5

Chúng ta có thể thêm một số tính chất khác vào đoạn text thông qua phương thức

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 1

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 2, dòng trên có ý nghĩa là thiết lập màu chữ của các kí tự từ vị trí 0 đến vị trí 6 có màu đỏ.

Font[] fonts = ge.getAllFonts[]; 6

Sau khi đã định nghĩa các tính chất mong muốn, chúng ta vẽ đoạn text lên nhưng chúng ta sẽ lấy đoạn text đó từ phương thức

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 3chứ không dùng đoạn string gốc.

Xoay chữ

Trong bài xử lý ảnh chúng ta đã học cách xoay các đối tượng hình học. Bản thân các ký tự được vẽ trong Java cũng là các đối tượng hình học, chúng ta sẽ lấy các đối tượng đó ra mà xoay rồi vẽ như vẽ một đối tượng hình học bình thường.

Font[] fonts = ge.getAllFonts[]; 7

Chúng ta sẽ dùng lớp

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 4 và lớp

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 5lớp

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 4 chứa các thông tin cần thiết để lấy kích thước của kí tự, lớp

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 7 lưu thông tin về các đặc điểm hình học của kí tự.

Font[] fonts = ge.getAllFonts[]; 8

Đầu tiên chúng ta tạo một đối tượng

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 7, trong đó lưu những thông tin về hình ảnh, vị trí…

Font[] fonts = ge.getAllFonts[]; 9

Mỗi kí tự trong đoạn text sẽ được lưu trong một đối tượng hình học riêng, nên chúng ta lấy về số lượng các kí tự [cũng như các đối tượng hình học].

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 0

Sau đó chúng ta lặp qua từng kí tự, tại mỗi lần lặp chúng ta lấy ra tọa độ của đối tượng vẽ ra kí tự đó bằng phương thức

import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; class Surface extends JPanel {

private 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.setFont[new Font["NewellsHand", Font.PLAIN, 18]];
    g2d.drawString["Most relationships seem so transitory", 20, 30];  
    g2d.drawString["They're all good but not the permanent one", 20, 60];  
    g2d.drawString["Who doesn't long for someone to hold", 20, 90];  
    g2d.drawString["Who knows how to love you without being told", 20, 120];  
    g2d.drawString["Somebody tell me why I'm on my own", 20, 150];  
    g2d.drawString["If there's a soulmate for everyone", 20, 180];          
}
@Override  
public void paintComponent[Graphics g] {  
    super.paintComponent[g];  
    doDrawing[g];  
}  
} public class SoulmateEx extends JFrame {
public SoulmateEx[] {  
    initUI[];  
}  
private void initUI[] {  
    setTitle["Soulmate"];
    add[new Surface[]];
    setSize[420, 250];  
    setDefaultCloseOperation[JFrame.EXIT_ON_CLOSE];  
    setLocationRelativeTo[null];        
}  
public static void main[String[] args] {  
    EventQueue.invokeLater[new Runnable[] {  
        @Override  
        public void run[] {  
            SoulmateEx ex = new SoulmateEx[];  
            ex.setVisible[true];  
        }  
    }];  
}  
} 9

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 1

Tiếp theo chúng ta tính góc xoay cho đối tượng đó dựa vào thứ tự của nó trong chuỗi.

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 2

Tiếp theo chúng ta xoay bằng cách sử dụng lớp

g2d.setFont[new Font["NewellsHand", Font.PLAIN, 18]]; 0.

System.out.print[fonts[i].getFontName[] + " : "]; System.out.println[fonts[i].getFamily[]]; 3

Cuối cùng chúng ta dùng phương thức getGlyphOutline[] để lấy về đối tượng hình học của kí tự hiện tại rồi dùng phương thức

g2d.setFont[new Font["NewellsHand", Font.PLAIN, 18]]; 1để tạo ra đối tượng đó ở trạng thái đã xoay.

Chủ Đề