Проблемы с рисованием графики на Java в JApplet

#java

#java

Вопрос:

Я надеюсь, что это не слишком похоже на вопрос новичка. Я раньше не занимался программированием в графическом стиле. Моя цель — создать рекламную игру в пинбол в апплете. Тем не менее, я сталкиваюсь с одним из первых препятствий. Мой апплет не отображает результаты метода paintComponent из моего класса Table (который расширяет JPanel). Я попробовал несколько вещей, например, как я загружаю изображение (в настоящее время использую двойную буферизацию, но раньше я использовал mediatracker), проверяя, позволит ли отсутствие каких-либо других элементов графического интерфейса отображать изображение (поскольку я задавался вопросом, не рисуется ли оно каким-то образом под ним) и другие вещи. Эта проблема поставила меня в тупик, и я начинаю задаваться вопросом (и надеяться), не упустил ли я из виду что-то маленькое, если это так, то я сожалею, но все равно был бы благодарен за помощь, поскольку я не могу далеко продвинуться, не устранив сначала эту проблему. Мой код для моего Pinball (апплета) и класса Table приведены ниже, другие классы еще не реализованы. Еще раз, я ценю любую помощь.

 import javax.swing.*; // useful for the drawing side, also going to be a JApplet
import java.awt.*;
import java.net.*;

public class Pinball extends JApplet {
    // variables go here
    Table table;

    // further initialisation of the GUI
    public void init() {
                        setSize(300, 300);
                table = new Table(this);
                add(table);
                                setContentPane(table); // makes our graphical JPanel container the content pane for the Applet
                // createGUI(); // this has been moved onto the table class
            }

    public void stop() {

    }

}
  

А теперь класс Table:

 import java.awt.*; // needed for old style graphics stuff
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*; // gives us swing stuff
import java.io.IOException;
import java.net.*; // useful for anything using URLs

public class Table extends JPanel {
// attributes go here
    Pinball pb;
    Color bgColour;
    JPanel eastPanel;
    JPanel logoPanel;
    JPanel livesPanel;
    JPanel scorePanel;
    JPanel tablePanel;
    JPanel scrollTextPanel;
        Image logo;

    // constructor goes here
public Table(Pinball pb) {
setPreferredSize(new Dimension(300, 300));
    this.pb = pb;
    // this is not needed anymore, with the new loadImage class down the bottom
//  Toolkit tk = Toolkit.getDefaultToolkit(); // needed to get images
//  logo = tk.getImage(base   "images/logo.jpg");
        logo = loadImage("logo.jpg");
     createGUI();
        }

        // public methods go here
        // all GUI creation stuff goes here
        public void createGUI() {
            /* allows the three parts (top, middle and right) 
             * to be made through (north, center and right) */
                    setLayout(new BorderLayout());
                    // setting the background colour
                    bgColour = new Color(190, 186, 221); // makes the sky blue colour for the background.
                    setBackground(bgColour);
                                                        // now putting a panel for the east side
                    eastPanel = new JPanel();
                    eastPanel.setBackground(bgColour);
                    eastPanel.setLayout(new BorderLayout(8, 8));
                    eastPanel.setPreferredSize(new Dimension(100, 280));
                                    logoPanel = new JPanel();
    logoPanel.setBackground(Color.WHITE);
    logoPanel.setPreferredSize(new Dimension(100, 100));
    logoPanel.setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, Color.white));
    //JLabel label1 = new JLabel("Logos go here");
    //logoPanel.add(label1);
    eastPanel.add(logoPanel, "North");
    livesPanel = new JPanel();
    livesPanel.setBackground(Color.WHITE);
    livesPanel.setPreferredSize(new Dimension(100, 100));
    JLabel label2 = new JLabel("Lives go here");
    livesPanel.add(label2);
    eastPanel.add(livesPanel, "Center");
    scorePanel = new JPanel();
    scorePanel.setBackground(Color.WHITE);
    scorePanel.setPreferredSize(new Dimension(100, 80));
    JLabel label3 = new JLabel("Scores go here");
    scorePanel.add(label3);
    eastPanel.add(scorePanel, "South");
add(eastPanel, "East");
    tablePanel = new JPanel();
    tablePanel.setBackground(bgColour);
    tablePanel.setPreferredSize(new Dimension(200, 280));
    add(tablePanel, "Center");
    scrollTextPanel = new JPanel();
    scrollTextPanel.setPreferredSize(new Dimension(300, 20));
    scrollTextPanel.setBackground(Color.WHITE);
    scrollTextPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    add(scrollTextPanel, "North");
    // repaint();
                        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
        g.drawImage(logo, 5, 5, 90, 90, null);
        g.drawLine(0, 0, 300, 300); // for testing, does not work
              }

        // a little useful method for handling loading of images and stuff
        public BufferedImage loadImage(String filename) {
        BufferedImage image = null;
        try {
               URL url = new URL(pb.getCodeBase(), "images/"   filename);
               image = ImageIO.read(url);
            } catch (IOException e) {
            }
    return image;
        }

}
  

Комментарии:

1. Добавление компонентов при инициализации в ваш подкласс JPanel плюс переопределение paintComponent не будут хорошо сочетаться друг с другом.

2. @justkt: они могут воспроизводиться красиво, если для свойства непрозрачности покрывающего компонента установлено значение false. Пожалуйста, смотрите мой ответ ниже.

Ответ №1:

Ваша таблица JPanel закрыта другими JPanels, что может быть нормально, но вы не сможете видеть сквозь непрозрачный компонент, который ее покрывает, в частности, tablePanel JPanel. Например, попробуйте:

   tablePanel = new JPanel();
  // tablePanel.setBackground(bgColour); //!! removed
  tablePanel.setOpaque(false); //!! added
  

И посмотрим, что произойдет.

Не связанный с этим вопрос к вам относительно этого кода здесь:

    public void init() {
      setSize(300, 300);
      table = new Table(this);
      add(table);
      setContentPane(table); // makes our graphical JPanel container the content
  

Почему вы добавляете объект table Table дважды, один раз в панель содержимого JApplet, а затем следующий как панель содержимого JApplet?

Комментарии:

1. Я был слишком медлителен в этом вопросе. 😉

2. Привет, и спасибо за быстрый ответ. К сожалению, это сработало не идеально, но это моя ошибка. Я переместил его, чтобы показать логотип на 5, 5, чтобы посмотреть, был ли это мой предыдущий набор координат (из logoPanel). Я использовал logoPanel.getX () 5 и logoPanel.getY () 5, чтобы получить координаты раньше, и не был уверен, что именно поэтому они не отображаются. Однако ваш код действительно сработал. Я начинаю задаваться вопросом, для такого графического проекта, как этот, было бы лучше использовать всю графику и никаких компонентов? Это мой первый опыт работы с графикой.

3. Привет, @Hovercraft, полный угрей, спасибо за ваш быстрый ответ. Ваш код действительно работал, но я не могу использовать его эффективно, хотя это моя ошибка. Я намеревался отобразить логотип на logoPanel, но я использовал код, в котором не был уверен, что это сработает, поэтому я попытался устранить эту проблему, переместив изображение. Код, который я использовал ранее для позиционирования, был (logo, logoPanel.getX() 5, logoPanel.getY() 5 …) и т.д. Это сработает? При необходимости я могу использовать абсолютные координаты.

4. Извините за тройной пост, я не понял, как удалять комментарии.

Ответ №2:

Запустите, затем изучите этот код и посмотрите, сможете ли вы определить источник проблемы.

 // <applet code='Pinball' width='300' height='300'></applet>
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*; // useful for the drawing side, also going to be a JApplet
import javax.imageio.ImageIO;

import java.net.*;
import java.io.IOException;

public class Pinball extends JApplet {
    // variables go here
    Table table;

    // further initialisation of the GUI
    public void init() {
        table = new Table(this);
        setContentPane(table); // makes our graphical JPanel container the content pane for the Applet
    }
}

class Table extends JPanel {
    // attributes go here
    Pinball pb;
    Color bgColour;
    JPanel eastPanel;
    JPanel logoPanel;
    JPanel livesPanel;
    JPanel scorePanel;
    JPanel tablePanel;
    JPanel scrollTextPanel;
    Image logo;

    // constructor goes here
    public Table(Pinball pb) {
        //setPreferredSize(new Dimension(300, 300));
        this.pb = pb;
        // this is not needed anymore, with the new loadImage class down the bottom
        //Toolkit tk = Toolkit.getDefaultToolkit(); // needed to get images
        //logo = tk.getImage(base   "images/logo.jpg");
        int size = 100;
        logo = //loadImage("logo.jpg");
            new BufferedImage( size,size, BufferedImage.TYPE_INT_RGB);
        Graphics g = logo.getGraphics();
        g.setColor(Color.red);
        g.fillRect(0,0,size,size);

        createGUI();
    }

    // public methods go here
    // all GUI creation stuff goes here
    public void createGUI() {
        /* allows the three parts (top, middle and right)
         * to be made through (north, center and right) */
        setLayout(new BorderLayout(20,20));
        // setting the background colour
        bgColour = new Color(190, 186, 221); // makes the sky blue colour for the background.
        setBackground(bgColour);
        // now putting a panel for the east side
        eastPanel = new JPanel();
        eastPanel.setBackground(bgColour);
        eastPanel.setLayout(new BorderLayout(8, 8));
        eastPanel.setPreferredSize(new Dimension(100, 280));
        logoPanel = new JPanel();
        logoPanel.setBackground(Color.WHITE);
        logoPanel.setPreferredSize(new Dimension(100, 100));
        logoPanel.setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, Color.green));
        eastPanel.add(logoPanel, "North");
        livesPanel = new JPanel();
        livesPanel.setBackground(Color.WHITE);
        livesPanel.setPreferredSize(new Dimension(100, 100));
        JLabel label2 = new JLabel("Lives go here");
        livesPanel.add(label2);
        eastPanel.add(livesPanel, "Center");
        scorePanel = new JPanel();
        scorePanel.setBackground(Color.WHITE);
        scorePanel.setPreferredSize(new Dimension(100, 80));
        JLabel label3 = new JLabel("Scores go here");
        scorePanel.add(label3);
        eastPanel.add(scorePanel, "South");
        add(eastPanel, "East");
        tablePanel = new JPanel();
        tablePanel.setBackground(bgColour);
        tablePanel.setPreferredSize(new Dimension(200, 280));
        add(tablePanel, "Center");
        scrollTextPanel = new JPanel();
        scrollTextPanel.setPreferredSize(new Dimension(300, 20));
        scrollTextPanel.setBackground(Color.WHITE);
        scrollTextPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(scrollTextPanel, "North");
    }

    @Override
    public void paintComponent(Graphics g) {
        System.out.println("paintComponent");
        super.paintComponent(g);
        g.setColor(Color.black);
        g.drawImage(logo, 5, 5, 90, 90, this);
        g.drawLine(0, 0, 300, 300); // for testing, does not work
    }

    // a little useful method for handling loading of images and stuff
    public BufferedImage loadImage(String filename) {
        BufferedImage image = null;
        try {
            URL url = new URL(pb.getCodeBase(), "images/"   filename);
            image = ImageIO.read(url);
        } catch (IOException e) {
            // do NOT ignore exceptions in broken code.
        }
        return image;
    }
}
  

Комментарии:

1. Привет @Andrew Thompson, спасибо за это. Итак, вы говорите, что думаете / думали, что это был мой метод LoadImage? Я попробовал пару перестановок в нем, но попробую эту, если вы думаете, что это поможет.

2. Нет. Удалите аргументы первого вызова BorderLayout конструктора и проверьте разницу. Это должно привести к тому, что частично показанное изображение / строка снова исчезнет. Просто еще в сторону. Я сопротивлялся изменению большинства setPreferredSize() вызовов, но обратите внимание, что лучше удалить их и решить, как правильно настроить графический интерфейс.