用Swing Java绘画

时间:2015-04-12 02:36:34

标签: java paint paintcomponent repaint jlayeredpane

首先,大家好!

我遇到了一个很大的问题:我需要构建一个程序,它包含构建一个包含5个方块和一个按钮的java swing接口。按钮功能是在方块内画一个圆圈。我有这个代码,但我不知道如何继续。

Frame类:

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°的位置,我想在它们里面有一个红色圆圈,怎么能我做到了吗? (请记住,当我点击“下一步”按钮时,会出现圆圈。

非常感谢大家!

2 个答案:

答案 0 :(得分:3)

//Graphics g = this.getGraphics();

不要使用getGraphics()来绘画。这幅画只是暂时的,当组件重新粉刷时会丢失。

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

这样做的一种方法是保持要绘制的List个对象。然后在paintComponent()方法中迭代List并绘制对象。

因此,您可以使用以下代码创建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 :(得分:1)

这些是一些东西,你没有做正确的意义。

  1. 首先,在实际添加所有组件之前,将JFrame的可见属性设置为可见,并使其实现其大小。
  2. 其次,您使用Absolute Layout,在大多数情况下应该避免使用{<1}}。
  3. 第三,你明确地创建了一个Graphics对象,哪一个应该避免,而是默认使用Java paintComponent ( ... )方法提供的那个
  4. 看一下这个例子:

    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)上,有关Concurrency in 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委托,该委托绘制了面板的背景。

    为了使我们的自定义绘画尽可能高效,我们将跟踪 X坐标(在我们的案例中为moveXBy变量)并仅重新绘制已更改的屏幕区域。建议的最佳做法是尽可能高效地运行应用程序。

    调用repaint方法。此方法由java.awt.Component定义,并且是允许您以编程方式重绘任何给定组件的表面的机制。它有一个无参数版本(重新绘制整个组件)和一个多参数版本(仅重新绘制指定区域。)此区域也称为剪辑。调用multi-arg版本的repaint需要花费一些额外的精力,但保证你的绘画代码不会浪费周期重新绘制屏幕上没有改变的区域。

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

    请参阅performing Custom Painting

    上的主题