gpt4 book ai didi

java - 如何将 GUI 的状态恢复到原来的外观?

转载 作者:行者123 更新时间:2023-12-02 07:25:16 24 4
gpt4 key购买 nike

我用 Java 为使用 2D 图形的吉他和弦查找应用程序编写了一个 GUI。该程序在 Canvas 上打开一个 .jpg 图像。然后,它将每个单独的音符(音品之间的空间)绘制为带有音符名称的椭圆形。该程序允许用户从工具栏中选择和弦,通过更改和弦各个音符的颜色将它们显示在指板上。然而,每当用户选择新的和弦时,先前的和弦都不会被删除。我怎样才能解决这个问题?这是我的一些代码(该程序有超过 1000 行代码)。

    public class Fretboard extends JFrame  implements ActionListener{
public static void main(String[] args) {
JFrame frame = new Fretboard();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
// Variables to be used throughout the program
ImagePanel imageSrc;
// Declare fonts to be used
Font font1 = new Font("SansSerif", Font.BOLD, 18); // Font to be used for notes with # or b
Font chordFont = new Font("SansSerif", Font.BOLD, 50); // Font for the name of the chord displayed
Font font = new Font("SansSerif", Font.BOLD, 20); // Font to be used for whole note

int h = 40, w = 26, x = 695, y = 254;

// Declare the note variables
// First string
Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h); // E note, open 1st string
Ellipse2D F1 = new Ellipse2D.Double(x, y, w, h); // F note, 1st string, 1st fret
Ellipse2D fSharp1 = new Ellipse2D.Double(x, y+125, w, h); // F#/Gb note, 1st string, 2nd fret
Ellipse2D G1 = new Ellipse2D.Double(x+2, y+240, w, h); // G note, 1st string, 3rd fret

/**
* Create the menu bar and set title
*/

public Fretboard() {
// Change the title of the window
setTitle("Fretboard Chord Finder");
// Create a menu bar where user will be given choice of chords
JMenuBar mb = new JMenuBar();
setJMenuBar(mb);

JMenu menu = new JMenu("Chords");
// Add names of chords to the menu
JMenuItem mi = new JMenuItem("A Major");
mi.addActionListener(this);
menu.add(mi);
mi = new JMenuItem("A Minor");
mi.addActionListener(this);
menu.add(mi);

Container cp = this.getContentPane();
cp.setLayout(new FlowLayout());
imageSrc = new ImagePanel();
cp.add(imageSrc);
}


/**
* Obtain the user's chord selection from the chord menu
*/
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if("A Major".equals(command))
paintAMajor();
if("A Minor".equals(command))
paintAMinor();
}

/**
* Displays the notes for the A Major chord when the user selects
* "A Major" from the toolbar.
*/
public void paintAMajor() {
// Declare local variables
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g;

// Display the name of the chord
g2.drawString("A Major Chord", 40, 150);
g2.drawString("Notes: A, C#, E", 40, 180);

// Display notes for the A Major chord
// Draw the E note on the open 1st string
// Change color to blue
g2.setColor(Color.red);
g2.draw(E1);
g2.fill(E1);
g2.setColor(Color.white);
g2.setFont(font);
g2.drawString("E", x+7, y-82);
// Change color back to red
g2.setColor(Color.red);
}

class ImagePanel extends JPanel {
BufferedImage image = null;

public ImagePanel() {
File fretBoardFile = new File("/Users/macbook/documents/workspace/Fretboard App/Gibson_Fretboard.jpg"); // The location of the fretboard image
// Open the image
try {
image = ImageIO.read(fretBoardFile);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setPreferredSize(new Dimension(1280, 960));
}

/**
*
* @param bi
*/
public ImagePanel(BufferedImage bi) {
image = bi;
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the image of the fretboard on the canvas.
// Check to see if the image is available
if(image != null) {
g2.drawImage(image, 25, 0, null);
}
else
g2.drawRect(0, 0, getWidth()-1, getHeight()-1);

// Draw notes
// Draw the E note on the open 1st string
// Change color to blue
g2.setColor(Color.blue);
g2.draw(E1);
g2.fill(E1);
g2.setColor(Color.white);
g2.setFont(font);
g2.drawString("E", x+7, y-82);
// Change color back to blue
g2.setColor(Color.blue);
}

这是该计划的要点。其他一切基本上都是每个单独音符的放置或显示和弦的类似方法。我被困住了,不知道如何修复这个程序。这也是我编写的第一个 GUI。请帮忙。谢谢!

最佳答案

我首先想到的是使用 getGraphics()。您应该避免使用此方法。

Java 中的图形是无状态的。也就是说,用于渲染组件的Graphics上下文不能保证在周期之间是相同的。您不应保留对 Graphics 上下文的引用。

所有绘制都应在组件 paint 方法的上下文中完成,最好是 JComponent#paintComponent,因为 paint 方法是一个复杂的方法,做了很多你真的不想重复的重要工作。

我会创建某种和弦“模型”,其中每个实例都能够自行绘制。然后,我将创建一个能够绘制品格和和弦的 View 。

用示例更新

这是一个概念验证示例。假设吉他弦从 5(粗)到 0(最小)开始。

我不是音乐家,我没有节拍或节奏,所以我可能犯了一些根本性的错误。

enter image description here

public class TestFretBoard {

public static void main(String[] args) {
new TestFretBoard();
}

public TestFretBoard() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ChordsPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class ChordsPane extends JPanel {

public ChordsPane() {
setLayout(new BorderLayout());
FretPane fretPane = new FretPane();
fretPane.setChord(new AChord());
add(fretPane);
}
}

public static interface FretBoard {

public Rectangle getFretBounds(int index);

public GuitarString getGuitarString(int index);

public GuitarString[] getGuitarStrings(int... index);
}

public static class FretPane extends JPanel implements FretBoard {

private static final Point BOARD_OFFSET = new Point(9, 9);
private static final int BOARD_WIDTH = 84;
private static final Rectangle[] FRET_BOUNDS = {
new Rectangle(BOARD_OFFSET.x, 20, BOARD_WIDTH, 68 - 20),
new Rectangle(BOARD_OFFSET.x, 71, BOARD_WIDTH, 113 - 71),
new Rectangle(BOARD_OFFSET.x, 116, BOARD_WIDTH, 153 - 116),
new Rectangle(BOARD_OFFSET.x, 156, BOARD_WIDTH, 189 - 156),
new Rectangle(BOARD_OFFSET.x, 192, BOARD_WIDTH, 222 - 192),
new Rectangle(BOARD_OFFSET.x, 225, BOARD_WIDTH, 254 - 225),
new Rectangle(BOARD_OFFSET.x, 257, BOARD_WIDTH, 289 - 257),
new Rectangle(BOARD_OFFSET.x, 287, BOARD_WIDTH, 312 - 287),
new Rectangle(BOARD_OFFSET.x, 315, BOARD_WIDTH, 338 - 315),
new Rectangle(BOARD_OFFSET.x, 341, BOARD_WIDTH, 364 - 341),
new Rectangle(BOARD_OFFSET.x, 367, BOARD_WIDTH, 389 - 367),
new Rectangle(BOARD_OFFSET.x, 392, BOARD_WIDTH, 412 - 392),};
private static final GuitarString[] GUITAR_STRINGS = {
new GuitarString(85 - BOARD_OFFSET.x, 1),
new GuitarString(72 - BOARD_OFFSET.x, 1),
new GuitarString(58 - BOARD_OFFSET.x, 1),
new GuitarString(43 - BOARD_OFFSET.x, 2),
new GuitarString(29 - BOARD_OFFSET.x, 2),
new GuitarString(15 - BOARD_OFFSET.x, 2),};
private BufferedImage background;
private Chord chord;

public FretPane() {
try {
background = ImageIO.read(new File("fretboard02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}

@Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}

public Chord getChord() {
return chord;
}

public void setChord(Chord chord) {
this.chord = chord;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.drawImage(background, x, y, this);
Chord chord = getChord();
if (chord != null) {
g2d.translate(x, y);
chord.paint(this, g2d);
g2d.translate(-x, -y);
}
}
g2d.dispose();
}

@Override
public Rectangle getFretBounds(int index) {
Rectangle bounds = null;
if (index >= 0 && index < FRET_BOUNDS.length) {
bounds = FRET_BOUNDS[index];
}
return bounds;
}

@Override
public GuitarString getGuitarString(int index) {
GuitarString gs = null;
if (index >= 0 && index < GUITAR_STRINGS.length) {
gs = GUITAR_STRINGS[index];
}
return gs;
}

@Override
public GuitarString[] getGuitarStrings(int... indices) {
List<GuitarString> strings = new ArrayList<GuitarString>(indices.length);
for (int index : indices) {
strings.add(getGuitarString(index));
}
return strings.toArray(new GuitarString[strings.size()]);
}
}

public static class GuitarString {

private int x;
private int width;

public GuitarString(int x, int width) {
this.x = x;
this.width = width;
}

public int getX() {
return x;
}

public int getWidth() {
return width;
}
}

public interface Chord {

public String getName();

public void paint(FretBoard board, Graphics2D g2d);
}

public abstract class AbstractChord implements Chord {

public abstract int[] getFrets();

public abstract GuitarString[] getGuitarStrings(FretBoard board, int fret);

@Override
public void paint(FretBoard board, Graphics2D g2d) {
for (int fret : getFrets()) {
Rectangle fretBounds = board.getFretBounds(fret);
// Guitar Strings start at 5 (thickest) to 0 (smallest)
GuitarString[] guitarStrings = getGuitarStrings(board, fret);

int y = fretBounds.y + (fretBounds.height / 2);

g2d.setColor(Color.RED);
Ellipse2D dot = new Ellipse2D.Float(0, 0, 10, 10);

for (GuitarString gs : guitarStrings) {
int x = ((gs.x + fretBounds.x) + (gs.width / 2)) - 5;
g2d.fill(getDot(dot, x, y - 5));
}
}
}

public Shape getDot(Ellipse2D dot, int x, int y) {

PathIterator pathIterator = dot.getPathIterator(AffineTransform.getTranslateInstance(x, y));
Path2D path = new Path2D.Float();
path.append(pathIterator, true);

return path;

}
}

public class AChord extends AbstractChord {

private int index;

@Override
public String getName() {
return "A";
}

@Override
public int[] getFrets() {
return new int[]{1};
}

@Override
public GuitarString[] getGuitarStrings(FretBoard board, int fret) {
GuitarString[] strings = new GuitarString[0];
switch (fret) {
case 1:
strings = board.getGuitarStrings(3, 2, 1);
break;
}
return strings;
}

}
}

图像和 UI 之间的映射需要做很多工作,这个你需要自己弄清楚,我打开了 PhotoShop 并手动测量了所有的点。如果您自己绘制指板,就会变得更容易。

基本概念围绕“和弦”。和弦有一个名字并且可以描绘自己。我已经为我的 Chord 界面创建了一个简单的抽象实现,该实现占用了大部分的工作时间,并且可以更轻松地创建新和弦(因为您只需要为其提供每个和弦的品格和琴弦即可)组成该和弦的品格)

我还建议您仔细阅读

关于java - 如何将 GUI 的状态恢复到原来的外观?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13652594/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com