2013-10-11 47 views
7

我想繪製一個網格並在單元格中繪製東西(爲了保持簡單,只需填充它們)。總的來說,我只是在一些面板尺寸下工作得非常好,單元距離它應該放置的位置大約1個像素(重疊線)。 TBH我真的沒有做足夠的計算來自己找到答案,所以我很抱歉,我真的不太清楚如何處理這個「錯誤」。計算單元格大小並繪製它們之間的線條

總之,這裏的代碼:

public class Gui extends JFrame { 

public static void main(String[] args) { 
    new Gui().setVisible(true); 
} 

public Gui() { 
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    add(new JPanel() { 
     public static final int SIZE = 3; 
     /** Line thickness ratio to a block */ 
     public static final float LINE_THICKNESS = 0.1f; 

     /** @return the width of a block. */ 
     protected final int getBlockWidth() { 
      return getWidth()/SIZE; 
     } 

     /** @return the height of a block. */ 
     protected final int getBlockHeight() { 
      return getHeight()/SIZE; 
     } 

     /** @return the width of a cell. */ 
     protected final int getCellWidth() { 
      return (int) Math.ceil(getBlockWidth()*(1-LINE_THICKNESS)); 
     } 

     /** @return the height of a cell. */ 
     protected final int getCellHeight() { 
      return (int) Math.ceil(getBlockHeight()*(1-LINE_THICKNESS)); 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      g.setColor(new Color(0, 0, 255, 100)); 
      int lineWidth = (int) (LINE_THICKNESS * getBlockWidth()); 
      int lineHeight = (int) (LINE_THICKNESS * getBlockHeight()); 
      for(int i = 0; i <= SIZE; i++) { 
       g.fillRect(i * getBlockWidth() - lineWidth/2, 0, lineWidth, getHeight()); 
       g.fillRect(0, i * getBlockHeight() - lineHeight/2, getWidth(), lineHeight); 
      } 
      g.setColor(new Color(255, 0, 0, 100)); 
      for(int i = 0; i < SIZE; i++) { 
       for(int j = 0; j < SIZE; j++) { 
        int x = j * getBlockWidth() + lineWidth/2; 
        int y = i * getBlockHeight() + lineHeight/2; 
        Graphics temp = g.create(x, y, getCellWidth(), getCellHeight()); 
        drawCell(temp, i, j); 
       } 
      } 
     } 

     private void drawCell(Graphics g, int i, int j) { 
      g.fillRect(0, 0, getCellWidth(), getCellHeight()); 
     } 
    }); 
    setLocation(new Point(500, 200)); 
    setSize(new Dimension(600, 600)); 
} 
} 

如果你運行它,你可能會明白我的意思。我想不出一個好的解釋。起初我想我必須在x和y上加1,因爲我想在線旁邊畫,但是這(顯然)只是把問題轉移到了另一邊。

以更大的尺寸(比如30)來運行它給了我另一個錯誤,它給了開放空間。我知道(或假設)這是因爲我使用整數,但它並沒有太大的交易。但總是歡迎提供更好的方法(通常)。

+0

定+1有一個良好的SSCCE.org和清晰,易於理解的問題。 – Dariusz

回答

4

有幾種方法可以解決這個問題。我不會給你代碼,因爲我相信(根據你問你的問題)你是那些喜歡自己思考和解決問題的人之一。

首先:首先在整個面板上繪製背景,然後繪製線條。不會有線條,畫面會稍微快一些。

第二種方式:繪圖順序很重要。您可以先安全地繪製背景(即使它重疊),然後用邊框覆蓋它。

第三種方式:不要使用整數。使用花車或雙打。你所有的麻煩都會消失。

第四種方式:計算餘數。您可以預測何時繪製線條,何時不繪製線條,仔細想想。預測並適當繪製。

0

嗨我有你同樣的問題,但我實現的解決方案的靈感來自Java教程中的示例,用於繪製多行文本並使用文本API繪製單元格上的文本。

http://java.sun.com/docs/books/tutorial/2d/text/drawmulstring.html

import java.awt.Component; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.font.FontRenderContext; 
import java.awt.font.LineBreakMeasurer; 
import java.awt.font.TextLayout; 
import java.text.AttributedCharacterIterator; 
import java.text.AttributedString; 
import java.text.BreakIterator; 

import javax.swing.JTable; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.TableCellRenderer; 


public class MultilineTableCell 
    implements TableCellRenderer { 
    class CellArea extends DefaultTableCellRenderer { 
     /** 
     * 
     */ 
     private static final long serialVersionUID = 1L; 
     private String text; 
     protected int rowIndex; 
     protected int columnIndex; 
     protected JTable table; 
     protected Font font; 
     private int paragraphStart,paragraphEnd; 
     private LineBreakMeasurer lineMeasurer; 

     public CellArea(String s, JTable tab, int row, int column,boolean isSelected) { 
      text = s; 
      rowIndex = row; 
      columnIndex = column; 
      table = tab; 
      font = table.getFont(); 
      if (isSelected) { 
       setForeground(table.getSelectionForeground()); 
       setBackground(table.getSelectionBackground()); 
      } 
     } 
     public void paintComponent(Graphics gr) { 
      super.paintComponent(gr); 
      if (text != null && !text.isEmpty()) { 
       Graphics2D g = (Graphics2D) gr; 
       if (lineMeasurer == null) { 
        AttributedCharacterIterator paragraph = new AttributedString(text).getIterator(); 
        paragraphStart = paragraph.getBeginIndex(); 
        paragraphEnd = paragraph.getEndIndex(); 
        FontRenderContext frc = g.getFontRenderContext(); 
        lineMeasurer = new LineBreakMeasurer(paragraph,BreakIterator.getWordInstance(), frc); 
       } 
       float breakWidth = (float)table.getColumnModel().getColumn(columnIndex).getWidth(); 
       float drawPosY = 0; 
       // Set position to the index of the first character in the paragraph. 
       lineMeasurer.setPosition(paragraphStart); 
       // Get lines until the entire paragraph has been displayed. 
       while (lineMeasurer.getPosition() < paragraphEnd) { 
        // Retrieve next layout. A cleverer program would also cache 
        // these layouts until the component is re-sized. 
        TextLayout layout = lineMeasurer.nextLayout(breakWidth); 
        // Compute pen x position. If the paragraph is right-to-left we 
        // will align the TextLayouts to the right edge of the panel. 
        // Note: this won't occur for the English text in this sample. 
        // Note: drawPosX is always where the LEFT of the text is placed. 
        float drawPosX = layout.isLeftToRight() 
         ? 0 : breakWidth - layout.getAdvance(); 
        // Move y-coordinate by the ascent of the layout. 
        drawPosY += layout.getAscent(); 
        // Draw the TextLayout at (drawPosX, drawPosY). 
        layout.draw(g, drawPosX, drawPosY); 
        // Move y-coordinate in preparation for next layout. 
        drawPosY += layout.getDescent() + layout.getLeading(); 
       } 
       table.setRowHeight(rowIndex,(int) drawPosY); 
      } 
     } 
    } 
    public Component getTableCellRendererComponent(
      JTable table, Object value,boolean isSelected, boolean hasFocus, int row,int column 
     ) 
    { 
     CellArea area = new CellArea(value.toString(),table,row,column,isSelected); 
     return area; 
    } 
} 
It resizes row heigth too but it does it well only when this renderer is used for a single column. 

And this is the way I used to invoke it for render my table. 

final int wordWrapColumnIndex = ...; 
myTable = new JTable() {  
    public TableCellRenderer getCellRenderer(int row, int column) { 
     if (column == wordWrapColumnIndex) { 
      return wordWrapRenderer; 
     } 
     else { 
      return super.getCellRenderer(row, column); 
     } 
    } 
}; 
相關問題