随着音乐绘画时出现伪影。删除工件时,之前绘制的形状不会保存

问题描述 投票:0回答:1

来自“Head First Java”的示例。该程序的本质是,当您单击该按钮时,会播放音符,同时在“我的绘制面板”面板上的“图形”面板上绘制矩形。但由于某种原因,框架组件的副本在绘图面板中与它们一起绘制。结果,绘图面板向下并向右移动。

代码启动程序

enter image description here

播放后的画面

enter image description here

代码:

import javax.sound.midi.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MiniMusicPlayer5 {

MyDrawPanel panelFigure;

public static void main(String[] args) {
    MiniMusicPlayer5 mini = new MiniMusicPlayer5();
    mini.getGuiPanel();
}

public void getGuiPanel() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    // We create a dance panel.
    JLabel label = new JLabel("Танцпол");
    label.setBackground(Color.yellow);
    label.setOpaque(true);
    label.setAlignmentX(JLabel.CENTER_ALIGNMENT);

    JPanel panelDance = new JPanel();
    panelDance.setBackground(Color.gray);
    Dimension d1 = new Dimension(400, 340);
    panelDance.setPreferredSize(d1);
    panelDance.setMaximumSize(d1);
    panelDance.setAlignmentX(JPanel.CENTER_ALIGNMENT);

    panelFigure = new MyDrawPanel(); // Create a drawing panel.
    panelDance.add(panelFigure);

    JPanel panelMain = new JPanel();
    panelMain.setLayout(new BoxLayout(panelMain, BoxLayout.Y_AXIS));
    panelMain.add(label);
    panelMain.add(panelDance);
    panelMain.revalidate();
    panelMain.repaint();
    panelMain.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 20));

    // Create a button panel.
    JButton buttonPlay = new JButton("Проиграть");
    buttonPlay.addActionListener(new ButtonPlayListener());

    JPanel panel = new JPanel();
    panel.setBorder(BorderFactory.createEmptyBorder(60, 20, 0, 20));
    panel.add(panelMain);
    panel.add(buttonPlay);

    // We create a frame.
    frame.setContentPane(panel);
    frame.setSize(600, 500);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
} // End of setUpGui().

public class ButtonPlayListener implements ActionListener {
    public void actionPerformed(ActionEvent ev) {
        try {
            Sequencer player = MidiSystem.getSequencer();
            player.open();
            player.addControllerEventListener(panelFigure, new int[]{127});
            Sequence seq = new Sequence(Sequence.PPQ, 4);
            Track track = seq.createTrack();

            for (int i = 0; i < 100; i += 4) {
                int note = (int) ((Math.random() * 50) + 1);
                if (note < 38) {
                    track.add(makeEvent(144, 1, note, 100, i));
                    track.add(makeEvent(176, 1, 127, 0, i));
                    track.add(makeEvent(128, 1, note, 100, i + 2));
                }
            }
            player.setSequence(seq);
            player.setTempoInBPM(180);
            player.start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
} // End of play().

public MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {
    MidiEvent event = null;
    try {
        ShortMessage a = new ShortMessage();
        a.setMessage(comd, chan, one, two);
        event = new MidiEvent(a, tick);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return event;
} // End of MidiEvent makeEvent().

// Panel for drawing is now a listener.
class MyDrawPanel extends JPanel implements ControllerEventListener {
    // We assign the flag the value of "FALSE" and we will install "TRUE" when we get a state.
    boolean msg = false;

    public Dimension getPreferredSize() {
        return new Dimension(400, 340);
    }

    // The method of processing an event from the listener's interface.
    public void controlChange(ShortMessage event) {
        // We get an event, assigning the flag the value of "True" and calling the repaint().
        msg = true;
        repaint();
    } // End of controlChange(ShortMessage event).

    public void paintComponent(Graphics g) {
        // We use the MSG flag so that drawing is triggered only when the Controllerevent event occurs, and other objects could not launch repaint().
        if (msg) {
            Graphics2D g2 = (Graphics2D) g;

            // Random color.
            int red = (int) (Math.random() * 250);
            int green = (int) (Math.random() * 250);
            int blue = (int) (Math.random() * 250);
            g2.setColor(new Color(red, green, blue));

            // Random position of the figure.
            int x = (int) ((Math.random() * 200) + 30);
            int y = (int) ((Math.random() * 170) + 90);
            int width = (int) ((Math.random() * 200) + 0);
            int height = (int) ((Math.random() * 170) + 0);
            g2.fillRect(x, y, width, height);
            msg = false;
        } // Closed if.
    } // End of void paintComponent(Graphics g).
}

通过应用不透明度规则和 super.paintComponent() 方法,伪影消失,但屏幕上的形状一次绘制一个,而不保存以前的形状。我需要保存以前的图纸。如何在保存以前的形状的同时删除伪影?

java swing events bufferedimage midi
1个回答
0
投票

通过使用 BufferedImage 类进行缓冲解决了该问题。这些问题的答案帮助解决了我的问题:在 Swing 内的 BufferedImage 中绘画绘制一个在下次绘画中不会消失的矩形。 我还必须回到《Head First Java 2》一书中的迷你音乐播放器代码的第二个版本。 感谢所有试图提供帮助的人!

最终代码:

import javax.sound.midi.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

public class MiniMusicPlayer4 implements ControllerEventListener {
    private BufferedImage panelFigure;
    private JLabel danceLabel;
    private RenderingHints renderingHints;
    private boolean msg = false;
    private static MiniMusicPlayer4 mini;

    public static void main(String[] args) {
        mini = new MiniMusicPlayer4();
        SwingUtilities.invokeLater(() -> mini.getGuiPanel());
    }

    public void getGuiPanel() {
        Map<RenderingHints.Key, Object> hintsMap = new HashMap<>();
        hintsMap.put(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        hintsMap.put(RenderingHints.KEY_DITHERING,
                RenderingHints.VALUE_DITHER_ENABLE);
        hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        renderingHints = new RenderingHints(hintsMap);

        JFrame frame = new JFrame("Танцы фигур");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setBorder(BorderFactory.createEmptyBorder
                (60, 20, 0, 20));

        JLabel label = new JLabel("Танцпол");
        label.setBackground(Color.yellow);
        label.setOpaque(true);
        label.setAlignmentX(JLabel.CENTER_ALIGNMENT);

        // Создаём панель танца фигур.
        panelFigure = new BufferedImage
                (400, 340, BufferedImage.TYPE_INT_ARGB);

        JPanel dancePanel = new JPanel();
        dancePanel.setBackground(Color.gray);
        Dimension d1 = new Dimension(400, 340);
        dancePanel.setPreferredSize(d1);
        dancePanel.setMaximumSize(d1);
        dancePanel.setAlignmentX(JPanel.CENTER_ALIGNMENT);

        danceLabel = new JLabel(new ImageIcon(panelFigure));

        dancePanel.add(danceLabel, null);

        JPanel panelMain = new JPanel();
        panelMain.setLayout(new BoxLayout(panelMain, BoxLayout.Y_AXIS));
        panelMain.add(label);
        panelMain.add(dancePanel);
        panelMain.setBorder(BorderFactory.createEmptyBorder
                (0, 0, 0, 20));

        // Создаём кнопку.
        JButton buttonPlay = new JButton("Проиграть");
        buttonPlay.addActionListener(new ButtonPlayListener());

        panel.add(panelMain);
        panel.add(buttonPlay);

        frame.setContentPane(panel);
        frame.setSize(600, 500);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    } // Конец getGuiPanel().

    /// Метод рисования.
    public void myDraw() {
        Graphics2D g2 = panelFigure.createGraphics();
        g2.setRenderingHints(renderingHints);
        if (msg) {
            // Случайный цвет.
            int red = (int) (Math.random() * 250);
            int green = (int) (Math.random() * 250);
            int blue = (int) (Math.random() * 250);
            g2.setColor(new Color(red, green, blue));

            // Случайное положение фигуры.
            int x = (int) ((Math.random() * 200) + 20);
            int y = (int) ((Math.random() * 170) + 20);
            int width = (int) ((Math.random() * 200) + 0);
            int height = (int) ((Math.random() * 170) + 0);
            g2.fillRect(x, y, width, height);
            msg = false;
        }
        danceLabel.repaint();
        danceLabel.revalidate();
    }

    public class ButtonPlayListener implements ActionListener {
        public void actionPerformed(ActionEvent ev) {
            try {
                Sequencer player = MidiSystem.getSequencer();
                player.open();
                player.addControllerEventListener(mini, new int[]{127});
                Sequence seq = new Sequence(Sequence.PPQ, 4);
                Track track = seq.createTrack();

                for (int i = 0; i < 100; i += 4) {
                    int note = (int) ((Math.random() * 50) + 1);
                    if (note < 38) {
                        track.add(new MidiEvent(new ShortMessage(ShortMessage.
                                NOTE_ON, 1, note, 100), i));
                        track.add(new MidiEvent(new ShortMessage(ShortMessage.
                                CONTROL_CHANGE, 1, 127, 0), i));
                        track.add(new MidiEvent(new ShortMessage(ShortMessage.
                                NOTE_OFF, 1, note, 100), i + 2));
                    }
                }
                player.setSequence(seq);
                player.setTempoInBPM(180);
                player.start();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    // Метод обработки события из интерфейса слушателя.
    public void controlChange(ShortMessage event) {
        // Получаем событие, присвоив флагу значение "true" и вызвав...
        // repaint().
        msg = true;
        myDraw();
    } // Конец controlChange(ShortMessage event).
}

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.