来自“Head First Java”的示例。该程序的本质是,当您单击该按钮时,会播放音符,同时在“我的绘制面板”面板上的“图形”面板上绘制矩形。但由于某种原因,框架组件的副本在绘图面板中与它们一起绘制。结果,绘图面板向下并向右移动。
代码启动程序
播放后的画面
代码:
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() 方法,伪影消失,但屏幕上的形状一次绘制一个,而不保存以前的形状。我需要保存以前的图纸。如何在保存以前的形状的同时删除伪影?
通过使用 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).
}