Использование paintComponent () и высокая загрузка ЦП - PullRequest
0 голосов
/ 05 июня 2019

Я пытаюсь создать забавную игру, в которую входит Колесо, мяч. Каждый раз, когда пользователь нажимает на кнопку, шар катится и случайным образом приземляется на один слот в колесе. Все в порядке, чтобы создать Колесо, я помещаю изображение и шар (Овальный объект) на отдельном JPanel. Функциональное поведение хорошо, как я ожидаю. Однако каждый раз, когда я запускаю программу, процессор звучит громко, и использование Java-приложения часто занимает до 25%.

Это довольно ужасно. Через некоторое время, выполняя некоторые тесты, кажется, что ошибка находится внутри моих painComponent() переопределенных методов, поскольку Java неоднократно вызывает этот метод без остановки. Более подробное исследование показывает, что проблема заключается в методе getScaledInstance, который используется для масштабирования изображения внутри панели. Мне кажется, что если я удалю этот метод, paintComponent() не будет вызываться повторно.

Однако, я не знаю, как сделать масштабированное изображение без getScaledInstance. Обратите внимание, что я попытался сделать копию на основе образца MadProgrammer Java: поддержание соотношения сторон фонового изображения JPanel

Итак, что вы думаете об этом? Есть ли способ установить фоновое изображение, сохранить соотношение сторон и не вызывать метод paintComponent()? Обратите внимание, что я пытался использовать Thread.sleep, но он работает не очень хорошо.

Это довольно сложно для меня. В любом случае, спасибо за чтение!

public class WheelPanel2 extends JPanel {

    private BufferedImage image;
    private int time = 0;
    private Image scaled = null;
    private int scaleWidth = 300;
    private int scaleHeight = 300;

    public WheelPanel2() {
        try {
            image = ImageIO.read(new File("img/Basic_roulette_wheel_1024x1024.png"));
            scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);

        } catch (IOException e) {
            e.printStackTrace();
        }
        setSize(400, 400);
        setPreferredSize(new Dimension(400, 400));
        setBorder(BorderFactory.createLineBorder(Color.BLACK));


        double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));
        int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
        int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);
        Image scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);

    }

    /**
     * The Paint Method - Create the image of the Wheel and the Ball
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));

        //TRUE WIDTH AND HEIGHT
        int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
        int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);
        scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);
        int width = getWidth() - 1;
        int height = getHeight() - 1;
        int x = (width - scaled.getWidth(this)) / 2;
        int y = (height - scaled.getHeight(this)) / 2;

        g.drawImage(scaled, x, y, this);
        System.out.println("PAINT");

    }



    /**
     * These two methods are used to automatically resize the wheelpanel and the ball
     */
    private double getScaleFactorToFit(Dimension original, Dimension toFit) {

        double dScale = 1d;

        if (original != null && toFit != null) {

            double dScaleWidth = getScaleFactor(original.width, toFit.width);
            double dScaleHeight = getScaleFactor(original.height, toFit.height);

            dScale = Math.min(dScaleHeight, dScaleWidth);

        }

        return dScale;
    }

    private double getScaleFactor(int iMasterSize, int iTargetSize) {

        double dScale;
        if (iMasterSize > iTargetSize) {

            dScale = (double) iTargetSize / (double) iMasterSize;

        } else {

            dScale = (double) iTargetSize / (double) iMasterSize;

        }

        return dScale;

    }
    public static void main (String[] args) {
        JFrame frame = new JFrame("HI THERE");
        frame.setSize(1000, 1000);
        frame.setLayout(new BorderLayout());
        frame.add(new WheelPanel2(), BorderLayout.CENTER);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(1);

    }
}

Если вы попытаетесь запустить программу, вы узнаете, что paintComponent вызывается без остановок.

Ответы [ 2 ]

2 голосов
/ 05 июня 2019

Вместо того, чтобы масштабировать изображение самостоятельно, позвольте Graphics сделать это, вызвав метод drawImage, который принимает аргументы ширины и высоты :

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    int width = image.getWidth(this);
    int height = image.getHeight(this);
    float scale = Math.min(
        (float) getWidth() / width,
        (float) getHeight() / height);

    width = (int) (width * scale);
    height = (int) (height * scale);

    int x = (getWidth() - width) / 2;
    int y = (getHeight() - height) / 2;

    g.drawImage(image, x, y, width, height, this);
}

На большинстве платформ это займетПреимущество графического ускорения системы для масштабирования изображения.

Если вы хотите быть уверены, что для масштабирования изображения используется эквивалент SCALE_SMOOTH, установите соответствующий RenderingHint :

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    ((Graphics2D) g).setRenderingHint(
        RenderingHints.KEY_INTERPOLATION,
        RenderingHints.VALUE_INTERPOLATION_BICUBIC);

    int width = image.getWidth(this);
    int height = image.getHeight(this);
    float scale = Math.min(
        (float) getWidth() / width,
        (float) getHeight() / height);

    width = (int) (width * scale);
    height = (int) (height * scale);

    int x = (getWidth() - width) / 2;
    int y = (getHeight() - height) / 2;

    g.drawImage(image, x, y, width, height, this);
}
0 голосов
/ 05 июня 2019

Привет, я не очень разбираюсь в колебаниях, но можете ли вы попытаться вызвать getScaledInstance только один раз в конструкторе и там создать Image scaled?

 //part of the class properties
private Image scaled = null;
//other properties

public WheelPanel() {
    this.this_class = this;
    try {
        image = ImageIO.read(new File("img/Basic_roulette_wheel_1024x1024.png"));
        //Create only one scaled image and after that use it in paintComponent method
        scaled = image.getScaledInstance(scaleWidth, scaleHeight,  Image.SCALE_SMOOTH);
    } catch (IOException e) {
        e.printStackTrace();
    }
    setSize(400, 400);
    setPreferredSize(new Dimension(400, 400));
    setBorder(BorderFactory.createLineBorder(Color.BLACK));      
}

Если это по какой-то причинене работает, вы можете попытаться создать Image scaled только один метод внутри paintComponent.Пример:

//part of the class properties
private Image scaled = null;
/**
* The Paint Method - Create the image of the Wheel and the Ball
*/
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));
    int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
    int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);
    if(scaled == null)
    {
        scaled = image.getScaledInstance(scaleWidth, scaleHeight,  Image.SCALE_SMOOTH);
    }

    int width = getWidth() - 1;
    int height = getHeight() - 1;
    int x = (width - scaled.getWidth(this)) / 2;
    int y = (height - scaled.getHeight(this)) / 2;
   g.drawImage(scaled, x, y, this_class);

 }

Редактировать: я видел, как вы изменили пример с помощью конструктора.Пожалуйста, попробуйте этот конструктор:

//part of the class properties
private Image scaled = null;


public WheelPanel2() {
    try {
        image = ImageIO.read(new File("img/Basic_roulette_wheel_1024x1024.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    setSize(400, 400);
    setPreferredSize(new Dimension(400, 400));
    setBorder(BorderFactory.createLineBorder(Color.BLACK));


    double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));
    int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
    int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);
    scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);

}

Удачи всем!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...