繁体   English   中英

使用Swing Java绘画

[英]Paint with Swing Java

首先大家好!

我对此有一个大问题:我需要构建一个程序,该程序包括构建一个包含5个正方形和一个按钮的java swing接口。 按钮功能是在正方形内画一个圆。 我有此代码,但我不知道如何继续。

框架类:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
public class Window extends JFrame{

    private static Pane pane;

    private Window(){
        setResizable(false);
        setVisible(true);
        setBounds(0,0,350,200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args){
        Window window = new Window();
        window.setLocationRelativeTo(null);

        pane = new Pane();
        window.add(pane);       
    }

}

窗格类:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLayeredPane;

public class Pane extends JPanel implements ActionListener{

    private JButton next;

    public Pane(){
        setBounds(0,0,350,200);
        setVisible(true);
        setLayout(null);
        repaint();

        next = new JButton("Next");
        next.setBounds(125,125,100,30);
        next.addActionListener(this);
        add(next);

    }

    public void actionPerformed (ActionEvent e){
        Object source = e.getSource();
        if (source == next){
            Graphics g = this.getGraphics();
            drawing(g);
        }
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawRect(50,50,50,50);
        g.drawRect(100,50,50,50);
        g.drawRect(150,50,50,50);
        g.drawRect(200,50,50,50);
        g.drawRect(250,50,50,50);
    }

    private int times = 0;
    public void drawing(Graphics g){
        if(times<5){
            g.setColor(Color.RED);
            g.fillOval(50+times*50, 50, 50, 50);
            times++;
        }
    }

}

我有这个问题和疑问:

  • 当我第一次点击“下一步”按钮时,圆圈出现并在第一个方框中立即消失。 我如何做才能让圆环首次可见?
  • 当我第二次点击按钮时,它在第二个正方形中出现了圆圈。 我不知道,我想问的是:我怎样才能使第一个正方形中的圆圈消失而只让第二个正方形中的圆圈可见? 对于圆在第三个正方形中的情况,我想做的是相同的,我想使圆在第二个正方形中消失。
  • 如果我想让圆出现在程序的开头,但是我想要一个蓝色的圆,然后在2°,3°,4°和5°的位置上想要一个红色的圆圈,我该怎么做? (请记住,当我点击“下一步”按钮时,圆圈会出现。

非常感谢大家!

//Graphics g = this.getGraphics();

不要使用getGraphics()进行绘画。 该绘制只是临时的,一旦组件重新绘制自身,就会丢失。

所有绘画都必须在paintComponent()方法中完成。 这意味着您需要在类中设置一个属性,该属性将告诉paintComponent()绘制什么。

一种方法是保留要绘制的对象List 然后,在paintComponent()方法中,遍历List并绘制对象。

因此,您可以使用以下代码创建列表:

List<Shape> shapes = new ArrayList<Shape>();

Shape的界面允许您代表的几何形状,如圆形,矩形,多边形等。然后,当你想画你添加一个圆形与如代码列表中的第一圈:

shapes.add( new Ellipse2D.Double(50, 50, 50, 50) );

最后,在paintComponent()方法中,绘制矩形之后,添加代码以绘制List中的Shapes。

Graphics2D g2d = (Graphics2D)g.create();

for (Shape shape: shapes)
{
    g2d.setColor( Color.RED );
    g2d.fill( shape );
}

g2d.dispose()

因此,无论何时单击下一步按钮,都将清除“列表”并添加一个新的Shape进行绘制。 或者,如果您不清除列表,则可以添加更多的圆圈,它们都将被绘制。

这有些事情,您做得不正确。

  1. 首先,在实际将所有组件添加到JFrame并使其实现大小之前,先将JFrame的visible属性设置为visible。
  2. 其次,您使用Absolute Layout ,在大多数情况下都应避免使用这种Absolute Layout
  3. 第三,显式创建一个Graphics对象,应避免使用该对象,而是默认使用Java的paintComponent ( ... )方法提供的对象。

看一下这个例子:

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

public class DrawingCircleExample {

    private JPanel drawingBoard;
    private JButton button;

    private static final int GAP = 5;

    private void displayGUI () {
        JFrame frame = new JFrame ( "" );
        frame.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );

        JPanel contentPane = new JPanel ();
        contentPane.setLayout ( new BorderLayout ( GAP, GAP ) );
        drawingBoard = new DrawingBoard ();
        contentPane.add ( drawingBoard, BorderLayout.CENTER );

        button = new JButton ( "Draw" );
        button.addActionListener ( new ActionListener () {
            @Override
            public void actionPerformed ( ActionEvent ae ) {
                 DrawingBoard board = ( DrawingBoard ) drawingBoard;
                 board.setState ();
            }
        } );
        contentPane.add ( button, BorderLayout.PAGE_END );

        frame.setContentPane ( contentPane );
        frame.pack ();
        frame.setLocationByPlatform ( true );
        frame.setVisible ( true );
    }

    public static void main ( String [] args ) {
        Runnable runnable = new Runnable () {
            @Override
            public void run () {
                new DrawingCircleExample ().displayGUI ();
            }
        };
        EventQueue.invokeLater ( runnable );
    }
}

class DrawingBoard extends JPanel {

    private static final int TOTAL_RECTANGLES = 5;
    private static final int WIDTH = 400;
    private static final int HEIGHT = 300;
    private static final int RADIUS = 50;
    private static final int X = 50;
    private static final int Y = 50;
    private int counter;
    private int moveXBy;
    private boolean isActive;
    private int count;

    public DrawingBoard () {
        setOpaque ( true );
        counter = 0;
        count = 0;
        isActive = false;
        moveXBy = ( RADIUS + ( counter ) * RADIUS );
    }

    public boolean setState () {        
        isActive = true;
        System.out.println ( "Outside MoveXBy: " + moveXBy );
        ++counter;
        counter %= TOTAL_RECTANGLES;
        int x = ( RADIUS + ( counter ) * RADIUS );
        if ( moveXBy != x ) {
            System.out.println ( "Inside First MoveXBy: " + moveXBy );
            repaint ( moveXBy, RADIUS, X, Y );
            moveXBy = x;
            System.out.println ( "Inside Second MoveXBy: " + moveXBy );
            repaint ( moveXBy, RADIUS, X, Y );          
        }       

        return isActive;
    }

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

    @Override
    protected void paintComponent ( Graphics g ) {
        super.paintComponent ( g );
        g.drawRect ( 50, RADIUS, X, Y );
        g.drawRect ( 100, RADIUS, X, Y );
        g.drawRect ( 150, RADIUS, X, Y );
        g.drawRect ( 200, RADIUS, X, Y );
        g.drawRect ( 250, RADIUS, X, Y );

        g.setColor ( Color.RED );
        g.fillOval ( moveXBy, RADIUS, X, Y ) ;
    }
}

编辑有关评论:

所有图形用户界面都需要某种主应用程序框架来显示。 Swing中 ,这是javax.swing.JFrame的实例。 因此,我们的第一步是实例化此类,并确保一切正常。 请注意,在Swing中进行编程时,您的GUI创建代码应放在事件调度线程(EDT)上 ,有关Swing中并发的更多信息。 这将防止可能导致死锁的潜在比赛条件。

DrawingBoard还重写getPreferredSize ,该方法返回面板的所需宽度和高度(在这种情况下, 400width300为高度)。因此, DrawingCircleExample类不再需要指定帧的大小(以像素为单位)。 它只是将面板添加到框架,然后调用pack。

paintComponent方法是您进行所有自定义绘制的地方。 该方法由javax.swing.JComponent定义,然后被您的子类覆盖以提供其自定义行为。 它的唯一参数是java.awt.Graphics对象,它公开了许多绘制2D形状和获取有关应用程序图形环境的信息的方法。 在大多数情况下,此方法实际接收的对象将是java.awt.Graphics2D (Graphics子类)的实例,它为复杂的2D图形渲染提供支持。

大多数标准的Swing组件的外观都由单独的“ UI Delegate”对象实现。 super.paintComponent(g)的调用将图形上下文传递给组件的UI委托,该UI委托绘制了面板的背景。

为了使自定义绘画尽可能高效,我们将跟踪X坐标 (在本例中为moveXBy变量),仅重绘屏幕上已更改的区域。 这是推荐的最佳实践,它将使您的应用程序尽可能高效地运行。

repaint方法的调用。 此方法由java.awt.Component定义,并且是一种允许您以编程方式重新绘制任何给定组件的表面的机制。 它具有无参数版本(重新绘制整个组件)和多参数版本(仅重新绘制指定的区域。)此区域也称为剪辑。 调用多参数版本的重新绘制会花费一些额外的精力,但是可以确保您的绘制代码不会浪费循环重新绘制未更改的屏幕区域。

因为我们是手动设置剪辑,所以我们的setState方法不会一次调用repaint方法,而是两次。 第一次调用告诉Swing重新绘制以前椭圆形的组件区域(继承的行为使用UI委托以当前背景色填充该区域。)第二次调用绘制当前椭圆形的组件区域。 。 值得注意的重要一点是,尽管我们在同一事件处理程序中连续两次调用了repaint ,但是Swing足够聪明,可以通过一次绘制操作获取该信息并重新绘制屏幕的这些部分。 换句话说, Swing不会连续两次重涂组件,即使这似乎是代码正在做的事情。

执行“自定义绘画”时进一步参考该主题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM