2008-10-27 35 views
11

Chương trình của tôi sẽ ghi đè public void paint(Graphics g, int x, int y); để rút ra một số đốt sử dụng g.drawString(someString, x+10, y+30);Làm thế nào để ra một String trên nhiều dòng sử dụng đồ họa

Bây giờ someString có thể khá dài và do đó, nó có thể không phù hợp trên cùng một dòng.

Cách tốt nhất để viết văn bản trên nhiều dòng là gì.
Ví dụ, trong một hình chữ nhật (x1, y1, x2, y2)?

Trả lời

9

Nhờ gợi ý của Epaga và một vài ví dụ trên mạng (không quá rõ ràng để tìm! Tôi đã sử dụng chủ yếu là Break a Line for text layout), tôi có thể tạo thành phần để hiển thị văn bản được bao bọc. Nó không đầy đủ, nhưng ít nhất nó cho thấy hiệu quả dự định.

class TextContainer extends JPanel 
{ 
    private int m_width; 
    private int m_height; 
    private String m_text; 
    private AttributedCharacterIterator m_iterator; 
    private int m_start; 
    private int m_end; 

    public TextContainer(String text, int width, int height) 
    { 
     m_text = text; 
     m_width = width; 
     m_height = height; 

     AttributedString styledText = new AttributedString(text); 
     m_iterator = styledText.getIterator(); 
     m_start = m_iterator.getBeginIndex(); 
     m_end = m_iterator.getEndIndex(); 
    } 

    public String getText() 
    { 
     return m_text; 
    } 

    public Dimension getPreferredSize() 
    { 
     return new Dimension(m_width, m_height); 
    } 

    public void paint(Graphics g) 
    { 
     super.paintComponent(g); 

     Graphics2D g2 = (Graphics2D) g; 
     FontRenderContext frc = g2.getFontRenderContext(); 

     LineBreakMeasurer measurer = new LineBreakMeasurer(m_iterator, frc); 
     measurer.setPosition(m_start); 

     float x = 0, y = 0; 
     while (measurer.getPosition() < m_end) 
     { 
      TextLayout layout = measurer.nextLayout(m_width); 

      y += layout.getAscent(); 
      float dx = layout.isLeftToRight() ? 
        0 : m_width - layout.getAdvance(); 

      layout.draw(g2, x + dx, y); 
      y += layout.getDescent() + layout.getLeading(); 
     } 
    } 
} 

Chỉ cần cho vui, tôi đã làm cho nó phù hợp một vòng tròn (than ôi, không thể biện minh, có vẻ như):

public void paint(Graphics g) 
{ 
    super.paintComponent(g); 

    Graphics2D g2 = (Graphics2D) g; 
    FontRenderContext frc = g2.getFontRenderContext(); 

    LineBreakMeasurer measurer = new LineBreakMeasurer(m_iterator, frc); 
    measurer.setPosition(m_start); 

    float y = 0; 
    while (measurer.getPosition() < m_end) 
    { 
     double ix = Math.sqrt((m_width/2 - y) * y); 
     float x = m_width/2.0F - (float) ix; 
     int width = (int) ix * 2; 

     TextLayout layout = measurer.nextLayout(width); 

     y += layout.getAscent(); 
     float dx = layout.isLeftToRight() ? 
       0 : width - layout.getAdvance(); 

     layout.draw(g2, x + dx, y); 
     y += layout.getDescent() + layout.getLeading(); 
    } 
} 

Tôi không quá chắc chắn về tính dx, mặc dù.

3

java.awt.font.TextLayout có thể hữu ích. Dưới đây là một đoạn mã ví dụ của họ:

Graphics2D g = ...; 
    Point2D loc = ...; 
    Font font = Font.getFont("Helvetica-bold-italic"); 
    FontRenderContext frc = g.getFontRenderContext(); 
    TextLayout layout = new TextLayout("This is a string", font, frc); 
    layout.draw(g, (float)loc.getX(), (float)loc.getY()); 

    Rectangle2D bounds = layout.getBounds(); 
    bounds.setRect(bounds.getX()+loc.getX(), 
        bounds.getY()+loc.getY(), 
        bounds.getWidth(), 
        bounds.getHeight()); 
    g.draw(bounds); 

Nếu không, bạn luôn có thể sử dụng một yếu tố văn bản Swing để làm công việc cho bạn, chỉ cần vượt qua trong các Graphics bạn muốn nó vẽ vào.

+0

Tôi đã nhận được tài khoản đó. Vấn đề của tôi là, tôi không muốn một hình chữ nhật xung quanh văn bản, nhưng văn bản bên trong một hình chữ nhật đã cho. – Burkhard

+0

Lưu ý rằng hàm tạo của TextLayout, không có giấy tờ, ném một ngoại lệ nếu chuỗi bạn vượt qua trống. –

+1

Sử dụng \t Hình dạng labelShape = textLayout1.getOutline (null); và sau đó g2d.fill (labelShape); họ nên loại bỏ biên giới – mk7

1

Tăng dần chuỗi của bạn, một từ cùng một lúc, sử dụng phương pháp của Epaga để tìm độ dài của chuỗi. Khi độ dài dài hơn hình chữ nhật của bạn, hãy xóa từ cuối cùng và in. Lặp lại cho đến khi bạn hết lời.

Có vẻ như thuật toán không đúng, nhưng đối với mỗi dòng, nó thực sự là O (screenWidth/averageCharacterWidth) => O (1).

Tuy nhiên, hãy sử dụng StringBuffer để tạo chuỗi của bạn!

+1

Điều này sẽ không có độ phức tạp về thời gian của O (1); O (n), có lẽ, khi bạn cần (ít nhất) thêm một từ (tức là thêm một số ký tự trong StringBuilder.append) cho đến khi tất cả các ký tự đã được sử dụng hết. – jamesh

+0

Tôi có vẻ xấu khi thể hiện bản thân mình ... Tôi có nghĩa là mỗi dòng là O (1). Bạn có thể ném 1000 từ vào nó, nhưng, đối với mỗi dòng, nó sẽ ngừng thêm từ ở cạnh màn hình. Nhìn chung, có, O (n). –

+0

Nó chỉ hoạt động nếu bạn cho rằng chuỗi sẽ ở tối đa 2 dòng, khi nó sẽ nhiều hơn, nó sẽ không hoạt động. –

0

Bạn có thể sử dụng JLabel và nhúng văn bản bằng html.

JLabel.setText("<html>"+line1+"<br>"+line2); 
+0

HTML của bạn bị tước bỏ. Tôi giả định chuỗi ký tự đầu tiên là và chữ thứ hai là
. –

+1

Nó không đánh bại mục đích nếu bạn phải thêm các dấu ngắt dòng của riêng mình? –

1

Đã có một số vướng bận điều này được giải pháp của tôi:

Graphics2D g=.... 
FontRenderContext frc = g.getFontRenderContext(); 
TextLayout layout = new TextLayout(text, font, frc); 
String[] outputs = text.split("\n"); 
for(int i=0; i<outputs.length; i++){ 
    g.drawString(outputs[i], 15,(int) (15+i*layout.getBounds().getHeight()+0.5)); 

Hy vọng rằng sẽ giúp .... đơn giản nhưng nó hoạt động.

Các vấn đề liên quan