Nano Hash - криптовалюты, майнинг, программирование

NullPointerException для графики Java

Я пытаюсь реализовать метод рисования определенной части сетки. Для этого я переопределил метод paintComponent:

public class Frame extends JPanel {
...
@Override
public void paintComponent( Graphics g ) {

    super.paintComponent( g );

    g.clearRect(0, 0, getWidth(), getHeight());
    this.rectWidth = getWidth() / this.NUM_COLUMNS;
    this.rectHeight = getHeight() / this.NUM_ROWS;

    for (int i = 0; i < NUM_ROWS; i++) {

        for (int j = 0; j < NUM_COLUMNS; j++) {

            int x = i * this.rectWidth;
            int y = j * this.rectHeight;
            g.setColor( Color.WHITE );
            g.fillRect( x, y, this.rectWidth, this.rectHeight );

        }
    }

}
}

Это хорошо, но затем я хочу нарисовать определенные части вызова функции следующим образом:

public void specificPaint( int coordinateX, int coordinateY, Color color ){

    Graphics g = this.getGraphics();

    int x = coordinateX * this.rectWidth;
    int y = coordinateY * this.rectHeight;

    g.setColor( color );
    g.fillRect( x, y, this.rectWidth, this.rectWidth);

}

Звонок должен быть таким

// TESTING
    this.modelMap.specificPaint( 40,40,Color.RED );
    this.modelMap.specificPaint( 10,10,Color.RED );
    this.modelMap.specificPaint( 20,25,Color.BLUE );

Я получаю ошибку нулевого указателя с объектом Graphics, почему я не могу восстановить и использовать его?

Есть ли лучший подход?

09.11.2015

  • См. редактирование, чтобы ответить с образцом кода. 09.11.2015

Ответы:


1

Никогда не делайте этого при получении объекта Graphics из компонента:

Graphics g = this.getGraphics();

Полученный таким образом объект Graphics не будет долговечным, и это может привести либо к NPE (как вы получаете), либо к изображению, которое не сохраняется при перерисовке. Вместо этого рисуйте в методе paintComponent. Обратите внимание, что вы можете вызвать repaint(...) и указать конкретный прямоугольник для рисования, передав параметр Rectangle.

Обратите внимание, что вы можете вызвать getGraphics() для BufferedImage и нарисовать его, а затем нарисовать BufferedImage в вашем методе paintComponent, если вы хотите сделать точечное рисование, которое не движется.

Не связанная с этим рекомендация: избегайте называть свой класс Frame, так как это может привести к конфликту имен с классом java.awt.Frame, если вы не будете осторожны.

Например:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyPanel extends JPanel {
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private int cols;
    private int rows;
    private static final Color BG = Color.BLACK;
    private static final int GAP = 1;
    private BufferedImage img;
    private int rectWidth;
    private int rectHeight;

    public MyPanel(int rows, int cols) {
        this.cols = cols;
        this.rows = rows;
        img = createMyImage();
    }

    public void specificPaint(int coordinateX, int coordinateY, Color color) {
        Graphics g = img.getGraphics(); // get img's Graphics object
        int x = coordinateX * this.rectWidth + GAP;
        int y = coordinateY * this.rectHeight + GAP;
        g.setColor(color);
        g.fillRect(x, y, rectWidth - 2 * GAP, rectWidth - 2 * GAP);
        g.dispose();
        repaint();
    }

    private BufferedImage createMyImage() {
        img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setBackground(BG);
        g2.clearRect(0, 0, img.getWidth(), img.getHeight());
        this.rectWidth = img.getWidth() / cols;
        this.rectHeight = img.getHeight() / rows;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                int x = i * this.rectWidth + GAP;
                int y = j * this.rectHeight + GAP;
                g2.setColor(Color.WHITE);
                g2.fillRect(x, y, this.rectWidth - 2 * GAP, this.rectHeight - 2 * GAP);
            }
        }
        g2.dispose();
        return img;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            g.drawImage(img, 0, 0, this);
        }

        // if you need to draw changing non-static images, do it here
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || img == null) {
            return super.getPreferredSize();
        }
        int w = img.getWidth();
        int h = img.getHeight();
        return new Dimension(w, h);
    }

    private static void createAndShowGui() {
        MyPanel modelMap = new MyPanel(50, 50);
        JFrame frame = new JFrame("MyPanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(modelMap);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        modelMap.specificPaint( 40,40,Color.RED );
        modelMap.specificPaint( 10,10,Color.RED );
        modelMap.specificPaint( 20,25,Color.BLUE );
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}
09.11.2015
  • Я не уверен, что создание BufferedImage здесь полностью необходимо, когда прямоугольник цвета можно просто нарисовать с помощью правильного объекта Graphics. 09.11.2015
  • @phflack: в этом нет необходимости, но если это неизменяющееся фоновое изображение, вам лучше использовать BufferedImage, так как это может улучшить время отклика графики. 09.11.2015

  • 2

    Изменять

    public void specificPaint(int coordinateX, int coordinateY, Color color)
    

    to

    public void specificPaint(int coordinateX, int coordinateY, Color color, Graphics g)
    

    Затем вызовите specificPaint внутри вашего метода paintComponent с объектом Graphics, который вы рисуете.

    См. Ответ Hovercraft для получения более подробной информации о том, почему использование this.getGraphics() не работает.

    09.11.2015
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..