【问题标题】:Graphics2D setfont() heavily slows down the start up of java applicationGraphics2D setfont() 大大减慢了 java 应用程序的启动速度
【发布时间】:2021-02-19 17:07:59
【问题描述】:

我正在用 java 制作一个游戏,它每秒刷新 60 次。每次它执行一个循环,我使用 g2d 来绘制图像和字符串。如果我使用g2d.setFont(new Font("Arial", Font.PLAIN, 8)); 和拉绳,一切正常,但如果我将字体设置为一些“不熟悉”的字体并做同样的事情,挥杆将在启动的第一秒显示白屏然后绘画一切正常,但显然太慢了(2 秒)。

我在 jframe 中放置了一个 jpanel 并覆盖了 jpanel 的 paint() 方法来绘制我需要的所有内容。我已经在我的代码中使用了SwingUtilities.invokeLater

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

public class Window extends JFrame{
    public Window(){
        add(new Board());
        setSize(800,600);
        setVisible(true);
    }
    public static void main(String[] args){
        new Window();
    }

    private class Board extends JPanel {
        Font font = new Font("Bitmap", Font.PLAIN, 64);

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D)g;
            g2d.setFont(font);
            g2d.drawString("This is slow", 220,200);
            Toolkit.getDefaultToolkit().sync();
            g2d.dispose();
            g.dispose();
        }
    }
}

这不是循环,但它非常滞后。

http://fontsov.com/download-fonts/bitmap1159.html

这是让我们的应用程序变慢的可爱字体。 “Arial”的加载速度非常快。我怎样才能减少这种延迟?

【问题讨论】:

  • 在不设置new Font 的情况下尝试一下。将字体缓存为类成员,并使用 that 字体。看看有没有不同的结果。除此之外,请发布MCVE 供我们测试
  • 你用了多少个setfonts?
  • 谢谢你的意思是我在课堂上首先这样做 Font font = new Font("Bitmap", Font.PLAIN, 64);?和 g2d.setFont(字体);在paint() 方法中?我试过了,它不起作用......:(
  • 现在看我评论的最后一点,以及气垫船回答的第一点
  • 只有一次和拉绳,它很慢....:(将“位图字体”更改为 Arial,它的速度非常快

标签: java swing fonts java-2d


【解决方案1】:

首先,为了获得最佳帮助,请创建并发布您的 minimal code example program 以供我们审查、测试并可能修复。没有这个,我们将很难完全理解您的问题。

考虑:

  • 覆盖 paintComponent 而不是 paint 以获得双缓冲的优势。
  • 避免使用invokeLater,除非您确定代码是从 Swing 事件线程中调用的,并且您正在执行需要在事件线程上的调用。
  • 将运行缓慢的代码放在后台线程中,例如可以使用 SwingWorker 找到的代码。
  • 将文本放在 JLabel 中,而不是在组件上绘制。
  • 将所有静态图像绘制到 BufferedImage 中,并在 paintComponent 中显示。然后直接在paintComponent 方法中绘制所有变化的图像,例如移动的精灵。
  • 不要忘记在您的 paintComponent(Graphics g) 方法覆盖中调用您的 super.paintCompmonent(g)

编辑
BufferedImage 解决方案可能看起来像......

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class FooFun {

   private static void createAndShowGui() {
      ChildClass mainPanel = new ChildClass();

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

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

abstract class FirstClass extends JPanel {

   private static final int FPS = 20;

   public FirstClass() {
      new Timer(1000 / FPS, taskPerformer).start();
   }

   ActionListener taskPerformer = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
          gameLoop(); //do loop here
          repaint();
      }
  };

  private void gameLoop() {

  }

  @Override
protected void paintComponent(Graphics g) {
   super.paintComponent(g);
   Graphics2D g2d = (Graphics2D)g;
   paintGame(g2d);
   // Toolkit.getDefaultToolkit().sync();
   // g2d.dispose();
   // g.dispose();
}

  public abstract void paintGame(Graphics2D g2d);
}

class ChildClass extends FirstClass {
   private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
   private static final int PREF_W = 900;
   private static final int PREF_H = 600;
   private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
   private static final int NIV_X = 240;
   private static final int NIV_Y = 130;
   private BufferedImage mainImage;

   public ChildClass() {
      mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = mainImage.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
      g2.setFont(font);
      g2.setColor(Color.black);
      g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y); 
      g2.dispose();
   }


   @Override
   public void paintGame(Graphics2D g2d) {
      if (mainImage != null) {
         g2d.drawImage(mainImage, 0, 0, this);     
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

}

编辑 2
或者使用 SwingWorker 后台线程......

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

public class FooFun {

   private static void createAndShowGui() {
      ChildClass mainPanel = new ChildClass();

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

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

abstract class FirstClass extends JPanel {

   private static final int FPS = 20;

   public FirstClass() {
      new Timer(1000 / FPS, taskPerformer).start();
   }

   ActionListener taskPerformer = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
         gameLoop(); // do loop here
         repaint();
      }
   };

   private void gameLoop() {

   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2d = (Graphics2D) g;
      paintGame(g2d);
   }

   public abstract void paintGame(Graphics2D g2d);
}

class ChildClass extends FirstClass {
   private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
   private static final int PREF_W = 900;
   private static final int PREF_H = 600;
   private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
   private static final int NIV_X = 240;
   private static final int NIV_Y = 130;
   private BufferedImage mainImage;

   public ChildClass() {
      imgWorker.addPropertyChangeListener(new ImgWorkerListener());
      imgWorker.execute();
   }

   private class ImgWorkerListener implements PropertyChangeListener {

      @Override
      public void propertyChange(PropertyChangeEvent pcEvt) {
         if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
            try {
               mainImage = imgWorker.get();
               // repaint() here if you don't have a game loop running
            } catch (InterruptedException | ExecutionException e) {
               e.printStackTrace();
            }
         }
      }
   }

   SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {

      @Override
      protected BufferedImage doInBackground() throws Exception {
         BufferedImage img = new BufferedImage(PREF_W, PREF_H,
               BufferedImage.TYPE_INT_ARGB);
         Graphics2D g2 = img.createGraphics();
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
         g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
               RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
         g2.setFont(font);
         g2.setColor(Color.black);
         g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
         g2.dispose();
         return img;
      }
   };

   @Override
   public void paintGame(Graphics2D g2d) {
      if (mainImage != null) {
         g2d.drawImage(mainImage, 0, 0, this);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

}

【讨论】:

  • @TonyStark:第二个版本将快速显示窗口,但不会显示文本,直到创建图像。 BufferedImage 的优点是它不会减慢您的动画速度。
  • 如果我不接受你的回答,我会泪流满面,非常感谢你的帮助......!不过,我的意思是,也许我一开始就不应该使用那种字体,因为 java 太奇怪了。毕竟这些方法都很慢......
【解决方案2】:

每次调用paint() 时创建一个新字体有点不经济(这种情况经常发生),您可以将其移至您的构造函数。 并且字体要改成一些正统字体(Arial、Calibri等)

【讨论】:

    猜你喜欢
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多