Java 计算单元大小并在它们之间绘制线
我想画一个网格,在单元格中画东西(为了让事情变得简单,只需填充它们)。 总的来说,我已经得到了它几乎只有在一些面板大小的工作单元是大约1像素的地方,它应该放置(重叠线)。 TBH我还没有做足够的计算来自己找到答案,所以我对此表示歉意,我也不太确定如何处理这个“错误” 不管怎样,代码如下:Java 计算单元大小并在它们之间绘制线,java,graphics,Java,Graphics,我想画一个网格,在单元格中画东西(为了让事情变得简单,只需填充它们)。 总的来说,我已经得到了它几乎只有在一些面板大小的工作单元是大约1像素的地方,它应该放置(重叠线)。 TBH我还没有做足够的计算来自己找到答案,所以我对此表示歉意,我也不太确定如何处理这个“错误” 不管怎样,代码如下: public class Gui extends JFrame { public static void main(String[] args) { new Gui().setVisible(true
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));
}
}
公共类Gui扩展JFrame{
公共静态void main(字符串[]args){
新建Gui().setVisible(true);
}
公共图形用户界面(){
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
添加(新JPanel(){
公共静态最终整数大小=3;
/**与块体的线厚比*/
公共静态最终浮子线厚度=0.1f;
/**@返回块的宽度*/
受保护的最终整型getBlockWidth(){
返回getWidth()/SIZE;
}
/**@返回块的高度*/
受保护的最终整型getBlockHeight(){
返回getHeight()/SIZE;
}
/**@返回单元格的宽度*/
受保护的最终整数getCellWidth(){
return(int)Math.ceil(getBlockWidth()*(1-LINE_-THICKNESS));
}
/**@返回单元格的高度*/
受保护的最终整数getCellHeight(){
return(int)Math.ceil(getBlockHeight()*(1-LINE_-THICKNESS));
}
@凌驾
公共组件(图形g){
g、 setColor(新颜色(0,0,255,100));
int线宽=(int)(线宽*getBlockWidth());
int lineHeight=(int)(线条厚度*getBlockHeight());
对于(int i=0;i有几种方法可以解决这个问题。我不会给你代码,因为我相信(基于你提问的方式)你是喜欢自己思考和解决问题的人之一
首先:首先在整个面板上画背景,然后画线。没有while线,画的速度会稍微快一点
第二种方法:绘制顺序很重要。你可以先安全地绘制背景(即使它重叠),然后用边框覆盖它
第三种方法:不要使用整数。使用浮点或双精度。所有的麻烦都会消失
第四种方法:计算余数。您可以预测何时绘制线,何时不绘制线,仔细考虑。预测线并适当地绘制。您好,我也遇到过同样的问题,但我实现的解决方案受到Java教程中绘制多行文本的示例的启发,并使用文本API在单元格上绘制文本
导入java.awt.Component;
导入java.awt.Font;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.font.FontRenderContext;
导入java.awt.font.LineBreakMeasurer;
导入java.awt.font.TextLayout;
导入java.text.AttributedCharacterator;
导入java.text.AttributeString;
导入java.text.BreakIterator;
导入javax.swing.JTable;
导入javax.swing.table.DefaultTableCellRenderer;
导入javax.swing.table.TableCellRenderer;
公共类多语言单元
实现TableCellRenderer{
类扩展了DefaultTableCellRenderer{
/**
*
*/
私有静态最终长serialVersionUID=1L;
私有字符串文本;
受保护的整数行索引;
受保护的int列索引;
保护JTable表;
保护字体;
私有int段落开始,段落结束;
专用测线器测线器;
公共区域(字符串s、JTable选项卡、int行、int列、布尔isSelected){
text=s;
行索引=行;
columnIndex=列;
表=选项卡;
font=table.getFont();
如果(当选){
setForeground(table.getSelectionForeground());
挫折背景(table.getSelectionBackground());
}
}
公共组件(图形组){
超级油漆组件(gr);
if(text!=null&&!text.isEmpty()){
Graphics2D g=(Graphics2D)gr;
if(lineMeasurer==null){
AttributedCharacterIterator段落=新的AttributedString(text).getIterator();
paragraphStart=段落.getBeginIndex();
paragraphEnd=段落.getEndIndex();
FontRenderContext frc=g.getFontRenderContext();
lineMeasurer=新的LineBreakMeasurer(段落,BreakIterator.getWordInstance(),frc);
}
float breakWidth=(float)table.getColumnModel().getColumn(columnIndex.getWidth();
float-drawPosY=0;
//将位置设置为段落中第一个字符的索引。
测线器设置位置(段落开始);
//获取行,直到显示整个段落。
while(lineMeasurer.getPosition()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);
}
}
};