Java Drum Sequencer: How to integrate live sequencing from checkBox states? - java

I'm a beginner working on a little drum machine project based off of Head First Java's code in Chapter 13.
At present, the code creates a sequence based on my input on the checkbox grid that the code draws to the GUI.
However I want the program to function like a real drum machine where I can add or subtract hits while the sequence plays.
My idea was to have all channels play on every tick of the sequence per default, and have the checkboxes unmute the channel at that specific tick. However I'm having a hard time figuring out how to implement that.
Is it possible? Is there an easier or better method that I'm not seeing to achieve what I'm aiming for?
import java.awt.*;
import javax.swing.*;
import javax.sound.midi.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.*;
import java.awt.event.*;
public class BeatBox {
JPanel mainPanel;
ArrayList<JCheckBox> checkboxList;
Sequencer sequencer;
Sequence sequence;
Track track;
JFrame theFrame;
String[] instrumentNames = {"Bass Drum", "Closed Hi-Hat", "Open Hi-Hat","Acoustic Snare",
"Crash Cymbal", "Hand Clap", "High Tom", "Hi Bongo", "Maracas", "Whistle", "Low Conga", "Cowbell",
"Vibraslap", "Low-mid Tom", "High Agogo", "Open Hi Conga" };
int[]instruments={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};
public static void main(String[]args){
new BeatBox().buildGUI();
}
public void buildGUI(){
theFrame=new JFrame("Cyber BeatBox");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout=new BorderLayout();
JPanel background=new JPanel(layout);
background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
//Build tempo slider
JSlider slider = new JSlider();
slider.setOrientation(JSlider.HORIZONTAL);
slider.setMinimum(50);
slider.setMaximum(200);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setMajorTickSpacing(10);
slider.setMinorTickSpacing(1);
slider.setValue(120);
JLabel label = new JLabel();
label.setText("Tempo: " + slider.getValue());
slider.addChangeListener(e -> {
JSlider source = (JSlider) e.getSource();
//float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)source.getValue()/100);
label.setText("Tempo: " + String.valueOf(source.getValue()));
});
checkboxList=new ArrayList<JCheckBox>();
Box buttonBox=new Box(BoxLayout.X_AXIS);
JButton start=new JButton("Start");
start.addActionListener(new MyStartListener());
buttonBox.add(start);
JButton stop=new JButton("Stop");
stop.addActionListener(new MyStopListener());
buttonBox.add(stop);
JButton resetButton = new JButton("Reset Patch");
resetButton.addActionListener(new MyResetListener());
buttonBox.add(resetButton);
Box nameBox=new Box(BoxLayout.Y_AXIS);
for(int i=0;i< 16;i++){
nameBox.add(new Label(instrumentNames[i]));
}
background.add(BorderLayout.NORTH,buttonBox);
background.add(BorderLayout.WEST,nameBox);
theFrame.getContentPane().add(background);
background.add(BorderLayout.SOUTH, slider);
buttonBox.add(BorderLayout.EAST, label);
GridLayout grid=new GridLayout(16,16);grid.setVgap(1);
grid.setHgap(2);
mainPanel=new JPanel(grid);
background.add(BorderLayout.CENTER,mainPanel);
for(int i=0;i< 256;i++){
JCheckBox c=new JCheckBox();
c.setSelected(false);
checkboxList.add(c);
mainPanel.add(c);
} // end loop
setUpMidi();
theFrame.setBounds(50,50,300,300);
theFrame.pack();
theFrame.setVisible(true);
} // close method
public void setUpMidi(){
try{
sequencer=MidiSystem.getSequencer();
sequencer.open();
sequence=new Sequence(Sequence.PPQ,4);
track=sequence.createTrack();
sequencer.setTempoInBPM(120);
}catch(Exception e){ e.printStackTrace(); }
} // close method
public void buildTrackAndStart(){
int[]trackList=null;
sequence.deleteTrack(track);
track=sequence.createTrack();
sequencer.setTickPosition(0);
for(int i=0;i<16;i++){
trackList=new int[16];
int key=instruments[i];
for(int j=0;j<16;j++){
JCheckBox jc=(JCheckBox)checkboxList.get(j+(16*i));
if(!jc.isSelected()){
trackList[j]=key;
} /*else{
trackList[j]=0;
}*/
} // close inner loop
makeTracks(trackList);
track.add(makeEvent(176,1,127,0,16));
} // close outer
track.add(makeEvent(192,9,1,0,15));
try{
sequencer.setSequence(sequence);
sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
sequencer.setMasterSyncMode(Sequencer.SyncMode.MIDI_SYNC);
sequencer.start();
sequencer.setTempoInBPM(120);
}catch(Exception e){
e.printStackTrace();
}
} // close buildTrackAndStart method
//Inner Classes
public class MyStartListener implements ActionListener{
public void actionPerformed(ActionEvent a){
buildTrackAndStart(); }
} // close inner class
public class MyStopListener implements ActionListener{
public void actionPerformed(ActionEvent a){
sequencer.stop();
sequencer.setTickPosition(0);}
} // close inner class
public class MyUpTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a){
float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)(tempoFactor*1.03));
}
} // close inner class
public class MyDownTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a){
float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)(tempoFactor*.97));
}
} // close inner class
public class MyResetListener implements ActionListener{
public void actionPerformed(ActionEvent a){
for(int i = 0; i<256; i++){
JCheckBox loopBox = checkboxList.get(i);
loopBox.setSelected(false);
}
}
} // close inner class
//Makers
public void makeTracks(int[]list){
for(int i=0;i<16;i++){
int key=list[i];
if(key!=0){
track.add(makeEvent(144,9,key,100,i));
track.add(makeEvent(128,9,key,100,i+1));
}
}
}
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;
}
}

Related

ActionListener class keeps repeating when swing Timer is started

I am trying to develop a very basic "Simon says" simulator using Java GUI. I have a method that generates and returns an int[] array; for each element in the array, the Timer computer should start, call the doClick() method for the specified JButton, and wait for 1/2 a second. Each JButton is connected to an ActionListener() that changes the color of the specific button to white, activates another Timer timer, and changes the button back to its original color.
Every time I call computer.start(); within the for-loop it runs the code within ComputerListener(), but it repeats endlessly. I have added print statements so that I can see what is going on via the output on Netbeans. I have looked at similar issues on the forum, but nothing has provided a viable solution.
My question: why is my ComputerListener class repeating when computer.start(); is called within the for-loop?
package simon;
// #jagged_prospect
import java.util.Random;
import java.util.Arrays;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.basic.BasicButtonUI;
public class SIMONPanel extends JPanel{
private static final int PANEL_W=300,PANEL_H=300;
private static final int PREF_W=500,PREF_H=500;
private static final String[] CARD_LABELS={"main","info","game"};
private final JPanel gameCard,infoCard,splashCard;
private final JButton rButton,yButton,gButton,bButton;
private final int lives=3;
private CardLayout cardlayout=new CardLayout();
private JPanel cards=new JPanel(cardlayout);
private Action[] actions={new ShowMainAction(),new ShowInfoAction(),
new ShowGameAction()};
private Object source;
private Timer timer,computer;
public SIMONPanel(){
setBackground(Color.BLACK);
setLayout(new BorderLayout());
gameCard=new JPanel();
infoCard=new JPanel();
splashCard=new JPanel();
// game card panel
gameCard.setLayout(new BorderLayout());
gameCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
JPanel gameButtonPanel=new JPanel();
gameButtonPanel.setLayout(new GridLayout(2,2));
JButton startButton=new JButton("Start");
startButton.addActionListener(new StartListener());
rButton=new JButton("red");
rButton.addActionListener(new ColorButtonListener());
rButton.setSize(50,50);
rButton.setUI((ButtonUI)BasicButtonUI.createUI(rButton));
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
yButton=new JButton("yellow");
yButton.addActionListener(new ColorButtonListener());
yButton.setSize(50,50);
yButton.setUI((ButtonUI)BasicButtonUI.createUI(yButton));
yButton.setBackground(Color.YELLOW);
gButton=new JButton("green");
gButton.addActionListener(new ColorButtonListener());
gButton.setSize(50,50);
gButton.setUI((ButtonUI)BasicButtonUI.createUI(gButton));
gButton.setBackground(Color.GREEN);
bButton=new JButton("blue");
bButton.addActionListener(new ColorButtonListener());
bButton.setSize(50,50);
bButton.setUI((ButtonUI)BasicButtonUI.createUI(bButton));
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
gameButtonPanel.add(gButton);
gameButtonPanel.add(rButton);
gameButtonPanel.add(yButton);
gameButtonPanel.add(bButton);
gameCard.add(gameButtonPanel,BorderLayout.CENTER);
gameCard.add(startButton,BorderLayout.SOUTH);
// splash card panel
splashCard.setLayout(new BorderLayout());
splashCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
splashCard.setBackground(Color.BLACK);
JLabel titleLabel=new JLabel("S I M O N",SwingConstants.CENTER);
titleLabel.setFont(new Font("Niagara Solid",Font.BOLD,84));
titleLabel.setForeground(Color.WHITE);
splashCard.add(titleLabel,BorderLayout.CENTER);
// info card panel
// nothing here yet
JPanel buttonPanel=new JPanel(new GridLayout(1,0,5,0));
for(Action action : actions){
buttonPanel.add(new JButton(action));
buttonPanel.setBackground(Color.BLACK);
}
cards.add(splashCard,CARD_LABELS[0]);
cards.add(infoCard,CARD_LABELS[1]);
cards.add(gameCard,CARD_LABELS[2]);
add(cards,BorderLayout.CENTER);
add(buttonPanel,BorderLayout.SOUTH);
}
// sets uniform panel size
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
// shows the Main Menu card
private class ShowMainAction extends AbstractAction {
public ShowMainAction() {
super("Main");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[0]);
}
}
// shows the Info card
private class ShowInfoAction extends AbstractAction {
public ShowInfoAction() {
super("Info");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[1]);
}
}
// show the Game card
private class ShowGameAction extends AbstractAction {
public ShowGameAction() {
super("Game");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[2]);
}
}
private class TimerListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
if(source==gButton){
gButton.setBackground(Color.GREEN);
}
else if(source==rButton){
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
}
else if(source==yButton){
yButton.setBackground(Color.YELLOW);
}
else if(source==bButton){
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
}
}
}
private class ColorButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
source=event.getSource();
int delay=300;
timer=new Timer(delay,new TimerListener());
if(source==gButton){
gButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==rButton){
rButton.setBackground(Color.WHITE);
rButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
else if(source==yButton){
yButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==bButton){
bButton.setBackground(Color.WHITE);
bButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
}
}
private class StartListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// calls generateSequence() to make pattern for player to replicate
// for debugging in output
System.out.println(Arrays.toString(generateSequence()));
}
}
public int[] generateSequence(){
Random ran=new Random();
ComputerListener cpu=new ComputerListener();
computer=new javax.swing.Timer(500,cpu);
int seqLen=4;
int[] gameSequence=new int[seqLen];
for(int x=0;x<seqLen;x++){
int assign=ran.nextInt(4)+1;
gameSequence[x]=assign;
}
for(int y=0;y<seqLen;y++){ // print and wait 1/2 second, repeat 3 times
computer.start();
}
//computer.stop(); // should stop ComputerListener()???
return gameSequence;
}
private class ComputerListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// for debugging in output
System.out.println("it worked");
}
}
}
You're calling the computer Swing Timer's start button multiple times in a for loop, and that is not what you want to do, and in fact, the whole purpose of the timer is to help you get rid of the for loop. Instead the Timer repeats an action, and changes a state, and keeps going until its done. Consider using an int array or better an ArrayList to hold the colors that the timer should iterate through, and within that ActionListener, do the action and advance a pointer to the next position in the array or List, using that pointer to decide what action to do next. Then when the pointer is completely through the collection, stop the Timer.
For an example of exactly what I'm describing, please check out my Timer's ActionListener for an incomplete Simon game here: Method keeps window from closing
The Timer's ActionListener, annotated, is below:
private class TimerListener implements ActionListener {
private SimonPanel simonPanel; // the Simon JPanel
private int colorListIndex = 0; // index into the ArrayList of MyColor objects
private int sliceCount = 0;
private List<MyColor> myColorList; // the MyColor ArrayList -- the random colors to press
private int maxCount;
public TimerListener(SimonPanel simonPanel, List<MyColor> myColorList) {
// pass in the key fields into the program via constructor parameter
this.simonPanel = simonPanel;
this.myColorList = myColorList; // again the ArrayList that holds random MyColor objects
maxCount = myColorList.size(); // size of my list
}
#Override
public void actionPerformed(ActionEvent evt) {
// if index at the end of the list -- get out and clean up
if (colorListIndex == maxCount) {
// clear the display of "pressed" colors
for (MyColor myColor : MyColor.values()) {
simonPanel.setMyColorPressed(myColor, false);
}
// stop this timer
((Timer) evt.getSource()).stop();
return;
}
// the listener is a little complex since it must turn on colors and turn them off
// which is why I use a sliceCount int counter variable here
if (sliceCount == 0) {
// turn on the next color in the list (using the index)
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, true);
sliceCount++;
} else if (sliceCount < TIME_SLICES - 1) {
sliceCount++;
return;
} else if (sliceCount == TIME_SLICES - 1) {
sliceCount = 0;
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, false); // turn off the color
colorListIndex++; // and increment the index
return;
}
}
}

How do you get user input from a button using ActionListener? Java [duplicate]

I want to count the number of times the button is clicked using GUI.
I did this code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
int clicked = 0;
clicked++;
System.out.println(clicked);
}
But it showing the output "1", each time I click the button.
I want every time I click the button to show me the count.
ex: If I click the button two times it should give me output of "2".
You are resetting the counter every time you click, because you have defined the variable inside the action method. Try not doing that.
int clicked = 0; // move this outside
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
// int clicked = 0; -- this resets it to 0 each time
clicked++;
System.out.println(clicked);
}
You've declared clicked as a local variable, initialised to 0, it can never be anything else but 1
Make clicked a class level variable instead...
private int clicked = 0;
//...
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Try below code
int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Change
int clicked = 0;
to be a member of your class. This way it wont be set to zero every time you press the button.
You have declared count variable inside the ActionListener. Declare it outside the block.
int clicked = 0; //make it as your class member.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Depending on how you are instantiating this class you need to declare the clicked variable at either the field level or the class variable level. Currently, the scope of the clicked variable is local to the method.
Option 1
int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Option 2
static int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
The option you use will depend on instantiation. The second option should be avoided if possible.
every time jButton1ActionPerformed fires, the clicked variables gets instantiated back to 0 that's why it is always giving you a value of 1. You should move the clicked variable outside of that method
//Somewhere in your class
private intClicked = 0;
//More methods here.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Threading extends JFrame {
private JPanel contentPane;
private JTextField DisplayOne;
private JTextField DisplayTwo;
int count;
int count1;
int count2;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run()
{
try {
Threading frame = new Threading();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Threading()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.CENTER);
DisplayOne = new JTextField();
panel.add(DisplayOne);
DisplayOne.setColumns(10);
DisplayTwo = new JTextField();
panel.add(DisplayTwo);
DisplayTwo.setColumns(10);
JButton btnCountOne = new JButton("Count 1");
count1=0;
btnCountOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
DisplayOne.setText(Integer.toString(count1++));
}
});
panel.add(btnCountOne);
JButton btnCountTwo = new JButton("Count 2");
count2=0;
btnCountTwo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
DisplayTwo.setText(Integer.toString(count2++));
}
});
panel.add(btnCountTwo);
JButton btnCountBoth = new JButton("Count Both");
count=0;
btnCountBoth.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
while (count < 10)
{
DisplayOne.setText(Integer.toString(++count));
DisplayTwo.setText(Integer.toString(count));
}
}
});
panel.add(btnCountBoth);
}
}

Program not overwriting variable

I have a program which uses 3 radiobuttons to switch between 3 incrementing values for a counter, here time.
I want to change status when a radiobutton is pressed, and it does so, but only for a fraction. When launching the program will keep printing
0
Normal
2
Normal
4
Normal
6
etc. When I press the button slow it prints CHANGE Slow once but keeps incrementing with 2 and still prints Normal every time.
How can I have this permenently switch to a different value for status, and a different increment, until I choose another radiobutton again?
package daynightcycle;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
/**
* Day/night cycle with visuals. Adjustable speed and time inserts.
* Optional date or daycounter later
* #author rogie
*/
public class DayNightCycle extends JFrame implements Runnable{
//JFrame entities
private JPanel animationPanel;
public JRadioButton button;
public JRadioButton button2;
public JRadioButton button3;
public int time = 0;
public String status = "Normal";
public static void main(String[] args) {
DayNightCycle frame = new DayNightCycle();
frame.setSize(2000, 1300);
frame.setLocation(1000,350);
frame.createGUI();
frame.setVisible(true);
frame.setTitle("Day/Night Cycle, Rogier");
(new Thread(new DayNightCycle())).start();
}
private void createGUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout(new FlowLayout() );
animationPanel = new JPanel();
animationPanel.setPreferredSize(new Dimension(2000, 900));
animationPanel.setBackground(Color.black);
window.add(animationPanel);
JRadioButton option1 = new JRadioButton("Slow");
JRadioButton option2 = new JRadioButton("Normal", true);
JRadioButton option3 = new JRadioButton("Fast");
option1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("CHANGE");
status = "Slow";
System.out.println(status);
}
});
option2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
status = "Normal";
}
});
option2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
status = "Fast";
}
});
//option2.setFont(new java.awt.Font("Tahoma", Font.BOLD, 30));
//option2.putClientProperty("JComponent.sizeVariant", "huge"); //doesn't work
ButtonGroup group = new ButtonGroup();
group.add(option1);
group.add(option2);
group.add(option3);
add(option1);
add(option2);
add(option3);
pack();
}
public void run() {
while(true){
System.out.println(time);
System.out.println(status);
try
{
Thread.sleep(500);
if (status.equals("Slow")) {
time += 1;
}
else if (status.equals("Normal")){
time += 2;
}
else {
time += 3;
}
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
}
You are creating to DayNightCycle-Objects, the first shows the GUI and the second prints on the console.
Change the line
(new Thread(new DayNightCycle())).start();
to
(new Thread(frame)).start();
public static void main(String[] args) {
final DayNightCycle frame = new DayNightCycle();
frame.setSize(2000, 1300);
frame.setLocation(1000,350);
frame.createGUI();
frame.setTitle("Day/Night Cycle, Rogier");
And then
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
Or in java 8:
EventQueue.invokeLater(() -> frame.setVisible(true));
}
You in effect created a second DayNightCycle.

Java program in Eclipse Mars, immediately terminates with no output?

I've been trying to code a music player (using java and JFugue) in Eclipse Mars, however, everytime I run the program it terminates after a few seconds with no output. Additionally, when I go to the "run as" drop down menu, there are no options. I feel like the problem is probably glaringly obvious, but I'm a bit new to java so without an error message I'm lost.
This is the main class
import java.util.Scanner;
import java.awt.*;
import java.awt.event.*;
import javax.sound.midi.MidiUnavailableException;
import javax.swing.*;
import java.io.IOException;
import org.jfugue.player.Player;
import org.jfugue.pattern.Pattern;
public class MusicPlayerMain
{
public static String songTitle;
public static JButton play = new JButton("play");
public static JButton back = new JButton("back");
public static JButton pause = new JButton("pause");
public static JButton forward = new JButton("forward");
public static JLabel label;
public static JComboBox dropDown;
public static JButton repeat = new JButton("repeat");
public static JButton selector;
public static void main(String[] args)
{
//-----------------------------------------------------------------
//starts up window
JFrame frame = new JFrame ("MusicPlayer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(3 , 1, 0, 50));
JPanel panelTop = new JPanel(new GridLayout(2, 2, 20, 50));
panelTop.add(new JLabel("Welcome to MusicPlayer!" + "\n" + "Please select a song!"));
String [] songs = {"WinterTime Ladybug Dance", "Song2", "Song3", "Song4", "Song5", "Song6", "Song7", "Song8", "Song9", "Song10"};
dropDown = new JComboBox();
for (int count1 = 0; count1 < 10; count1++)
{
dropDown.addItem(songs[count1]);
}
panelTop.add(dropDown);
selector = new JButton("Select");
panelTop.add(selector);
JPanel panelMiddle = new JPanel(new GridLayout(2, 1, 20, 50));
panelMiddle.setSize(500,200);
JPanel panelBottom = new JPanel(new GridLayout(1, 4, 20, 50));
panelBottom.setSize(500,200);
JPanel panelBottom2 = new JPanel(new GridLayout(1,1,20,50));
panelBottom2.setSize(500,100);
frame.add(panelTop);
frame.add(panelMiddle);
frame.add(panelBottom);
frame.add(panelBottom2);
//-----------------------------------------------------------------
//sets an action for the select button (displays song menu and plays song)
selector.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
label = new JLabel();
//make it so that label changes to song title
String titleOfSong = (String)dropDown.getSelectedItem();
label.setText(titleOfSong);
panelMiddle.add(label);
JProgressBar songProgress = new JProgressBar();
panelMiddle.add(songProgress); //shows progress of song with timer to show duration of song
panelBottom.add(back);//the song's array list index -1
panelBottom.add(play);//a player class
panelBottom.add(pause);//ManagedPlayer class
panelBottom.add(forward);//the song's array list index +1
panelBottom2.add(repeat);//repeats a playlist, song, or returns to normal
Music musical = new Music(selector, dropDown, back, play, pause, forward, label, repeat, songTitle);
try
{
musical.PutSongsIntoArrayList();
}
catch(IOException ioe)
{
System.out.println("No music found!");
}
frame.pack();
musical.playTheMusic(dropDown, songTitle);
}
});
//-----------------------------------------------------------------------
//navigates the music
play.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Music musical = new Music(selector, dropDown, back, play, pause, forward, label, repeat, songTitle);
musical.playTheMusic(dropDown, songTitle);
}
});
pause.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
try
{
Music musical = new Music(selector, dropDown, back, play, pause, forward, label, repeat, songTitle);
musical.pauseTheMusic(play);
}
catch(MidiUnavailableException md)
{
System.out.println("no song found!");
}
}
});
back.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Music musical = new Music(selector, dropDown, back, play, pause, forward, label, repeat, songTitle);
musical.goBack();
}
});
forward.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Music musical = new Music(selector, dropDown, back, play, pause, forward, label,repeat,songTitle);
musical.goForward();
}
});
Music musical = new Music(selector, dropDown, back, play, pause, forward, label, repeat, songTitle);
musical.keepGoing();
repeat.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Music musical = new Music(selector, dropDown, back, play, pause, forward, label,repeat,songTitle);
musical.setToRepeat();
}
});
}
}
This is the class that supplies the methods to navigate the music
import java.awt.*;
import javax.swing.*;
import org.jfugue.player.*;
import org.jfugue.pattern.*;
import javax.sound.midi.MidiUnavailableException;
import java.util.Scanner;
import java.io.File;
import java.util.ArrayList;
import java.io.IOException;
import java.util.Iterator;
public class Music
{
//take out the ones I don't need later
private JButton slctr;
private JComboBox drpDwn;
private JButton bck;
private JButton ply;
private JButton pse;
private JButton frwrd;
private JButton rpt;
private JLabel lbl;
private String title;
String tokens;
//declaring classes
ArrayList <String> TheTokens = new <String> ArrayList();
File musicFile = new File("Tokens.txt");
Pattern pat = new Pattern(tokens);
Player plays = new Player();
public Music(JButton s, JComboBox d, JButton b, JButton p, JButton ps, JButton f, JLabel l, JButton r, String t) //constructor
{
slctr = s;
drpDwn = d;
bck = b;
ply = p;
pse = ps;
frwrd = f;
lbl = l;
rpt = r;
title = t;
}
public void PutSongsIntoArrayList() throws IOException //puts the song tokens into an ArrayList so it can be manipulated
{
Scanner fileScanner = new Scanner(musicFile);
while(fileScanner.hasNext())
{
String readIt = fileScanner.nextLine();
Scanner scanLine = new Scanner(readIt);
scanLine.useDelimiter(",");
title = scanLine.next();
tokens = scanLine.nextLine();
TheTokens.add(title);
TheTokens.add(tokens);
scanLine.close();
}
fileScanner.close();
}
public void playTheMusic(JComboBox d, String title)//used for when song is selected, also when song is stopped and must be played again
{
String selectedSong = (String)d.getSelectedItem();
Iterator itr = TheTokens.iterator();
while(itr.hasNext())
{
if (selectedSong.equals(title))
{
plays.play(pat);
}
}
}
public void pauseTheMusic(JButton ply) throws MidiUnavailableException //pauses the currently playing song
{
plays.getManagedPlayer().pause();
while(!ply.getModel().isPressed()) //allows the method to pause the song indefinitely. Will only end once the song is resumed
{
if(ply.getModel().isPressed())
{
plays.getManagedPlayer().resume(); //resumes the song
}
}
}
public void goBack() //allows the user to listen to the previous song mid-song
{
int index = TheTokens.indexOf(title)-1;
TheTokens.get(index);
plays.play(pat);
}
public void goForward() //allows the user to listen to the next song mid-song
{
int index = TheTokens.indexOf(title)+1;
TheTokens.get(index);
plays.play(pat);
}
public void keepGoing() //causes the next song to play after the first one finishes.
//NOTE: is similar to musical.goForward() but instead of proceeding to next song when a button is pressed,
//this method proceeds to the next song after the first song finishes
{
boolean NextSong = plays.getManagedPlayer().isFinished();
if(NextSong == true)
{
int index = TheTokens.indexOf(title)+1;
TheTokens.get(index);
plays.delayPlay(2000, pat);
plays.play(pat);
}
}
public void setToRepeat()//cycles through repeat playlist, repeat song, and normal
//in main class, pressing button will change text on button to show what part of cycle player is in
{
Iterator itr = TheTokens.iterator();
while(!rpt.getModel().isPressed())
{
if(!itr.hasNext())
{
String inDEX = TheTokens.get(0);
}
if(rpt.getModel().isPressed())
{
while(!rpt.getModel().isPressed())
{
pat.repeat(1);
plays.play(pat);
if(rpt.getModel().isPressed())
{
break;
}
}
}
}
}
}
Try adding frame.setVisible(true) at the end of your main method.

How to make a Gui actually prompt for the dialog boxes?

So I was trying to understand using a Gui in Java and did so by making a little guess the number game. It compiles correctly, however when I run the program it just shows the frame with "Congratulations you win!" at the top. My main question is why the dialog boxes aren't popping up at all and what I should do to fix that. On a related note, when I had the code as JOptionPane.showInputDialog(this,"Play again? Y/N") I got the error message "non-static variable this cannot be referenced from a static context." My secondary, and much less important question, is how to make the message be in the center of the box vertically as well as horizontally.
import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
public class RandomNumberGame{
public static JLabel higherThan;
public static JPanel tooHigh;
public static JLabel lowerThan;
public static JPanel tooLow;
public static JPanel exactlyCorrect;
public static JLabel correctAnswer;
public static JFrame guiFrame;
public static void main(String[] args){
RandomFun();
}
public static void RandomFun()
{
Scanner input=new Scanner(System.in);
guiFrame = new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Fun Games!");
guiFrame.setSize(500,500);
guiFrame.setLocationRelativeTo(null);
guiFrame.setVisible(true);
final JPanel tooHigh = new JPanel();
higherThan = new JLabel("Too High!");
final JPanel tooLow = new JPanel();
lowerThan = new JLabel("Too Low!");
final JPanel exactlyCorrect = new JPanel();
correctAnswer = new JLabel("Congratulations, you won!");
tooHigh.add(higherThan);
tooLow.add(lowerThan);
exactlyCorrect.add(correctAnswer);
guiFrame.add(tooHigh, BorderLayout.CENTER);
guiFrame.add(tooLow, BorderLayout.CENTER);
guiFrame.add(exactlyCorrect, BorderLayout.CENTER);
}
public static void GuessNumber(){
String again;
String lastGuess = "0";
boolean moreGame=true;
int lastGuessInt = Integer.parseInt(lastGuess.toString());
int winner = (int) (Math.random()*999+1);
while(moreGame){
lastGuess = JOptionPane.showInputDialog("Guess a Number");
if(winner < lastGuessInt){
tooHigh.setVisible(true);
tooLow.setVisible(false);
exactlyCorrect.setVisible(false);
}
else if(winner > lastGuessInt){
tooHigh.setVisible(false);
tooLow.setVisible(true);
exactlyCorrect.setVisible(false);
}
else{
tooHigh.setVisible(false);
tooLow.setVisible(false);
exactlyCorrect.setVisible(true);
moreGame=false;
}
}
again = JOptionPane.showInputDialog("Play again? Y/N");
switch(again){
case "y": case "Y":
GuessNumber();
break;
case "n": case "N":
System.exit(0);
break;
}
}
}
Why the "mis-behavior":
Your main method calls RandomFun()
And RandomFun() then creates a JFrame and displays.
It adds 3 JPanels all in the BorderLayout.CENTER position!
Thus only the last JPanel will show because it will cover all the previously added JPanels as per BorderLayout's documented behavior.
Thus your code is behaving exactly as you'd expect it to.
Other issues include a gross over-use of the static modifier, calling setVisible(true) on the JFrame before adding all components, setting the size of the JFrame, creating a method, GuessNumber() that is never called by viable running code, code not adhering to Java naming conventinons (methods and fields should begin with a lower-case letter, classes with an upper-case letter),...
If I were in your shoes, I'd put the GUI coding to the side as I'd first want to concentrate on learning Java basics, including avoiding all static methods and fields and instead creating true OOPs-compliant classes, since this understanding is critical prior to delving into GUI coding. Just a few weeks of study should be enough to get you strong enough to then try some Swing coding.
My attempt to create a guessing game program:
import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.text.JTextComponent;
#SuppressWarnings("serial")
public class RandomNumberGame2 extends JPanel {
private static final int LOW = 0;
private static final int HIGH = 100;
public static final String START_GAME = "Please guess the random number between "
+ LOW + " and " + HIGH;
public static final String TO_HIGH = "Your guess is too high. Please try again";
public static final String TO_LOW = "Your guess is too low. Please try again";
public static final String CONGRATS_YOU_WIN = "Congratulations, you win!!!";
private Random random = new Random();
private int randomNumber; // holds the randomly selected number
private JTextField inputField = new JTextField(5); // where user enters guess
private JButton submitButton = new JButton(new SubmitAction("Submit", KeyEvent.VK_S));
private JButton resetButton = new JButton(new ResetAction("Reset", KeyEvent.VK_R));
private JLabel statusLabel = new JLabel(START_GAME, SwingConstants.CENTER);
public RandomNumberGame2() {
// so field will select all when gains focus
inputField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComp = (JTextComponent) e.getSource();
textComp.selectAll();
}
});
// so input field will submit number if enter is pressed
inputField.addActionListener(submitButton.getAction());
JPanel centerPanel = new JPanel(); // uses flow layout by default
centerPanel.add(new JLabel("Enter number here:"));
centerPanel.add(inputField);
centerPanel.add(submitButton);
centerPanel.add(resetButton);
setLayout(new BorderLayout());
add(statusLabel, BorderLayout.PAGE_START);
add(centerPanel, BorderLayout.CENTER);
resetGame();
}
public void resetGame() {
randomNumber = random.nextInt(HIGH - LOW) + LOW;
inputField.setText("");
statusLabel.setText(START_GAME);
inputField.requestFocusInWindow();
inputField.selectAll();
}
private class SubmitAction extends AbstractAction {
public SubmitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
try {
int input = Integer.parseInt(inputField.getText().trim());
if (input > randomNumber) {
statusLabel.setText(TO_HIGH);
} else if (input < randomNumber) {
statusLabel.setText(TO_LOW);
} else {
statusLabel.setText(CONGRATS_YOU_WIN);
}
inputField.requestFocusInWindow();
inputField.selectAll();
} catch (NumberFormatException e1) {
JOptionPane.showMessageDialog(RandomNumberGame2.this,
"Please enter only integer data", "Non-numeric Data Error",
JOptionPane.ERROR_MESSAGE);
inputField.setText("");
}
}
}
private class ResetAction extends AbstractAction {
public ResetAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
resetGame();
}
}
private static void createAndShowGui() {
RandomNumberGame2 mainPanel = new RandomNumberGame2();
JFrame frame = new JFrame("Fun Games 2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories