2013-10-11 3 views
7

Ich möchte ein Gitter zeichnen und Zeug in den Zellen zeichnen (um die Dinge einfach zu halten füllen Sie sie einfach). Insgesamt habe ich es funktioniert ziemlich nur in einigen Panel-Größen die Zelle ist etwa 1 Pixel von wo es platziert werden sollte (überlappend die Zeile). TBH Ich habe nicht wirklich genug Berechnungen durchgeführt, um die Antwort möglicherweise selbst zu finden, also entschuldige ich mich dafür, ich bin mir allerdings nicht ganz sicher, wie ich mich diesem "Bug" nähern soll.Berechne Zellgrößen und zeichne (mit Linien dazwischen) sie

Wie auch immer, hier ist der Code:

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)); 
} 
} 

Wenn Sie es ausführen werden Sie wahrscheinlich sehen, was ich meine. Ich kann mir keine gute Erklärung in Worten vorstellen. Zuerst dachte ich, ich müsste +1 zu x und y hinzufügen, da ich neben der Linie zeichnen möchte, aber das verschiebt (offensichtlich) das Problem einfach auf die andere Seite.

Das Laufen mit einer größeren GRÖßE (wie 30) gibt mir einen anderen Fehler, dass es offenen Raum zu den Seiten gibt. Ich weiß (oder nehme an), dass dies der Fall ist, weil ich Integer benutze und es nicht zu groß ist. Aber Hinweise für einen besseren Ansatz (im Allgemeinen) sind immer willkommen.

+0

Definite +1 für eine gute SSCCE.org und klare, verständliche Frage. – Dariusz

Antwort

4

Es gibt mehrere Möglichkeiten, wie Sie das beheben können. Ich werde Ihnen keinen Code geben, da ich glaube (basierend darauf, wie Sie Ihre Frage gestellt haben), dass Sie einer von denen sind, die selbständig Probleme denken und lösen wollen.

Zuerst einmal: Zeichnen Sie zuerst den Hintergrund auf die gesamte Tafel und zeichnen Sie dann die Linien. Es wird keine Weile geben, während die Linien und die Zeichnung etwas schneller sein werden.

Zweiter Weg: Die Reihenfolge der Zeichnung ist wichtig. Sie können den Hintergrund zuerst sicher zeichnen (auch wenn er sich überlappt) und ihn dann mit Rahmen überschreiben.

Dritter Weg: Verwenden Sie keine Ints. Verwenden Sie Floats oder Doubles. Alle deine Probleme werden verschwinden.

Vierter Weg: Berechnen Sie den Rest. Sie können vorhersagen, wann die Linien gezeichnet werden und wann nicht, denken Sie darüber nach. Vorhersagen und angemessen zeichnen.

0

Hallo Ich hatte Ihr Problem, aber die Lösung, die ich implementiert habe, ist inspiriert von der Probe aus dem Java-Tutorial zum Zeichnen mehrzeiliger Text und zeichnet den Text auf der Zelle mit den Text-APIs.

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); 
     } 
    } 
}; 
Verwandte Themen