Java2d画直角坐标系

本文介绍如何在Java项目中使用Java2D的bufferedImage来绘制直角坐标系,作为替代收费插件jfreechart的选择。内容包括将图片划分为border和主体两部分,并详细讲解了自定义边界类的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近项目用到java作图,首先想到的是利用开源插件jfreechart,文档收费,网上资料参差不齐,最后还是觉得采用java2D bufferedImage作图。 现在分享一下。

把一张图片分为border部分和主体部分,如下图所示:


定义一个边界类

/**
 * Copyright (c) 2014, alax
 * All Rights Reserved.
 */

package chapterOne.axis;
/**
 *
 * @author   	 alax_app@yeah.net
 * @Date	 	 2014-3-18 下午11:41:10
 *
 */
public class AxisBorder {
	
	private int left;
	private int right;
	private int top;
	private int bottom;
	
	private int backgroundColor;	//背景色
	
	public AxisBorder(){
		
	}
	
	public AxisBorder(int left, int right, int top, int bottom,
			int backgroundColor) {
		super();
		this.left = left;
		this.right = right;
		this.top = top;
		this.bottom = bottom;
		this.backgroundColor = backgroundColor;
	}



	public int getLeft() {
		return left;
	}

	public void setLeft(int left) {
		this.left = left;
	}

	public int getRight() {
		return right;
	}

	public void setRight(int right) {
		this.right = right;
	}

	public int getTop() {
		return top;
	}

	public void setTop(int top) {
		this.top = top;
	}

	public int getBottom() {
		return bottom;
	}

	public void setBottom(int bottom) {
		this.bottom = bottom;
	}

	public int getBackgroundColor() {
		return backgroundColor;
	}

	public void setBackgroundColor(int backgroundColor) {
		this.backgroundColor = backgroundColor;
	}
	
}

接下来定义坐标轴实例

/**
 * Copyright (c) 2014, alax
 * All Rights Reserved.
 */

package chapterOne.axis;

import java.util.Date;

/**
 *
 * @author   	 alax_app@yeah.net
 * @Date	 	 2014-3-19 上午12:10:01
 *
 */
public class Axis {
	public static final String VALUE = "value";
	public static final String DATETIME = "datetime";
	
	private int lineColor;		//y轴颜色
	private int lineWidth;		//y轴宽度
	private String title;		//y轴标题
	private String type;		//y轴类型  支持value 类型 和datetime类型
	
	private double max;			//最大值
	private double min;			//最小值
	
	private int ticks;			//刻度个数
	
	private Date startDate;
	private Date endDate;
	
	
	private String labelFormat; //刻度值排版 
	
	
	public Axis(){
		
	}
	


	public Axis(int lineColor, int lineWidth, String title, String type,
			double max, double min, int ticks, Date startDate, Date endDate,
			String labelFormat) {
		super();
		this.lineColor = lineColor;
		this.lineWidth = lineWidth;
		this.title = title;
		this.type = type;
		this.max = max;
		this.min = min;
		this.ticks = ticks;
		this.startDate = startDate;
		this.endDate = endDate;
		this.labelFormat = labelFormat;
	}






	public int getLineColor() {
		return lineColor;
	}

	public void setLineColor(int lineColor) {
		this.lineColor = lineColor;
	}

	public int getLineWidth() {
		return lineWidth;
	}

	public void setLineWidth(int lineWidth) {
		this.lineWidth = lineWidth;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public double getMax() {
		return max;
	}

	public void setMax(double max) {
		this.max = max;
	}

	public double getMin() {
		return min;
	}

	public void setMin(double min) {
		this.min = min;
	}


	public String getLabelFormat() {
		return labelFormat;
	}

	public void setLabelFormat(String labelFormat) {
		this.labelFormat = labelFormat;
	}


	public Date getStartDate() {
		return startDate;
	}


	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}


	public Date getEndDate() {
		return endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}


	public int getTicks() {
		return ticks;
	}


	public void setTicks(int ticks) {
		this.ticks = ticks;
	}
	
	
}

定义点

/**
 * Copyright (c) 2014, alax
 * All Rights Reserved.
 */

package chapterOne.axis;
/**
 *
 * @author   	 alax_app@yeah.net
 * @Date	 	 2014-3-19 上午12:35:20
 *
 */
public class Point {
	
	private int x;
	private int y;
	
	
	public Point(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	
}

画利用bufferedImage画坐标

/**
 * Copyright (c) 2014, alax
 * All Rights Reserved.
 */

package chapterOne.axis;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.imageio.ImageIO;

/**
 *
 * @author   	 alax_app@yeah.net
 * @Date	 	 2014-3-19 上午12:30:20
 *
 */
public class AxisUtils {

	
	public static void main(String[] args) throws Exception {
		int width = 1000;
		int height = 400;
		AxisBorder axisBorder = new AxisBorder(60, 60, 40, 40, 0xffffff);
		BufferedImage bufferedImage = new BufferedImage(width+axisBorder.getLeft() + axisBorder.getRight(),
				height + axisBorder.getTop() +axisBorder.getBottom(), BufferedImage.TYPE_INT_RGB);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		
		Graphics2D g = bufferedImage.createGraphics();
		Date startDate = sdf.parse("20140318120000");
		Date endDate = sdf.parse("20140320120000");
		Axis xAxis = new Axis(0x000000, 2, "时间", "datetime", 0, 0, 5, startDate, endDate, "");
		Axis yAxis = new Axis(0x000000, 2, "高度", "value", 30, 0, 5, null, null, "");
		drawAxis(axisBorder, xAxis, yAxis, width, height, g);
		
		//导出图片
		String pathname = "E:\\config\\test.jpg";
		ImageIO.write(bufferedImage, "jpg", new File(pathname));
		
	}
	public static void drawAxis(AxisBorder border ,Axis xaxis, Axis yaxis, int width, int height, Graphics2D g){
		//抗锯齿 字体更平滑
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		drawBorder(border, width, height, g);
		drawXAxis(border, xaxis, width, height, g);
		drawYAxis(border, yaxis, width, height, g);
		//设置作图区域颜色为白色
		g.setColor(new Color(0xFFFFFF));
		g.fillRect(border.getLeft(), border.getTop(), width, height);
	}
	
	/**
	 * 画x轴坐标
	 * @param axisBorder
	 * @param xaxis
	 * @param width
	 * @param height
	 * @param g
	 */
	private static void drawXAxis(AxisBorder axisBorder,
			Axis xaxis, int width ,int height, Graphics2D g){
		//画x坐标
		Point point1 = new Point(axisBorder.getLeft(), axisBorder.getTop() + height);
		Point point2 = new Point(axisBorder.getLeft() + width, axisBorder.getTop() + height);
		drawLine(point1, point2, new Color(xaxis.getLineColor()) , xaxis.getLineWidth(), g);
		//画刻度
		int ticks = xaxis.getTicks();
		int skips = width / ticks;
		int x = axisBorder.getLeft();
		int y1 = axisBorder.getTop() + height ;
		int y2 = y1 + 10;
		String type = xaxis.getType();	//获取坐标轴类型
		for(int i = 1 ; i <= ticks ; i++){
			point1 = new Point(x + skips * i,y1);
			point2 = new Point(x + skips * i,y2);
			drawLine(point1, point2, new Color(xaxis.getLineColor()) , xaxis.getLineWidth(), g);
			
		}
		//画label
		if(type.equals(Axis.VALUE)){
			double vskips = (xaxis.getMax() - xaxis.getMin() ) / ticks + xaxis.getMin();
			for(int i = 1 ; i <= ticks ; i++){
				drawString(g, x + skips * i, y2, getValueLabel(vskips * i + xaxis.getMin(), xaxis.getLabelFormat()));
			}
		}else if(type.equals(Axis.DATETIME)){
			long t0 = xaxis.getStartDate().getTime() ;
			long tskips = ( xaxis.getEndDate().getTime() - t0 ) /ticks;
			Calendar c = Calendar.getInstance();
			for(int i = 1 ; i <= ticks ; i++){
				c.setTimeInMillis(t0 + i * tskips);
				drawString(g, x + skips * i, y2+10, getDateLabel(c.getTime(), xaxis.getLabelFormat()));
			}
		}
		//画title
		drawString(g, axisBorder.getLeft(), 
				axisBorder.getTop() + height + axisBorder.getBottom() /2, xaxis.getTitle());
		
	}
	
	
	/**
	 * 画Y轴坐标
	 * @param axisBorder
	 * @param yaxis
	 * @param width
	 * @param height
	 * @param g
	 */
	private static void drawYAxis(AxisBorder axisBorder,
			Axis axis, int width ,int height, Graphics2D g){
		//画x坐标
		Point point1 = new Point(axisBorder.getLeft(), axisBorder.getTop() + height);
		Point point2 = new Point(axisBorder.getLeft(), axisBorder.getTop());
		
		
		drawLine(point1, point2, new Color(axis.getLineColor()) , axis.getLineWidth(), g);
		
		//画刻度
		int ticks = axis.getTicks();
		int skips = height / ticks;
		int x1 = axisBorder.getLeft();
		int x2 = x1 - 10 ;
		int y1 = axisBorder.getTop() + height ;
		String type = axis.getType();	//获取坐标轴类型
		for(int i = 1 ; i <= ticks ; i++){
			point1 = new Point(x2,y1 - skips * i);
			point2 = new Point(x1,y1 - skips * i);
			drawLine(point1, point2, new Color(axis.getLineColor()) , axis.getLineWidth(), g);
			
		}
		//画label
		if(type.equals(Axis.VALUE)){
			double vskips = (axis.getMax() - axis.getMin() ) / ticks + axis.getMin();
			for(int i = 1 ; i <= ticks ; i++){
				drawString(g, x2 - 20 , y1 - skips * i, getValueLabel(vskips * i + axis.getMin(), axis.getLabelFormat()));
			}
		}else if(type.equals(Axis.DATETIME)){
			long t0 = axis.getStartDate().getTime() ;
			long tskips = ( axis.getEndDate().getTime() - t0 ) /ticks;
			Calendar c = Calendar.getInstance();
			for(int i = 1 ; i <= ticks ; i++){
				c.setTimeInMillis(t0 + i * tskips);
				drawString(g, x2 - 20 , y1 - skips * i, getDateLabel(c.getTime(), axis.getLabelFormat()));
			}
		}
		//画title
		//画y坐标title
		int x = Math.min(30, axisBorder.getLeft());
		int y0 = axisBorder.getTop() + height/2 + 80;
		
		//逆时针旋转180度
		g.rotate(-Math.PI/2, x, y0);
		Font font = new Font("宋体", Font.BOLD, 16);
		g.setFont(font);
		g.drawString(axis.getTitle(),x,y0);
		//恢复画布,顺时针旋转180度
		g.rotate(Math.PI/2,x,y0);
		
	}
	
	/**
	 * 画线
	 * @param point1
	 * @param point2
	 * @param lineColor
	 * @param lineWidth
	 * @param g
	 */
	private static void drawLine(Point point1 , Point point2, Color lineColor, int lineWidth ,Graphics2D g){
		g.setStroke(new BasicStroke(lineWidth));
		g.setColor(lineColor);
		g.drawLine(point1.getX(), point1.getY(), point2.getX(), point2.getY());
	}
	
	/**
	 * 写字符
	 */
	private static void drawString(Graphics2D g,int x ,int y,String str){
		g.drawString(str, x, y);
	}
	
	
	
	/**
	 * 获取数字型label
	 * @param value
	 * @param format
	 * @return
	 */
	public static String getValueLabel(double value , String format ){
		if(format == null  || format.equals("")){
			return value +"";
		}
		return String.format(format, value+"");
	}
	
	/**
	 * 获取时间类型label
	 * @param date
	 * @param format
	 * @return
	 */
	public static String getDateLabel(Date date , String format){
		SimpleDateFormat sdf = new SimpleDateFormat("dd");
		if(format == null  || format.equals("")){
			format = "dd日HH时";
		}
		sdf.applyPattern(format);
		return sdf.format(date);
	}
	
	/**
	 * 画border
	 * @param border
	 * @param width
	 * @param height
	 * @param g
	 */
	public static void drawBorder(AxisBorder border, int width, int height,Graphics2D g){
		g.setColor(new Color(border.getBackgroundColor()));
		g.fillRect(0, 0, border.getLeft(), border.getTop()+height+border.getBottom()); //填充背景色
		g.fillRect(border.getLeft(), 0, width+border.getRight(), border.getTop());
		g.fillRect(border.getLeft(), border.getTop()+height, width+border.getRight(), border.getBottom());
		g.fillRect(border.getLeft()+width, border.getTop(), border.getRight(), height);
	}
	
}

测试方法

public static void main(String[] args) throws Exception {
		int width = 1000;
		int height = 400;
		AxisBorder axisBorder = new AxisBorder(60, 60, 40, 40, 0xffffff);
		BufferedImage bufferedImage = new BufferedImage(width+axisBorder.getLeft() + axisBorder.getRight(),
				height + axisBorder.getTop() +axisBorder.getBottom(), BufferedImage.TYPE_INT_RGB);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		
		Graphics2D g = bufferedImage.createGraphics();
		Date startDate = sdf.parse("20140318120000");
		Date endDate = sdf.parse("20140320120000");
		Axis xAxis = new Axis(0x000000, 2, "时间", "datetime", 0, 0, 5, startDate, endDate, "");
		Axis yAxis = new Axis(0x000000, 2, "高度", "value", 30, 0, 5, null, null, "");
		drawAxis(axisBorder, xAxis, yAxis, width, height, g);
		
		//导出图片
		String pathname = "E:\\config\\test.jpg";
		ImageIO.write(bufferedImage, "jpg", new File(pathname));
		
	}

最终效果图如下



<think>嗯,用户现在想用Java Swing矩形。之前他们问过三角形,现在应该是想继续学习绘制其他形状。我需要先回忆一下Swing中绘制图形的基本方法,确保回答的结构和之前的三角形教程类似,这样用户更容易理解。 首先,用户可能需要了解如何在Swing中自定义组件,比如继承JPanel并重写paintComponent方法。之前三角形的时候提到过这点,所以这里也应该强调重写这个方法的重要性,并且记得调用super.paintComponent(g)来确保组件正确渲染。 接下来,绘制矩形的话,Graphics类里有drawRect和fillRect方法,这些可能比三角形更简单,因为矩形只需要指定左上角的坐标、宽度和高度。不过用户可能也会想知道如何绘制圆角矩形或者自定义样式的矩形,比如虚线边框或者不同颜色填充。 然后,考虑到用户之前学过三角形,可能已经了解坐标系的概念,但需要再次确认坐标系原点在左上角,y轴向下,避免坐标计算错误。此外,动态调整矩形位置和大小,比如根据窗口大小居中显示,这也是一个常见的需求,应该包含在步骤中。 用户可能还想知道如何通过不同的方法实现,比如使用drawPolygon或者GeneralPath,虽然对于矩形来说直接使用drawRect更方便,但提供多种方法可以让他们有更多的选择。同时,优化部分应该包括设置颜色、填充、线条粗细以及抗锯齿等,这些都能提升视觉效果。 另外,要检查代码示例是否正确,比如在自定义Panel类中使用正确的参数调用drawRect,主窗口的创建是否和之前的一致。可能还需要提醒一些常见错误,比如忘记调用super.paintComponent导致渲染问题,或者坐标计算错误让矩形显示的位置不对。 最后,需要确保回答结构清晰,分步骤说明,从基础原理到实现步骤,再到参数说明和优化扩展,这样用户能一步步跟着操作。同时,提供完整的代码示例和效果说明,帮助他们验证自己的实现是否正确。</think>--- ### 一、基础原理 1. **Swing绘图核心方法**:与绘制三角形相同,需重写`JPanel`的`paintComponent(Graphics g)`方法 2. **`Graphics`类专用方法**: - `drawRect(int x, int y, int width, int height)`:绘制空心矩形 - `fillRect(...)`:填充矩形 - `drawRoundRect(...)`:绘制圆角矩形 3. **坐标系定位**:参数$(x,y)$表示矩形左上角坐标,宽度和高度单位为像素 --- ### 二、实现步骤(以居中矩形为例) #### 1. 自定义面板类 ```java class RectanglePanel extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 必须首先调用 // 启用抗锯齿(可选) Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 定义矩形参数 int rectWidth = 200; // 宽度 int rectHeight = 120; // 高度 Color fillColor = new Color(255, 200, 200); // 浅红色填充 // 计算居中坐标(左上角位置) int x = (getWidth() - rectWidth) / 2; int y = (getHeight() - rectHeight) / 2; // 绘制填充矩形 g2d.setColor(fillColor); g2d.fillRect(x, y, rectWidth, rectHeight); // 绘制边框(可单独设置样式) g2d.setColor(Color.RED); g2d.setStroke(new BasicStroke(3)); // 3像素宽边框 g2d.drawRect(x, y, rectWidth, rectHeight); } } ``` #### 2. 主窗口创建(通用模板) ```java public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("绘制矩形示例"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 400); frame.add(new RectanglePanel()); frame.setVisible(true); }); } ``` --- ### 三、关键参数详解 $$ drawRect(int\ x,\ int\ y,\ int\ width,\ int\ height) $$ 1. **坐标参数**: - $x$: 左上角x坐标(水平方向) - $y$: 左上角y坐标(垂直方向) 2. **尺寸参数**: - $width$: 矩形宽度(向右延伸) - $height$: 矩形高度(向下延伸) --- ### 四、扩展功能实现 #### 1. 圆角矩形 ```java // 圆角半径参数(水平半径20px,垂直半径15px) int arcWidth = 20; int arcHeight = 15; // 绘制方法 g2d.drawRoundRect(x, y, width, height, arcWidth, arcHeight); ``` #### 2. 渐变填充 ```java // 创建渐变对象(从左上到右下) GradientPaint gradient = new GradientPaint( x, y, Color.BLUE, x + width, y + height, Color.CYAN ); g2d.setPaint(gradient); // 替代setColor g2d.fillRect(x, y, width, height); ``` #### 3. 虚线边框 ```java // 设置虚线模式(实线5px,空白3px) float[] dashPattern = {5, 3}; g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, dashPattern, 0)); g2d.drawRect(x, y, width, height); ``` --- ### 五、不同实现方式对比 | 方法 | 优点 | 适用场景 | |--------------------|------------------------|----------------------| | `drawRect()` | 代码最简,效率高 | 标准直角矩形 | | `drawPolygon()` | 可自定义任意四边形 | 非轴对齐矩形(如旋转矩形) | | `draw(Shape)` | 支持复杂图形操作 | 需要组合图形或路径操作时 | | `draw3DRect()` | 自动生成3D效果边框 | 快速实现立体按钮效果 | --- ### 六、动态调整技巧 1. **响应窗口缩放**:在`paintComponent`中实时计算`x, y`坐标 2. **交互式绘制**:通过鼠标事件获取坐标(示例代码): ```java // 在面板类中添加鼠标监听器 addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); } public void mouseReleased(MouseEvent e) { endX = e.getX(); endY = e.getY(); repaint(); // 触发重绘 } }); // 在paintComponent中使用动态坐标 int width = Math.abs(endX - startX); int height = Math.abs(endY - startY); int x = Math.min(startX, endX); int y = Math.min(startY, endY); g2d.drawRect(x, y, width, height); ``` --- ### 执行效果 - 窗口中心显示一个浅红色填充的矩形(200x120px) - 带有3px宽的红色实线边框 - 窗口缩放时矩形保持居中 - 修改`rectWidth`和`rectHeight`可调整尺寸 - 替换为`drawRoundRect`可实现圆角效果 通过组合这些方法,可以轻松实现从简单到复杂的各种矩形绘制需求。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值