[英]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++;
}
}
}
我有这个问题和疑问:
非常感谢大家!
//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进行绘制。 或者,如果您不清除列表,则可以添加更多的圆圈,它们都将被绘制。
这有些事情,您做得不正确。
JFrame
并使其实现大小之前,先将JFrame
的visible属性设置为visible。 Absolute Layout
,在大多数情况下都应避免使用这种Absolute Layout
。 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 ,该方法返回面板的所需宽度和高度(在这种情况下, 400
为width
, 300
为高度)。因此, 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.