【问题标题】:Drawing multiple connected lines in JApplet by using paintComponent使用paintComponent在JApplet中绘制多条连接线
【发布时间】:2016-01-08 10:37:43
【问题描述】:

我正在尝试创建用户可以在 Canvas 中绘制线条的应用程序。用户可以从下拉列表中选择方向并输入线的长度。第一行从 Canvas 的中心开始,下一行从上一行结束的地方开始,依此类推 - 用户可以一条一条地绘制多条线,并且所有线都连接在一起。

我有两个类 - TurtleApplet,它使用程序逻辑创建 GUI 和 Canvas:

public class TurtleApplet extends JApplet implements ActionListener
{
private JComboBox direction;
private JRadioButton activeButton, passiveButton;
private Button drawButton;
private ButtonGroup group;
private TextField pixels;
private Canvas canvas; 
private JPanel panel;
private JPanel panelRadio;
private Button quitPr;


public void init() 
{ 

    //directions
    String[] directionStrings = { "Right", "Left", "Up", "Down"};
    direction = new JComboBox(directionStrings);
    //direction.setSelectedIndex(4);

    //Buttons
    activeButton = new JRadioButton("Aktīvs");
    passiveButton = new JRadioButton("Neaktīvs");
    quitPr = new Button("Iziet");

    //Canvas
    canvas = new Canvas();
    //canvas.setSize(600, 500);
    //canvas.setBackground(Color.red);
    canvas.setBorder(BorderFactory.createTitledBorder("Turtle drawing"));


    //Panels
    panel = new JPanel();
    panelRadio =new JPanel();   
    panel.setLayout(new FlowLayout());
    panelRadio.setLayout(new FlowLayout());

    //actionListener
    activeButton.addActionListener(this);
    passiveButton.addActionListener(this);
    activeButton.setSelected(true);
    quitPr.addActionListener(this);

    //Add radiobuttons
    group = new ButtonGroup();
    group.add(activeButton);
    group.add(passiveButton);


    //Add Buttons to panel
    panelRadio.add(activeButton);
    panelRadio.add(passiveButton);

    //textfield
    pixels = new TextField(12);

    //Draw button
    drawButton = new Button("Zīmēt");
    drawButton.addActionListener(this);
    direction.addActionListener(this);

    panel.add(panelRadio); 
    panel.add(pixels);
    panel.add(direction);
    panel.add(drawButton);
    panel.add(quitPr);
    getContentPane().add(panel,"North");
    getContentPane().add(canvas, "Center");
    setSize(650,550);

} 


public void actionPerformed( ActionEvent e) 
{
    if ( e.getSource() == activeButton ) {  
        drawButton.setVisible(true);
        pixels.setEditable(true);

    } else if (e.getSource() == passiveButton)  {    
        drawButton.setVisible(false);
        pixels.setEditable(false);

    } else if(e.getSource() == quitPr){
        System.exit(0);
    }else if(e.getSource() == drawButton){

        int y = Integer.parseInt(pixels.getText());
        canvas.addPatt(direction.getSelectedIndex(), Integer.parseInt(pixels.getText()));
        repaint();
    }

   //repaint();
} 


} 




 public class Canvas extends JPanel {
private static final int RIGHT=0, LEFT=1, UP=2, DOWN=3;
public static final int WIDTH=600, HEIGHT=500;
private int direction = 0 ;                          
private int pixels;     
//rivate List points;
public Polygon t = new Polygon();

//public Dimension d = getSize();
public int x = WIDTH/2;
public int y = HEIGHT/2;


public Canvas() {
    setSize(WIDTH, HEIGHT);
}

public void addPatt(int pat, int lev) {
    direction = pat;
    pixels = lev;
}

public void paintComponent(Graphics g) {

    switch (direction) {
    case LEFT: 
        drawLineLeft(g, pixels);

        break;
    case RIGHT:
        drawLineRight(g, pixels);
        break;
    case UP:
        drawLineUp(g, pixels);

        break;
    case DOWN:
        drawLineDown(g, pixels);
        break;
    } 
} 

private void drawLineLeft(Graphics g, int pix){

    if(pix > 0){
       g.drawLine(x, y, x-10*pix, y);//left
       x =x -10*pix;  
    }
}

private void drawLineUp(Graphics g, int pix){

    if(pix > 0){
        g.drawLine(x, y, x, y-10*pix);//up
        y = y-10*pix;    
    }
}

private void drawLineRight(Graphics g, int pix){
    if(pix > 0){
        g.drawLine(x, y, x+10*pix, y);//right
        x = x+10*pix;
    }
}

private void drawLineDown(Graphics g, int pix){
    if(pix > 0){
        g.drawLine(x, y, x, y+10*pix);// down
        y = y+10*pix;
    }
}

} 

Applet 可以工作,但问题是在绘制新行时保存以前的行。当用户输入线条的方向和长度并按下按钮时,屏幕上会出现新的线条,但之前的线条会消失。我知道问题出在paintComponent 方法上,但我不知道如何准确更正我的代码以使所有行都可见。有人建议我将点坐标存储在数组中,然后通过在paintComponent 中循环遍历数组来绘制线条,但我不知道如何实现这一点。也许有更好的解决方案?

【问题讨论】:

  • 正如我在您的last question 中所说,case 状态就像if-else,您只允许它画一条线。您需要维护一个 List 的“行”,每次调用 paintComponent 方法时都可以对其进行迭代
  • 非常感谢您的帮助!我更新了我的代码,但是当我在 Canvas 类中声明 private List<Line> lines 时,我得到了 The type List is not generic; it cannot be parameterized with arguments <Line>。在 GUI 类中单击按钮时如何正确调用升级后的 addPatt 方法?再次感谢您!
  • 为什么要编写小程序?如果是老师指定的,请参考Why CS teachers should stop teaching Java applets
  • 不要导入“java.awt.List”导入“java.util.List”

标签: java swing canvas paintcomponent japplet


【解决方案1】:

正如我在您的last question 中所说,case 状态就像if-else,您只允许它画一条线。您需要维护一个 List 的“行”,每次调用 paintComponent 方法时都可以对其进行迭代

因为一行由多个属性表示,最好将这些信息封装到一个简单的类或 POJO 中

public enum Direction {
    UP, DOWN, LEFT, RIGHT
}

public class Line {
    private Direction direction;
    private int length;

    public Line(Direction direction, int length) {
        this.direction = direction;
        this.length = length;
    }

    public Direction getDirection() {
        return direction;
    }

    public int getLength() {
        return length;
    }


}

在这里,我将方向属性分离为一个简单的enum,这使您可以更轻松地在程序的其他地方引用这些属性

然后您维护Lines 中的List,当调用paintComponent 时,您只需重新迭代并重新绘制...

public class Canvas extends JPanel {

    public static final int WIDTH = 600, HEIGHT = 500;

    public int x = WIDTH / 2;
    public int y = HEIGHT / 2;

    private List<Line> lines;

    public Canvas() {
        lines = new ArrayList<>(25);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(WIDTH, HEIGHT);
    }

    public void addPatt(Direction direction, int length) {
        lines.add(new Line(direction, length));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Line line : lines) {
            switch (line.getDirection()) {
                case UP:
                    drawLineUp(g, line.getLength());
                    break;
                case DOWN:
                    drawLineDown(g, line.getLength());
                    break;
                case LEFT:
                    drawLineLeft(g, line.getLength());
                    break;
                case RIGHT:
                    drawLineDown(g, line.getLength());
                    break;
            }
        }
    }

    private void drawLineLeft(Graphics g, int pix) {

        if (pix > 0) {
            g.drawLine(x, y, x - 10 * pix, y);//left
            x = x - 10 * pix;
        }
    }

    private void drawLineUp(Graphics g, int pix) {

        if (pix > 0) {
            g.drawLine(x, y, x, y - 10 * pix);//up
            y = y - 10 * pix;
        }
    }

    private void drawLineRight(Graphics g, int pix) {
        if (pix > 0) {
            g.drawLine(x, y, x + 10 * pix, y);//right
            x = x + 10 * pix;
        }
    }

    private void drawLineDown(Graphics g, int pix) {
        if (pix > 0) {
            g.drawLine(x, y, x, y + 10 * pix);// down
            y = y + 10 * pix;
        }
    }

}

请记住,在 Swing 中绘制是破坏性的,每次调用 paintComponent 时,您都需要重新绘制组件的整个状态。

请参阅Painting in AWT and SwingPerforming Custom Painting 了解有关绘画工作原理的更多详细信息

【讨论】:

  • 如何从 GUI 类调用 addPatt 方法?它怎么知道选择了哪个方向?
  • 您按照现在的方式进行操作(希望不要传递int 作为方向,而是传递enum
  • 我收到了这个The method addPatt(Direction, int) in the type Canvas is not applicable for the arguments (int, int)
  • 正如我所说,您需要将 enum Direction 传递给方法,而不是您一直在传递的 int canvas.addPatt(Direction.UP, 10); - 这意味着您需要更改JComboBox 中的值到 Direction
  • 现在坐标有问题。例如,当我从中心向上绘制 5 像素长的线时,一切都很好,打赌,当我在同一方向上再添加一条线时,它会在 previos 的末尾添加一条新线,这也很好,但两条线都向上移动从中心距离 5 像素,并且绘图不再从中心开始。每次添加新行时,整个绘图都会移动。
【解决方案2】:

有人建议我将点坐标存储在数组中,然后通过在paintComponent 中循环遍历数组来绘制线条,但我不知道如何实现这一点。

这取决于您的具体要求。

如果您需要添加/删除行的能力,那么这可能是最好的方法。

如果您只需要添加线条的能力,那么您可能希望将线条直接绘制到 BufferedImage,然后将 BufferedImage 显示为 JLabel 上的图标。

查看Custom Painting Approaches,它比较了两种方法并提供了两种方法的工作示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多