0

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

(如果您想了解这方面的信息,请查看信息,但这对于该问题并不重要)

龙曲线是一个重复的数学结构。我已经为画布应该绘制的内容编写了一个生成器,它通过返回一个由 '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
4

2 回答 2

2

Okay, so I've gone back over the code...

  • Mixing heavyweight (java.awt.Canvas) and lightweight (Swing) components is unadvisable as they can cause or sorts of painting issues
  • getGraphics is not how paint should be done. Instead, I'd start with a custom JPanel and override its paintComponent. See Painting in AWT and Swing and Performing Custom Painting for more details
  • Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

I believe the problem is associated with this...

lastPos=newPos;

All you are doing is making lastPos point to the same place in memory as newPos, so when you assign values to newPos, lastPos will have the same values, hence the reason you're seeing dots.

What I would do first, is separate the responsible for the generation of the data from the display.

I'd start with some kind of model (note, you could create a model which took iterations instead and which generated the data itself, but I was focusing on solving the initial problem)

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

}

and then the display...

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

            }
        }

    }
} 

The idea here is to try and decouple of the responsibility a little, the responsibility for the generation and displaying of the data sit firmly in two different areas.

Then in your actionPerformed method you could simply do...

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

which could result in something like...

Dragons!

于 2016-04-21T01:35:06.653 回答
0

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

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

这意味着您必须在一个新类中继承 JComponent,并在其中实现绘制。这个类应该有一个内部数据结构,其中的线条可以随时呈现。然后在 JFrame 中使用您的新类。

于 2016-04-21T01:21:03.333 回答