I wrote a GUI in Java for a guitar chord finder application using 2D graphics. The program opens an .jpg image on the canvas. It then draws each individual note (space between the frets) as an ellipse with the name of the note. The program allows the user to select chords from a toolbar where they are displayed on the the fretboard by changing the color of the chord’s individual notes. However, whenever the user selects a new chord, the previous chord is not deleted. How can I fix this? Here is some of my code (The program is over 1000 lines of code).
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);
}
This is the gist of the program. Everything else is basically the placement of each individual notes or similar methods to display the chords. I am stuck and have no idea how to fix this program. This is the first GUI I have ever programmed as well. Please help. Thanks!
The first thing that jumps out at me is the use
getGraphics(). You should avoid using this method.Graphics in Java are stateless. That is, the
Graphicscontext used to render your component is not guaranteed to be the same between cycles. You shouldn’t keep a reference to theGraphicscontext.All painting should be done from within the context of the components
paintmethods, preferably,JComponent#paintComponent, as thepaintmethod is acomplex method, doing a lot of important work you really don’t want to have to duplicate.I would create a chord “model” of some kind, where each instance was capable of painting it self. I would then create a view that was capable of painting the fret and the chords.
Update with example
This is a proof of concept example. It is assumed that guitar strings start at 5 (thickets) to 0 (smallest).
I’m not a musician, I have no beat or rhythm, so I may have made some fundamental mistakes.
A lot of work goes into mapping between the image and UI, this you’re going to have figure out yourself, I cracked open PhotoShop and measured out all the points manually. If you draw the fret board your self, it becomes easier.
The basic concept revolves around “Chords”. A chord has a name and can paint itself. I’ve create a simple abstract implementation of my
Chordinterface that takes up much of the leg work and makes it easier creating new chords (as you simply only need to provide it with the frets and strings for each fret that makes up that chord)I’d also suggest you have a read through