简体   繁体   English

Java Jpanel油漆

[英]Java Jpanel paint

I have this example of a java jpanel: 我有一个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 . 因此,我们仅定义方法paint ,然后创建新的JavaGame对象,并且仅调用paint I don't get two things: 我没有两件事:

  1. new JavaGame() - shouldn't we assign a object name like obj = new JavaGame()? new JavaGame()-我们是否应该分配一个对象名称,例如obj = new JavaGame()?
  2. Shouldn't we call the method paint like obj.paint()? 我们不应该像obj.paint()那样调用paint方法吗?

I have basic understanding of OOP, but this piece of code confuses me. 我对OOP有基本的了解,但是这段代码使我感到困惑。 Could someone please explain it to me? 有人可以给我解释一下吗?

new JavaGame() - shouldn't we assign a object name like obj = new JavaGame()? new JavaGame()-我们是否应该分配一个对象名称,例如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() . 这里最重要的是创建一个JavaGame对象,您可以通过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. 由于此对象在其构造函数中显示JFrame,因此只需创建对象即可创建显示,而无需将对象分配给任何变量。

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变量:

Foo bar = new Foo();

But then assigned the same object to a baz variable: 但是然后将相同的对象分配给baz变量:

Foo baz = bar;

Both bar and baz refer to the exact same Foo object. bar和baz均指完全相同的Foo对象。 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()? 我们不应该像obj.paint()那样调用paint方法吗?

As noted by MightyPork (1+ to him), the paint method is called by the JVM , and should not be directly called by you. 正如MightyPork(对他而言为1+)所指出的那样,paint方法是由JVM调用 ,不应由您直接调用。 You can suggest that it be called by calling repaint() , but you should almost never call it, or the paintComponent(...) method, directly. 您可以建议通过调用repaint()调用它,但几乎永远不要直接调用它,也不要直接调用paintComponent(...)方法。


Other issues: 其他事宜:

  • When painting in Swing, don't forget to call the super paint method within your own override. 在Swing中绘画时,请不要忘记在自己的替代中调用super paint方法。 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. 通常,您将希望直接在JFrame中绘制,因为JFrame负责许多关键组件,并且如果您弄乱了某些内容,则可能会弄乱GUI。
  • Much better would be to draw in a JPanel's paintComponent method, and then display that JPanel within your JFrame. 更好的方法是绘制一个JPanel的paintComponent方法,然后在JFrame中显示该JPanel。
  • 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? 因此,当使用API​​时,我们只需在代码中“填充”类中的方法,JVM就会知道何时调用这些方法?

Most often Swing graphics is "passive". 大多数情况下,Swing图形是“被动的”。 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. 而是由JVM(Java虚拟机-运行Java程序的代码)为您绘制图形。 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. 如果要制作动画,通常会更改一些位置变量,例如xPosition和yPosition int变量,然后在JPanel的paintComponent(Graphics g)方法中使用这些变量。 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. 因此,如果您在Swing计时器中更改了这些变量所保存的值,然后在值更改后调用repaint() ,JVM将(通常)使用新值来重新绘制您的组件。


A more complex example that shows drawing in a JPanel, and shows a very simple animation: 一个更复杂的示例,它在JPanel中显示绘图,并显示一个非常简单的动画:

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();
         }
      });
   }
}

You create the object new JavaGame() without assigning it to any variable, and that's it. 您创建对象new JavaGame()而不将其分配给任何变量,仅此而已。

Swing render and event threads kick in and take care of the rest of the app's life. Swing渲染和事件线程开始运行,并照顾了应用程序的剩余生命。

I'm not sure why the Garbage Collector doesn't pick it up and end it, but I've done it this way for a long time and it works fine. 我不确定垃圾收集器为什么不捡起并结束它,但是我已经用这种方式做了很长时间了,并且效果很好。

  1. You don't need an object name. 您不需要对象名称。 When you use new , the constructor will be called, which creates the frame. 当您使用new ,将调用构造函数,从而创建框架。
  2. Paint gets called whenever it needs to be. Paint会在需要时被调用。 Check out this answer . 看看这个答案

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

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