Java jFrame画布绘制点而不是线条

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java jFrame画布绘制点而不是线条相关的知识,希望对你有一定的参考价值。

我一直想为龙曲线设计一个生成器。

(如果你想要查看this的信息,但问题并不重要)

龙曲线是重复的数学结构。我已经为画布绘制的内容编写了一个生成器,它通过返回一个由'r'或'l'组成的char数组来工作,说明该行是否必须向左或向右转。在这里的代码中,它是方法input()。这部分很完美。

问题在于,每当我想在画布上绘制它时(使用drawLine),它只会将前两行绘制为实际线条,其余的只是点。

点位于正确的位置,如果你把东西变得很大,你就不能再说出差异,但是,那里应该有线条。

图片:

这是我使用的代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;




/**
  *
  * Description
  *
  * @version 1.0 from 4/20/2016
  * @author 
  */

public class CurveGen extends JFrame {
  // start attributes
  private Canvas display = new Canvas();
  private JButton startButton = new JButton();
  private JLabel jLabel1 = new JLabel();
  private JTextArea outText = new JTextArea("");
    private JScrollPane outTextScrollPane = new JScrollPane(outText);
  private JLabel jLabel2 = new JLabel();
  private JSlider xSlider = new JSlider();
  private JSlider ySlider = new JSlider();
  private JNumberField iterationsNF = new JNumberField();
  private JNumberField sizeNF = new JNumberField();
  // end attributes




  public CurveGen(String title) { 
    // Frame-Init
    super(title);
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    int frameWidth = 1022; 
    int frameHeight = 731;
    setSize(frameWidth, frameHeight);
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    setResizable(false);
    Container cp = getContentPane();
    cp.setLayout(null);
    // start components

    display.setBounds(16, 64, 601, 601);
    cp.add(display);
    startButton.setBounds(736, 464, 241, 129);
    startButton.setText("START!");
    startButton.setMargin(new Insets(2, 2, 2, 2));
    startButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent evt) { 
        startButton_ActionPerformed(evt);
      }
    });
    startButton.setFont(new Font("Dialog", Font.BOLD, 36));
    cp.add(startButton);
    jLabel1.setBounds(760, 96, 75, 41);
    jLabel1.setText("Iterations:");
    cp.add(jLabel1);
    outTextScrollPane.setBounds(728, 392, 257, 57);
    cp.add(outTextScrollPane);
    jLabel2.setBounds(768, 144, 67, 41);
    jLabel2.setText("Size:");
    cp.add(jLabel2);
    xSlider.setBounds(0, 8, 633, 49);
    xSlider.setMinorTickSpacing(25);
    xSlider.setMajorTickSpacing(100);
    xSlider.setPaintTicks(true);
    xSlider.setPaintLabels(true);
    xSlider.setToolTipText("Starting point y-coordinate");
    xSlider.setMaximum(600);
    xSlider.setValue(300);
    cp.add(xSlider);
    ySlider.setBounds(624, 56, 65, 625);
    ySlider.setMinorTickSpacing(25);
    ySlider.setMajorTickSpacing(100);
    ySlider.setPaintTicks(true);
    ySlider.setPaintLabels(true);
    ySlider.setOrientation(SwingConstants.VERTICAL);
    ySlider.setMaximum(600);
    ySlider.setInverted(true);
    ySlider.setValue(300);
    ySlider.setToolTipText("Starting point x-coordinate");
    cp.add(ySlider);
    iterationsNF.setBounds(856, 96, 81, 41);
    iterationsNF.setText("");
    cp.add(iterationsNF);
    sizeNF.setBounds(856, 144, 81, 41);
    sizeNF.setText("");
    cp.add(sizeNF);
    // end components

    setVisible(true);
  } // end of public CurveGen

  // start methods

  public static void main(String[] args) {
    new CurveGen("CurveGen");



  } // end of main

  public char[] input(int iter) {         
    char oldOut[] = new char[0];            
    for (int i=1;i<=iter;i++) {
      char newOut[] = new char[((int)Math.pow(2, i))-1];
      for (int n=0;n<oldOut.length;n++) {
        newOut[n] = oldOut[n];
        if (oldOut[n]=='r') {
          newOut[newOut.length-n-1] = 'l';
        }
        if (oldOut[n]=='l') {
          newOut[newOut.length-n-1] = 'r';
        } // end of if
      } // end of for
      newOut[oldOut.length]='l';      
      oldOut = newOut; 
    } // end of for        
    return oldOut;
  }  



  public void startButton_ActionPerformed(ActionEvent evt) {


    int iterations = iterationsNF.getInt();
    int size = sizeNF.getInt();

    char com[] = input(iterations);
    outText.setText(String.valueOf(com));

    int dir = 0;
    int newDir = 0;
    int lastPos[] = {xSlider.getValue(),ySlider.getValue()-size};
    int newPos[] = {0,0};

    Graphics g = display.getGraphics();

    g.clearRect(0,0,601,601);
    g.drawLine(xSlider.getValue(),ySlider.getValue(),xSlider.getValue(),ySlider.getValue()-size);


    for (int i=0;i<=com.length-1;i++) {
      dir = newDir;
      if (dir==0) {
        if (com[i]=='l') {
          newPos[0] = lastPos[0]-size;
          newPos[1] = lastPos[1];
          newDir = 3;
        } 
        if (com[i]=='r') {
          newPos[0] = lastPos[0]+size;
          newPos[1] = lastPos[1];
          newDir = 1;
        }              
      } 
      if (dir==1) {
        if (com[i]=='l') {
          newPos[0] = lastPos[0];
          newPos[1] = lastPos[1]-size;
          newDir = 0;
        } 
        if (com[i]=='r') {
          newPos[0] = lastPos[0];
          newPos[1] = lastPos[1]+size;
          newDir = 2;
        }              
      } 
      if (dir==2) {
        if (com[i]=='l') {
          newPos[0] = lastPos[0]+size;
          newPos[1] = lastPos[1];
          newDir = 1;
        } 
        if (com[i]=='r') {
          newPos[0] = lastPos[0]-size;
          newPos[1] = lastPos[1];
          newDir = 3;
        }              
      } 
      if (dir==3) {                                
        if (com[i]=='l') {
          newPos[0] = lastPos[0];
          newPos[1] = lastPos[1]+size;
          newDir = 2;
        } 
        if (com[i]=='r') {
          newPos[0] = lastPos[0];
          newPos[1] = lastPos[1]-size;
          newDir = 0;
        }              
      } 

      g.drawLine(lastPos[0],lastPos[1],newPos[0],newPos[1]);

      lastPos=newPos;
    } // end of for




  } // end of startButton_ActionPerformed

  // end methods
} // end of class CurveGen
答案

好的,所以我回过头来看代码......

  • 混合重量级(java.awt.Canvas)和轻量级(Swing)组件是不可取的,因为它们可能导致或各种绘画问题
  • getGraphics不是应该如何涂漆。相反,我开始使用自定义JPanel并覆盖其paintComponent。有关详细信息,请参阅Painting in AWT and SwingPerforming Custom Painting
  • 避免使用null布局,像素完美布局是现代ui设计中的错觉。影响组件个体大小的因素太多,您无法控制。 Swing旨在与布局管理器一起工作,放弃这些将导致问题和问题的结束,您将花费越来越多的时间来纠正

我认为问题与此有关......

lastPos=newPos;

你所做的只是让lastPos指向内存中与newPos相同的位置,所以当你为newPos指定值时,lastPos将具有相同的值,因此你看到点的原因。

我首先要做的是分离负责从显示器生成数据。

我从某种模型开始(注意,你可以创建一个模型,它取代了iterations,它生成了数据本身,但我专注于解决最初的问题)

public class DragonModel {

    private Point startPoint;
    private int size;
    private char[] values;

    public DragonModel(Point startPoint, int size, char[] values) {
        this.startPoint = startPoint;
        this.size = size;
        this.values = values;
    }

    public Point getStartPoint() {
        return startPoint;
    }

    public int getSize() {
        return size;
    }

    public char[] getValues() {
        return values;
    }

}

然后显示...

public class DragonPane extends JPanel {

    private DragonModel model;

    public void setModel(DragonModel model) {
        this.model = model;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (model != null) {
            Graphics2D g2d = (Graphics2D) g.create();
            int size = model.getSize();
            int dir = 0;
            int newDir = 0;
            Point lastPos = model.getStartPoint();
            Point newPos = new Point(0, 0);

            for (char value : model.values) {
                if (dir == 0) {
                    if (value == 'l') {
                        newPos.x = lastPos.x - size;
                        newPos.y = lastPos.y;
                        newDir = 3;
                    }
                    if (value == 'r') {
                        newPos.x = lastPos.x + size;
                        newPos.y = lastPos.y;
                        newDir = 1;
                    }
                }
                if (dir == 1) {
                    if (value == 'l') {
                        newPos.x = lastPos.x;
                        newPos.y = lastPos.y - size;
                        newDir = 0;
                    }
                    if (value == 'r') {
                        newPos.x = lastPos.x;
                        newPos.y = lastPos.y + size;
                        newDir = 2;
                    }
                }
                if (dir == 2) {
                    if (value == 'l') {
                        newPos.x = lastPos.x + size;
                        newPos.y = lastPos.y;
                        newDir = 1;
                    }
                    if (value == 'r') {
                        newPos.x = lastPos.x - size;
                        newPos.y = lastPos.y;
                        newDir = 3;
                    }
                }
                if (dir == 3) {
                    if (value == 'l') {
                        newPos.x = lastPos.x;
                        newPos.y = lastPos.y + size;
                        newDir = 2;
                    }
                    if (value == 'r') {
                        newPos.x = lastPos.x;
                        newPos.y = lastPos.y - size;
                        newDir = 0;
                    }
                }
                g.drawLine(lastPos.x, lastPos.y, newPos.x, newPos.y);
                dir = newDir;
                lastPos = new Point(newPos);

            }
        }

    }
} 

这里的想法是尝试将责任分解一点,产生和显示数据的责任牢牢地存在于两个不同的领域。

然后在你的actionPerformed方法中你可以简单地做...

public void startButton_ActionPerformed(ActionEvent evt) {

    int iterations = Integer.parseInt(iterationsNF.getText());
    int size = Integer.parseInt(sizeNF.getText());

    char com[] = input(iterations);
    outText.setText(String.valueOf(com));

    DragonModel model = new DragonModel(new Point(xSlider.getValue(), ySlider.getValue()), size, com);
    display.setModel(model);

} // end of startButton_ActionPerformed

这可能会导致......

Dragons!

另一答案

绘图代码应该在paint(Graphics)方法内部,以正确地与渲染循环同步。在事件处理程序中,更新组件的数据模型(计算行并将它们保存在组件内的数据结构中),然后调用方法repaint()以触发事件呈现循环,这将调用您的paint方法。

还有其他一些变体,但一般的想法是你更改数据然后请求渲染。渲染引擎也可以在其他情况下调用您的paint方法,不仅在您更改数据时,因此理想情况下paint()具有快速渲染所需的所有数据,这意味着它不应该执行除渲染之外的计算或繁重操作Graphics对象。

这意味着您必须在新类中继承JComponent,并在其中实现paint。这个类应该有一个内部数据结构,其中的行准备好在任何时间点呈现。然后在JFrame中使用新类。

以上是关于Java jFrame画布绘制点而不是线条的主要内容,如果未能解决你的问题,请参考以下文章

如何在画布上动画绘制线条

绘制画布后淡出线条?

如何在html5画布中逐步绘制线条动画

在 HTML 画布上绘制的线条未出现在触摸事件中

从 Typescript 中的 For 循环在画布上绘制线条不会呈现

如何让用户在 WPF 中使用画布绘制线条