【问题标题】:How to draw lines in Java如何在 Java 中画线
【发布时间】:2011-08-13 16:34:11
【问题描述】:

我想知道Java中是否有一个函数可以从坐标(x1,x2)到(y1,y2)画一条线?

我想要做这样的事情:

drawLine(x1, x2, x3, x4);

而且我希望能够在代码中的任何时候做到这一点,让几行同时出现。

我已经尝试过这样做:

public void paint(Graphics g){
   g.drawLine(0, 0, 100, 100);
}

但这使我无法控制何时使用该函数,并且我无法弄清楚如何多次调用它。

希望你明白我的意思!

附:我想创建一个有很多坐标的坐标系。

【问题讨论】:

  • 您使用的是 AWT 还是 Swing?在当今时代使用 AWT 毫无意义。如果在 Swing 中编码,使用非“顶级”容器,例如 JComponentJPanel,覆盖 paintComponent(Graphics) 方法而不是 paint(Graphics)
  • 我正在使用 AWT,只是因为那是我第一次发现的......但我会尝试你的建议。谢谢

标签: java coordinates coordinate-systems


【解决方案1】:

一个非常简单的用于绘制线条的摆动组件示例。它在内部保留一个列表,其中包含使用方法 addLine 添加的行。每次添加新行时,都会调用 repaint 来通知图形子系统需要新的绘制。

该类还包括一些使用示例。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class LinesComponent extends JComponent{

private static class Line{
    final int x1; 
    final int y1;
    final int x2;
    final int y2;   
    final Color color;

    public Line(int x1, int y1, int x2, int y2, Color color) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.color = color;
    }               
}

private final LinkedList<Line> lines = new LinkedList<Line>();

public void addLine(int x1, int x2, int x3, int x4) {
    addLine(x1, x2, x3, x4, Color.black);
}

public void addLine(int x1, int x2, int x3, int x4, Color color) {
    lines.add(new Line(x1,x2,x3,x4, color));        
    repaint();
}

public void clearLines() {
    lines.clear();
    repaint();
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    for (Line line : lines) {
        g.setColor(line.color);
        g.drawLine(line.x1, line.y1, line.x2, line.y2);
    }
}

public static void main(String[] args) {
    JFrame testFrame = new JFrame();
    testFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    final LinesComponent comp = new LinesComponent();
    comp.setPreferredSize(new Dimension(320, 200));
    testFrame.getContentPane().add(comp, BorderLayout.CENTER);
    JPanel buttonsPanel = new JPanel();
    JButton newLineButton = new JButton("New Line");
    JButton clearButton = new JButton("Clear");
    buttonsPanel.add(newLineButton);
    buttonsPanel.add(clearButton);
    testFrame.getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
    newLineButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            int x1 = (int) (Math.random()*320);
            int x2 = (int) (Math.random()*320);
            int y1 = (int) (Math.random()*200);
            int y2 = (int) (Math.random()*200);
            Color randomColor = new Color((float)Math.random(), (float)Math.random(), (float)Math.random());
            comp.addLine(x1, y1, x2, y2, randomColor);
        }
    });
    clearButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            comp.clearLines();
        }
    });
    testFrame.pack();
    testFrame.setVisible(true);
}

}

【讨论】:

  • @Karoline:我同意你将这篇文章标记为“正确”的决定。这是第一篇使用 Swing 的文章,充分利用了 OO(Line 类)并展示了如何在按钮单击时添加线条以及删除它们。 @jassuncao:不过有一个问题。在ArrayList(看似“更轻”)上使用LinkedList 是否有任何具体原因?
  • 在这种情况下,我们不需要 ArrayList 中存在的快速索引优势。添加新行是一个恒定且快速的操作,对于具有大量元素的 ArrayList 来说,这是无法保证的。但主要原因是我习惯了计算机图形的链表。这是我年轻时用 C 语言开发 3D 引擎时使用最多的东西。
  • 导入 java.awt.*;导入 java.awt.event.*;导入 java.util.LinkedList;导入 javax.swing.*;
【解决方案2】:

将行存储在某种类型的列表中。当需要绘制它们时,迭代列表并绘制每一个。像这样:

截图

DrawLines

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.Line2D;

import javax.swing.JOptionPane;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;

import java.util.ArrayList;
import java.util.Random;

class DrawLines {

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            public void run() {
                LineComponent lineComponent = new LineComponent(400,400);
                for (int ii=0; ii<30; ii++) {
                    lineComponent.addLine();
                }
                JOptionPane.showMessageDialog(null, lineComponent);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class LineComponent extends JComponent {

    ArrayList<Line2D.Double> lines;
    Random random;

    LineComponent(int width, int height) {
        super();
        setPreferredSize(new Dimension(width,height));
        lines = new ArrayList<Line2D.Double>();
        random = new Random();
    }

    public void addLine() {
        int width = (int)getPreferredSize().getWidth();
        int height = (int)getPreferredSize().getHeight();
        Line2D.Double line = new Line2D.Double(
            random.nextInt(width),
            random.nextInt(height),
            random.nextInt(width),
            random.nextInt(height)
            );
        lines.add(line);
        repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.white);
        g.fillRect(0, 0, getWidth(), getHeight());
        Dimension d = getPreferredSize();
        g.setColor(Color.black);
        for (Line2D.Double line : lines) {
            g.drawLine(
                (int)line.getX1(),
                (int)line.getY1(),
                (int)line.getX2(),
                (int)line.getY2()
                );
        }
    }
}

【讨论】:

  • 完美运行!很好的例子!虽然我确实把它分成了两个文件(每个班级一个)。我还向 LineComponent 添加了函数 addLine(double x1, double y1, double x2, double y2) 以便我可以添加自己选择的行。
  • @Tihamer “虽然我确实将它分成了两个文件(每个类一个文件)。” 我应该期望大多数人会做出更多的改变以适应将minimal reproducible example 中的概念 放入他们的代码库或应用程序中。一个非公开课程的唯一原因是让 MRE 成为可能!很高兴它有帮助。 :)
【解决方案3】:

您需要创建一个扩展 Component 的类。在那里您可以覆盖paint方法并将您的绘画代码放入:

package blah.whatever;

import java.awt.Component;
import java.awt.Graphics;

public class TestAWT extends Component {

/** @see java.awt.Component#paint(java.awt.Graphics) */
@Override
public void paint(Graphics g) {
    super.paint(g);
    g.drawLine(0,0,100,100);
    g.drawLine(10, 10, 20, 300);
    // more drawing code here...
}

}

将此组件放入应用程序的 GUI 中。如果您使用的是 Swing,则需要扩展 JComponent 并覆盖paintComponent。

正如 Helios 所提到的,绘制代码实际上告诉系统您的组件的外观。当系统认为需要(重新)绘制时(例如,如果窗口移动到您的组件前面),系统会询问此信息(调用您的绘制代码)。

【讨论】:

    【解决方案4】:

    在你的课堂上你应该有:

    public void paint(Graphics g){
       g.drawLine(x1, y1, x2, y2);
    }
    

    然后,如果需要,您将在代码中更改 x1、y1、x2、y2 并调用 repaint();

    【讨论】:

    • @Karoline:要显示多个图形,只需遍历它们并全部绘制出来
    【解决方案5】:

    我了解到您正在使用 Java AWT API 进行绘图。当控件需要重绘时调用paint方法。而且我很确定它在 Graphics 参数中提供了需要重绘的矩形(以避免重绘所有矩形)。

    因此,如果您要呈现固定图像,则只需在该方法中绘制所需的任何内容。

    如果您正在制作动画,我假设您可以使某些区域无效,并且将自动调用绘制方法。所以你可以修改状态,调用invalidate,会再次调用。

    【讨论】:

    • +1 用于解释无效区域。执行此操作时要了解的重要概念。
    【解决方案6】:

    给你一些想法:

    public void paint(Graphics g) {
       drawCoordinates(g);
    }
    
    private void drawCoordinates(Graphics g) {
    
      // get width & height here (w,h)
    
      // define grid width (dh, dv)
    
      for (int x = 0; i < w; i += dh) {
        g.drawLine(x, 0, x, h);
      }
      for (int y = 0; j < h; j += dv) {
          g.drawLine(0, y, w, y);
      }
    }
    

    【讨论】:

    • 我想问是否可以使用双变量而不是整数来画线。如果是怎么办?
    • 你不能。例如,没有像素 3.4 这样的东西。
    【解决方案7】:

    您可以使用要在其上绘制的组件的getGraphics 方法。反过来,这应该允许您绘制线条并制作其他可通过 Graphics 类获得的东西

    【讨论】:

    • 我只得到 getGraphics 方法的空指针异常:(
    • 你从哪个类调用getGraphics?
    • "你可以使用组件的getGraphics方法" 当然可以,但是这样做是愚蠢的。 Java 绘画应在请求时在paint()paintComponent() 方法中完成。
    【解决方案8】:

    我构建了一整类方法来绘制点、线、矩形、圆等。我将它设计为将窗口视为一张方格纸,其中原点不必位于左上角,并且y 值随着您的上升而增加。这是我画线的方法:

    public static void drawLine (double x1, double y1, double x2, double y2)
    {       
        ((Graphics2D)g).draw(new Line2D.Double(x0+x1*scale, y0-y1*scale, x0+x2*scale, y0-y2*scale));
    }
    

    在上面的示例中,(x0, y0) 表示屏幕坐标中的原点,scale 是缩放因子。输入参数将作为图形坐标提供,而不是屏幕坐标。没有repaint() 被调用。你可以保存它,直到你画完所有你需要的线。

    我突然想到有人可能不想用方格纸来思考:

        ((Graphics2D)g).draw(new Line2D.Double(x1, y1, x2, y2));
    

    注意Graphics2D 的使用。这允许我们使用双精度而不是整数来绘制Line2D 对象。除了其他形状之外,我的课程还支持 3D 透视图和一些便捷的方法(例如在给定半径的某个点绘制一个圆心。)如果有人感兴趣,我很乐意分享更多这门课程。

    【讨论】:

      【解决方案9】:
      a simple line , after that you can see also a doted line 
      
      import java.awt.*;
      
      import javax.swing.*;
      
      import java.awt.Graphics.*;
      
      import java.awt.Graphics2D.*;
      
      import javax.swing.JFrame;
      
      import javax.swing.JPanel;
      
      import java.awt.BasicStroke;
      
      import java.awt.Event.*;
      
      import java.awt.Component.*;
      
      import javax.swing.SwingUtilities;
      
      
      /**
       *
       * @author junaid
       */
      public class JunaidLine extends JPanel{
      
      
      //private Graphics Graphics;
      
      private void doDrawing(Graphics g){
      
      Graphics2D g2d=(Graphics2D) g;
      
      float[] dash1 = {2f,0f,2f};
      
      g2d.drawLine(20, 40, 250, 40);
      
      BasicStroke bs1 = new BasicStroke(1,BasicStroke.CAP_BUTT,
      
                          BasicStroke.JOIN_ROUND,1.0f,dash1,2f);
      
      g2d.setStroke(bs1);
      
      g2d.drawLine(20, 80, 250, 80);
      
          }
      
      @Override
      
      public void paintComponent(Graphics g){
      
      super.paintComponent( g);
      
      doDrawing(g);
      
      }
      
      
      }
      
      class BasicStrokes extends JFrame{
      
      public  BasicStrokes(){
      
      initUI();
      
      }
      
      private void initUI(){
      
      setTitle("line");
      
      setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      
      add(new JunaidLine());
      
      setSize(280,270);
      
      setLocationRelativeTo(null);
      
      }
      
      /**
      
      * @param args the command line arguments
      
      */
      
      public static void main(String[] args) {
      
      
      SwingUtilities.invokeLater(new Runnable(){   
      
      @Override
      
      public void run(){
      
      BasicStrokes bs = new BasicStrokes();
      
      bs.setVisible(true);
      
      }                
      
      });
      
      }
      
      
      }
      

      【讨论】:

        【解决方案10】:

        要回答您最初的问题,请使用 (x1, y1)(x2, y2)

        例如,

        这是画一条水平线:

        g.drawLine( 10, 30, 90, 30 );
        

        这是画一条垂直线:

        g.drawLine( 10, 30, 10, 90 );
        

        我希望它有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-13
          • 2011-06-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多