Java Jpanel 油漆 [英] Java Jpanel paint

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

问题描述

我有一个 java jpanel 的例子:

import java.awt.*;导入 javax.swing.*;公共类 JavaGame 扩展了 JFrame {公共 JavaGame() {setTitle("游戏");设置大小(500,500);setResizable(false);设置可见(真);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}公共无效油漆(图形g){g.drawString("Hello World!",75,75);}公共静态无效主(字符串 [] args){新的 JavaGame();}}

所以,我们只需定义方法paint,然后创建新的JavaGame 对象,它只调用paint.我不明白两件事:

<块引用>

  1. new JavaGame() - 我们不应该分配一个像 obj = new JavaGame() 这样的对象名称吗?
  2. 我们不应该像 obj.paint() 一样调用方法paint吗?

我对OOP有基本的了解,但是这段代码让我很困惑.有人可以给我解释一下吗?

解决方案

new JavaGame() - 我们不应该分配一个像 obj = new JavaGame() 这样的对象名称吗?

这就是对象和引用变量之间的重要区别.这里最重要的是创建一个 JavaGame 对象,您可以通过 new JavaGame() 来完成.由于此对象在其构造函数中显示 JFrame,因此只需创建该对象即可创建显示,您无需将该对象分配给任何变量.

请注意,对象没有名称,但某些变量有.例如,如果您创建了一个 Foo 对象,并将其分配给一个 bar 变量:

Foo bar = new Foo();

但随后将相同的对象分配给了 baz 变量:

Foo baz = bar;

bar 和 baz 都指向完全相同的 Foo 对象.那么对象的名称是什么?同样,对象名称不存在且毫无意义.

<小时><块引用>

我们不应该像obj.paint()一样调用paint方法吗?

正如 MightyPork 所指出的(对他来说是 1+),paint 方法被JVM 调用,不应由您直接调用.您可以建议通过调用 repaint() 来调用它,但您几乎不应该直接调用它,或者直接调用 paintComponent(...) 方法.

<小时>

其他问题:

  • 在 Swing 中绘画时,不要忘记在您自己的覆盖中调用超级绘画方法.否则,组件将不会自己进行内务绘制,并且您将破坏绘制链,这意味着被绘制的容器所持有的组件可能无法正确绘制或根本无法绘制.
  • 一般来说,您希望不想直接在 JFrame 中绘图,因为 JFrame 负责许多关键组件,如果您搞砸了某些东西,GUI 可能会搞砸.
  • 最好在 JPanel 的 paintComponent 方法中绘制,然后在 JFrame 中显示该 JPanel.
  • 查看教程以了解所有血腥但非常重要的细节:
<小时>

编辑你问:

<块引用>

那么,在使用 API 时,我们只需用代码填充"类中的方法,JVM 就会知道何时调用这些方法?

Swing 图形通常是被动的".这意味着您将组件设置为以某种方式绘制,但您不会自己主动绘制它.而是 JVM(Java 虚拟机——运行 Java 程序的代码)为您进行绘图.如果你想做动画,通常你会改变一些位置变量,例如 xPosition 和 yPosition int 变量,然后在你的 JPanel 的 paintComponent(Graphics g) 方法中使用这些变量.因此,如果您在 Swing Timer 中更改这些变量保存的值,然后在值更改后调用 repaint(),JVM 将(通常)使用新值重新绘制您的组件.

<小时>

一个更复杂的例子,在 JPanel 中显示绘图,并显示一个非常简单的动画:

import java.awt.Color;导入 java.awt.Dimension;导入 java.awt.Graphics;导入 java.awt.Graphics2D;导入 java.awt.RenderingHints;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 javax.swing.*;//在 JPanel 中绘制,而不是 JFrame公共类 SimpleAnimation 扩展 JPanel {私有静态最终 int OVAL_WIDTH = 40;私有静态最终 int TIMER_DELAY = 50;私有静态最终 int PREF_W = 800;private static final int PREF_H = PREF_W;私人整数 xPosition = 0;私有整数 yPosition = 0;公共简单动画(){//在这里启动我的计时器新定时器(TIMER_DELAY,新定时器监听器()).开始();}@覆盖受保护的无效paintComponent(图形g){//调用super方法使JPanel//可以先做自己的看家图super.paintComponent(g);//我这样做是为了让我的图形平滑Graphics2D g2 = (Graphics2D) g;g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);g2.setColor(Color.red);//使用 xPosition 和 yPosition 来放置我的椭圆g2.fillOval(xPosition, yPosition, OVAL_WIDTH, OVAL_WIDTH);}//这样我们的 GUI 就会大到足以看清@覆盖公共维度 getPreferredSize() {如果(isPreferredSizeSet()){返回 super.getPreferredSize();}返回新维度(PREF_W,PREF_H);}//Swing Timer 用来驱动动画的类私有类 TimerListener 实现 ActionListener {@覆盖public void actionPerformed(ActionEvent e) {//改变 xPosition 和 yPositionxPosition++;y位置++;//并调用重绘重绘();}}//要在我们的 Runnable 中调用的方法私有静态无效 createAndShowGui() {SimpleAnimation mainPanel = new SimpleAnimation();JFrame frame = new JFrame("SimpleAnimation");frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);frame.getContentPane().add(mainPanel);框架.pack();frame.setLocationByPlatform(true);frame.setVisible(true);}公共静态无效主(字符串 [] args){//这用于确保所有 Swing 代码//在 Swing 事件线程上启动.SwingUtilities.invokeLater(new Runnable() {公共无效运行(){createAndShowGui();}});}}

I have this example of a java jpanel:

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

    public class JavaGame extends JFrame {

    public JavaGame() {
    setTitle("Game");
    setSize(500,500);
    setResizable(false);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void paint(Graphics g) {
    g.drawString("Hello World!",75,75);
    }

    public static void main(String[] args) {

    new JavaGame();

    }

    }

So, we just define the method paint, and we create new JavaGame object, and it just calls paint. I don't get two things:

  1. new JavaGame() - shouldn't we assign a object name like obj = new JavaGame()?
  2. Shouldn't we call the method paint like obj.paint()?

I have basic understanding of OOP, but this piece of code confuses me. Could someone please explain it to me?

解决方案

new JavaGame() - shouldn't we assign a object name like obj = new JavaGame()?

This gets to the important distinction between objects and reference variables. What is most important here is creating a JavaGame object, which you do by new JavaGame(). Since this object displays the JFrame in its constructor, then simply creating the object is all that is needed to create the display, and you don't need to assign the object to any variable.

Note that objects don't have names, but rather, some variables do. For instance, if you created a Foo object, and assigned it to a bar variable:

Foo bar = new Foo();

But then assigned the same object to a baz variable:

Foo baz = bar;

Both bar and baz refer to the exact same Foo object. What then is the object's name? Again, object names don't exist and are meaningless.


Shouldn't we call the method paint like obj.paint()?

As noted by MightyPork (1+ to him), the paint method is called by the JVM, and should not be directly called by you. You can suggest that it be called by calling repaint(), but you should almost never call it, or the paintComponent(...) method, directly.


Other issues:

  • When painting in Swing, don't forget to call the super paint method within your own override. Otherwise the component will not do its own house-keeping painting, and you will break the painting chain, meaning components held by the painted container might not be painted correctly or at all.
  • In general, you will want to not want to draw directly within a JFrame, since a JFrame is responsible for many key components, and if you messed something up, the GUI could be messed up.
  • Much better would be to draw in a JPanel's paintComponent method, and then display that JPanel within your JFrame.
  • Check out the tutorials for all the gory but very important details:

Edit You ask:

So, when use API, we just "fill" with code the methods in the class, and the JVM will know when to call these methods?

Most often Swing graphics is "passive". Meaning you set your component up to be drawn a certain way, but you don't actively draw it yourself. Rather the JVM (the Java Virtual Machine -- the code that runs your Java program) does the drawing for you. If you want to do animation, often you'll change some positional variables, for instance xPosition and yPosition int variables, and then use those variables within your JPanel's paintComponent(Graphics g) method. So if you change the values held by these variables within a Swing Timer, and then call repaint() after the values have changed, the JVM will (usually) repaint your component, using the new values.


A more complex example that shows drawing in a JPanel, and shows a very simple animation:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

// draw in a JPanel, not a JFrame
public class SimpleAnimation extends JPanel {
   private static final int OVAL_WIDTH = 40;
   private static final int TIMER_DELAY = 50;
   private static final int PREF_W = 800;
   private static final int PREF_H = PREF_W;
   private int xPosition = 0;
   private int yPosition = 0;

   public SimpleAnimation() {
      // start my timer here
      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      // call the super method so that the JPanel
      // can do its own house-keeping graphics first
      super.paintComponent(g);

      // I do this to so that my graphics are smooth 
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(Color.red);

      // use xPosition and yPosition to place my oval
      g2.fillOval(xPosition, yPosition, OVAL_WIDTH, OVAL_WIDTH);
   }

   // so our GUI will be big enough to see
   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   // class used by the Swing Timer to drive animation
   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         // change xPosition and yPosition
         xPosition++;
         yPosition++;

         // and call repaint
         repaint();
      }
   }

   // a method to be called in our Runnable
   private static void createAndShowGui() {
      SimpleAnimation mainPanel = new SimpleAnimation();

      JFrame frame = new JFrame("SimpleAnimation");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      // this is used to make sure that all Swing code
      // is started on the Swing event thread.
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

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

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