用 Swing Java 绘画 [英] Paint with Swing Java

查看:78
本文介绍了用 Swing Java 绘画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先大家好!

我遇到了一个大问题:我需要构建一个程序,该程序包括构建一个包含 5 个方块和一个按钮的 java swing 界面.按钮功能是在正方形内画一个圆.我有这个代码,但我不知道如何继续.

I'm having a big problem with this: i need to build a program which consist in building a java swing interface that contains 5 squares, and one button. The button function is to draw a circle inside the squares. I have this code, but i dont know how to continue.

框架类:

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° 位置我想要一个红色圆圈在里面,怎么办我做吗?(请记住,当我单击下一步"按钮时会出现圆圈.

非常感谢大家!

推荐答案

有些事情是你做的不正确.

THere are some thingies, that you not doing in the right sense.

  1. 首先,在实际添加所有组件之前,将 JFrame 的可见属性设置为可见,并使其实现其大小.
  2. 其次,您使用了 Absolute Layout,在大多数情况下应该避免使用这种布局.
  3. 第三,您显式创建一个 Graphics 对象,应该避免使用 Java 的 paintComponent ( ... ) 方法默认提供的对象
  1. Firstly, you setting the visible property of the JFrame to visible much before you actually added all components to it, and make it realize its size.
  2. Secondly, you using an Absolute Layout, which one should avoid in most of the situations.
  3. Thirdly, you creating a Graphics object explicitly, which one should avoid and instead use the one provided by Java's paintComponent ( ... ) method by default

看看这个例子:

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 中的并发.这将防止可能导致死锁的潜在竞争条件.

All Graphical User Interfaces require some kind of main application frame in which to display. In Swing, this is an instance of javax.swing.JFrame. Therefore, our first step is to instantiate this class and make sure that everything works as expected. Note that when programming in Swing, your GUI creation code should be placed on the Event Dispatch Thread (EDT), more info on Concurrency in Swing. This will prevent potential race conditions that could lead to deadlock.

DrawingBoard 还覆盖 getPreferredSize,返回期望的面板宽度和高度(在本例中 400width300> 是高度.)因此,DrawingCircleExample 类不再需要以像素为单位指定框架的大小.它只是将面板添加到框架中,然后调用包.

DrawingBoard also overrides getPreferredSize, which returns the desired width and height of the panel (in this case 400 is the width, 300 is the height.) Because of this, the DrawingCircleExample class no longer needs to specify the size of the frame in pixels. It simply adds the panel to the frame and then invokes pack.

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

The paintComponent method is where all of your custom painting takes place. This method is defined by javax.swing.JComponent and then overridden by your subclasses to provide their custom behavior. Its sole parameter, a java.awt.Graphics object, exposes a number of methods for drawing 2D shapes and obtaining information about the application's graphics environment. In most cases the object that is actually received by this method will be an instance of java.awt.Graphics2D (a Graphics subclass), which provides support for sophisticated 2D graphics rendering.

大多数标准 Swing 组件的外观和感觉由单独的UI 委托"对象实现.super.paintComponent(g) 的调用将图形上下文传递给组件的 UI 委托,后者绘制面板的背景.

Most of the standard Swing components have their look and feel implemented by separate "UI Delegate" objects. The invocation of super.paintComponent(g) passes the graphics context off to the component's UI delegate, which paints the panel's background.

为了使我们的自定义绘画尽可能高效,我们将跟踪 X 坐标(在我们的例子中为 moveXBy 变量)并仅重新绘制屏幕上具有改变了.这是推荐的最佳做法,可让您的应用程序尽可能高效地运行.

To keep our custom painting as efficient as possible, we will track the X coordinates ( moveXBy variable in our case ) and repaint only the areas of the screen that have changed. This is a recommended best practice that will keep your application running as efficiently as possible.

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

The invocation of the repaint method. This method is defined by java.awt.Component and is the mechanism that allows you to programatically repaint the surface of any given component. It has a no-arg version (which repaints the entire component) and a multi-arg version (which repaints only the specified area.) This area is also known as the clip. Invoking the multi-arg version of repaint takes a little extra effort, but guarantees that your painting code will not waste cycles repainting areas of the screen that have not changed.

因为我们手动设置剪辑,我们的 setState 方法调用 repaint 方法不是一次,而是两次.第一次调用告诉 Swing 重新绘制以前椭圆所在的组件区域(继承行为使用 UI 委托用当前背景颜色填充该区域.)第二次调用绘制椭圆当前所在的组件区域.值得注意的一点是,尽管我们在同一个事件处理程序中连续调用了两次 repaintSwing 足够聪明,可以获取该信息并重新绘制在一次绘画操作中筛选所有内容.换句话说,Swing 不会连续两次重绘组件,即使代码看起来就是这样做的.

Because we are manually setting the clip, our setState method invokes the repaint method not once, but twice. The first invocation tells Swing to repaint the area of the component where the oval previously was (the inherited behavior uses the UI Delegate to fill that area with the current background color.) The second invocation paints the area of the component where the oval currently is. An important point worth noting is that although we have invoked repaint twice in a row in the same event handler, Swing is smart enough to take that information and repaint those sections of the screen all in one single paint operation. In other words, Swing will not repaint the component twice in a row, even if that is what the code appears to be doing.

执行自定义绘画

这篇关于用 Swing Java 绘画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆