PM Homework 2: Building Custom Swing Components: The MusicView Component
Homework 2: Building Custom Swing Components: The MusicView Component
Start Assignment
Due Friday by 11:59pm Points 100 Submitting a file upload File Types zip
Copyright By PowCoder代写 加微信 powcoder
This is an INDIVIDUAL assignment.
In the last assignment you learned how to put together Swing applications by assembling existing components. In this assignment, you’ll learn how to create your own Swing component from scratch. We’ll be building a MusicView component to display a page of sheet music and allow the user to interact with it in a variety of ways. This MusicView component will appear in the main content area from Homework 1, replacing the JLabel that you have there now.
The learning goals for this assignment are:
Experience with the Swing drawing pipeline. Experience writing a variety of input listeners. Experience with the Swing component architecture
Music Notation Basics
This section has a brief introduction to the notation system used for Western music. Reminder: you do not need to be a musician or be able to read musical notation in order to do this project. This section just has some basic terminology that we’ll use in this and later assignments, and gives a bit of background context in case you’re interested.
In musical notation, a set of basic symbols represent notes (musical sounds), rests (pauses between sounds), and what are known as accidentals (these are symbols that indicate a change in the basic pitch of the note, such as sharps and flats). For notes and rests, the shape of the symbol indicates the duration of it ¡ª how long the note is played, or how long the pause is between notes. There are a broad range of these symbols, but for this project we’ll be using the following:
Notes: whole note , half note , quarter note , eighth note , and sixteenth note .
Rests: whole rest , half rest , quarter rest , eighth rest , and sixteenth rest . Accidentals: sharp and flat .
https://gatech.instructure.com/courses/266116/assignments/1153302 1/11
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
These musical symbols are placed on a staff that consists of five horizontal lines. The symbols are the front of the staff indicate, first, the pitch range that the staff represents (in this case, the treble clef represented by the curly symbol), and the timing of the music on the staff (the C-shape indicating “common” time). Here’s a blank staff that has no notes on it yet:
Note, rest, and accidental symbols are placed either directly on a line in the staff, or in a space between the lines.
The vertical position of a note on the staff indicates the audible pitch of it; a note’s pitch is commonly represented by a letter from the set ABCDEFG. Starting from the bottom line and going to the top, these are labeled EGBDF; the spaces between the lines are labeled FACE from the bottom up. However, the labels ABCDEFG get repeated; on a piano keyboard, for example, there are multiple “A” notes that repeat across the length of the keyboard. So technically, the notes on the treble clef are referred to as E4, F4, G4, A5, B5, C5, D5, E5, and F5 (going from the bottom line through all the spaces and lines up to the top line).
Here’s an example of the first staff of Beethoven’s Ode to Joy; below the staff shows the names of the notes based on their vertical position (note that as shown here, some notes are below the actual staff; you don’t need to worry about those in this assignment):
Most pieces of music will have many staves, one after the other on the page. The last staff in a piece of music has a special bar at the end that indicates that it’s the completion of the musical piece. This is only present on the last staff:
While there’s much (much) more to musical notation, for the purposes of this homework that’s all you need to know. In the next phase of this project we’ll let the user create and delete staves of music, and then use the mouse to add musical symbols to these staves, and edit the music by dragging musical symbols around.
Description
https://gatech.instructure.com/courses/266116/assignments/1153302 2/11
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
Don’t be intimidated by the length of the homework description! Although long, most of this writeup is here just to provide detail about what I expect from this assignment, as well as some hints about how best to do the implementation.
In this homework, we’ll create a custom Swing component that can display musical notation, and allow us to interact with it in a variety of ways.
There are several major chunks of functionality you’ll need to add for this assignment, which I’ve detailed below. This homework is more complex than the last one, so be sure to get started early. I’d recommend working on the pieces in the following order:
#1: Basic Component Architecture
You should start by creating a new subclass of JComponent, called MusicView or some such. Your new component should have a paintComponent() method in it that will draw the component to the screen. You’ll also need to define several member variables that hold any state information associated with that component. You get to define these data structures, but remember that at a minimum you’ll need to keep track of the number of staves that exist currently, as well as the positions of each musical symbol that the user has added to these staves. You might represent this as a list of staves with a list of symbols for each staff, but it’s entirely up to you.
You may also want to define your own API for your MusicView, so that other parts of your application can interact with it. For example, you might add a newStaff() method that updates the staff data structure to include a new staff, and so forth.
You will likely have only a single MusicView instance in your application, unless you are planning to have multiple pages of music (see Extra Credit). In that case, my recommendation is that you have multiple instances of MusicView and swap out which one is currently in your component hierarchy when the user changes to a different page.
#2: Basic Component Display
Your component’s paintComponent() method will be called whenever Swing decides it’s time to render your MusicView on the screen: overriding this method is how you plug into Swing’s repaint architecture.
By default¡ªwhen the application is first started¡ªyour MusicView should render a simple view of a default set of four staves:
Draw a neutral background color (such as white or gray) that will serve as the background of your component. You can use the drawRect() method on the Graphics object for this.
Draw the default initial four staves. There should be some padding around the edges and between the staves; in other words, leave a gap of space between them and some border spacing between
https://gatech.instructure.com/courses/266116/assignments/1153302 3/11
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
them and the edges of the component. Be sure to leave plenty of room between the staves on the page (at least a full staff’s worth), because we’ll be using that space in later assignments.
To draw the staves, you’ll use the drawLine() method on the Graphics object that’s passed to your paintComponent() method.
Hint: While you could just put the code to draw the staves directly into your MusicView class, it can often be helpful to create some additional classes to keep track of common objects in your application that you’ll be using a lot. So my recommendation is to create a separate Staff class to keep track of the data associated with each staff, and to contain the code for drawing a staff. If you create such a class, it should probably store the X,Y starting position of the staff and perhaps a boolean flag indicating if it’s the last staff or not; you might also define a paint() method on it that takes a Graphics object and draws the staff using it. If you set things up this way, then your paintComponent() code would just iterate through a list of the Staff objects that you maintain and call the paint() method on each, passing its graphics object.
You can choose the size at which you wish to draw your staff. For example, you might choose to render each staff at 60 pixels high by 1000 pixels wide. Each staff should have vertical lines at the left and right edges, and the end staff should have the thin and thick lines seen above in the images.
For images like the treble clef, common time marker, and others, you’ll render these over the top of your staff using drawImage(). All of the graphics files for these symbols, as well as noted, rests, etc., are available on Canvas here (https://gatech.instructure.com/courses/266116/files/33852107/download? download_frd=1) . You should download this file and include the images in your project folder so that they get included in your JAR file; see below for more details on how to make sure these are included in the JAR you submit.
Take a look at the original image files to get a feel for their size; you’ll want to take this into consideration when deciding how large your staff should be drawn, as objects like the treble clef and the notes should “fit” onto whatever size you choose for your staff ¡ª the round part of the bottom of the note images should fit on and between the lines of the staff, and the treble clef should be slightly larger than the staff height, as shown in the images above. (If for some reason the size of the default images doesn’t work for you, let me know; I can provide larger images or show you how to scale images in Java.)
Your code will need to load up all of the images when it’s initialized. Here’s some sample code that shows how to load image files that are bundled into your JAR. Look at the getResource(“/images/trebleClef.png”) and similar lines ¡ª this indicates that when you create your JAR file the images will be found in a folder named “images” at the top level of your JAR file. You’ll need to tweak this path if you don’t set things up this way.
trebleClefImage = ImageIO.read(getClass().getResource(“/images/trebleClef.png”));
commonTimeImage = ImageIO.read(getClass().getResource(“/images/commonTime.png”));
flatImage = ImageIO.read(getClass().getResource(“/images/flat.png”));
sharpImage = ImageIO.read(getClass().getResource(“/images/sharp.png”));
naturalImage = ImageIO.read(getClass().getResource(“/images/natural.png”));
ttps://gatech.instructure.com/courses/266116/assignments/1153302 4/11
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
https://gatech.instructure.com/courses/266116/assignments/1153302 5/11
sixteenthNoteImage = ImageIO.read(getClass().getResource(“/images/sixteenthNote.png”));
eightNoteImage = ImageIO.read(getClass().getResource(“/images/eighthNote.png”));
quarterNoteImage = ImageIO.read(getClass().getResource(“/images/quarterNote.png”));
halfNoteImage = ImageIO.read(getClass().getResource(“/images/halfNote.png”));
wholeNoteImage = ImageIO.read(getClass().getResource(“/images/wholeNote.png”));
sixteenthRestImage = ImageIO.read(getClass().getResource(“/images/sixteenthRest.png”));
eightRestImage = ImageIO.read(getClass().getResource(“/images/eighthRest.png”));
quarterRestImage = ImageIO.read(getClass().getResource(“/images/quarterRest.png”));
halfRestImage = ImageIO.read(getClass().getResource(“/images/halfRest.png”));
wholeRestImage = ImageIO.read(getClass().getResource(“/images/wholeRest.png”));
Hint: Note that the file contains images for a complete staff, including the clef and time indicator; my recommendation is not to use this, but rather draw the staff “by hand” using drawLine(). It’ll make this and later assignments easier if you do it this way.
In your paintComponent() code, you can render any of these images to the screen by using the drawImage() method on the Graphics object passed to your paint code. For example, to render a treble clef onto the screen at a particular set of x,y coordinates, you would do:
g.drawImage(trebleClefImage, x, y, null);
So implement your drawing code so that it’s rendering the staves to the screen with appropriate spacing, and then be sure to render the clef and common time symbols at the left part of each staff. Remember that the last staff that gets drawn should have the bars at the end to indicate it’s the last one in the composition.
Note that if you try to test your component at this point, you may not actually see anything on the screen. That’s because your component will have a default size of 0,0, which basically means that nothing will get drawn. In order to fix this, you’ll need to set your component’s actual size and its preferredSize to some non-zero values¡ªthis will let Swing know how much space you want it to take on the screen. The next section has details on how to do this.
#3: Sizing and Scrolling
We’re going to take a simple approach to sizing and scrolling in this assignment:
The MusicView should have a reasonable preferred size that lets it look nice on the screen. You can play around with this, but maybe 60 pixel borders at the top, left, right, and bottom edges, and plenty of space between the staves. Experiment and find something that works well given the design you want to create.
If the space available in the content area is less than this minimum, scrollbars should allow the user to scroll around the MusicView.
If the space available in the content area is greater than the minimum, you don’t need to dynamically resize the MusicView to fit the available space. In other words, if you make the window really large,
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
the MusicView should still just draw at its preferred size; there will be white space around it, but that’s ok.
The best way to achieve this behavior is, first, make sure you’re correctly setting the size of your component. Once you know how big you want your MusicView to be on the screen, call setSize() to set its actual size to this value, and setPreferredSize() to tell any parent components or layout managers that this is the “ideal” size for your component.
Next, create a JScrollPane and set your MusicView to be its child (called its “client” in scroll pane terminology), and install the JScrollPane into your component hierarchy, replacing the lame JLabel that we used as a placeholder in Homework 1. The JScrollPane will then be in charge of sizing your MusicView, but will use the preferred size of your MusicView as the minimum size it will ever make it. If you resize the window to be smaller than this value, the JScrollPane will display scroll bars to let you move around the MusicView. If you resize the window to be larger than this value, the JScrollPane will increase the size of your MusicView component. You can always be assured, however, that the size you set as the preferred size will always be the minimum size for your MusicView.
So, in your drawing code in paintComponent(), it’s ok to just assume that you’re drawing within the bounds specified by the preferred size you picked for your MusicView. If it turns out the window is huge, then your actual component size will be larger than this, but all the drawing will still occur within the box represented by your preferred size, and it’s ok that there’s whitespace around the rendering.
#4: Adding and Deleting Staves
After getting the basic drawing working, it’s time to implement the functionality that will let us add and delete staves from the MusicView. You’ll need to modify the listeners for your and Delete Staff buttons and menus in order to do this.
Clicking should add another empty staff onto the end of the list of staves being displayed. Two important things to note here are that 1) this new staff will become the end staff, and so should have the special “last staff” bars on it; the previous last staff should just be rendered as a regular staff at this point.
And 2) adding a staff will also change the size of your component. You should update your calculation of the size and preferred size for your component and call setSize() and setPreferredSize() to use the new size. You may also need to call invalidate() on your component so that its JScrollPane parent “notices” the change.
Clicking Delete Staff should remove the last staff from the set of staves being displayed. As before, this will change which staff is rendered as the last one, and will also alter your component’s size. Remember that there should always be at least one staff displayed, so if the number of staves gets to zero, the Delete Staff button should be grayed out until another staff is added.
After any of these changes, remember to call repaint() so that your component’s visual state will be refreshed.
https://gatech.instructure.com/courses/266116/assignments/1153302 6/11
9/28/22, 8:26 PM Homework 2: Building Custom Swing Components: The MusicView Component
#5: Adding Notes and Rests
Next we’ll implement the functionality that allows us to add notes and rests to our musical compositions.
From a UI perspective, the way this will work is that the user will select one of the radio buttons on the side of the interface to indicate which type of symbol they want to add (either a note or a rest). The current position of the slider will indicate the selected duration of the note or rest (e.g., whether it’s a whole, half, quarter, or so forth duration). Then when the user presses the mouse within the MusicView, the correct symbol appears at the mouse location. As long as the mouse is held down, the user can drag it interactively to position it. Then, when the mouse is released, the symbol stays at that position. As long as the tool is selected, future presses/drags/releases will drop the same type of symbol onto the MusicView.
As symbols are added to staves, your listeners will need to update the data structure you’re using to keep track of these. You should create some code that implements the MouseListener and MouseMotionListener interfaces. When a mousePressed is triggered, you should add a new note at the current X,Y coordinates, and call repaint(). This gets the note or rest on the screen initially. Each
time mouseDragged is triggered, you should update the coordinate of the note/rest, and again call repaint(). Finally, when mouseReleased is triggered, you know the note or rest is in its final position.
Hint: My recommendation is to create a couple of other little classes that you use to store details about Notes and Rests, which will track details such as 1) the duration of the note or rest (e.g., sixteenth, eighth, and so on), 2) which staff it’s associated with, 3) its X,Y position within that staff, 4) the pitch of the note (see below) and any more details you might want to keep track of. You might also include a paint() method that draws the appropriate image for the note or rest at its X,Y coordinate; then in your paintComponent() method you’d just iterate through the list of notes and rests and call their paint() methods to delegate drawing to them (much as with the Staff class recommendation above).
For notes, a requirement of this assignment is to figure out the symbol name that represents the pitch of the note, based on its vertical position in the staff (remember that the vertical positions of notes on the staff indicate the pitch that they represent). For example, if a note is on the bottom line of the staff, it’s an E4 note; if it’s between the bottom two lines it’s an F4 note, and so forth. So the final piece of note functionality you’ll need to implement is to figure out the specific pitch of the note based on its vertical position. This ties back to how you chose to draw your staff ¡ª when you wrote the code to draw your staff you figured out the pixel coordinates of where to draw the lines, so you know their positions as wel
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com