First, my program is very simple. I just need to click or press Alt + Enter the JButton to increment the counter.
Here is the program so you can try it:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class holdDownClass implements ActionListener {
private static JButton exebouton;
private JTextArea ecran = new JTextArea();
private JScrollPane scrollecran = new JScrollPane(ecran);
private int counter = 0;
public static void main(String[] args) {
new holdDownClass();
}
private holdDownClass() {
// Window
JFrame frame = new JFrame("Name");
frame.setBounds(400, 350, 625, 355);
frame.setLayout(null);
Container container = frame.getContentPane();
// Panel
JPanel panneau = new JPanel();
panneau.setLayout(null);
panneau.setBounds(2, 42, 146, 252);
frame.add(panneau);
JLabel nglabel = new JLabel("Click or Press Alt+Enter");
nglabel.setBounds(5, 0, 200, 20);
panneau.add(nglabel);
// Button
exebouton = new JButton("Execute");
exebouton.setMnemonic(KeyEvent.VK_ENTER); // Shortcut: Alt + Enter
exebouton.setBounds(4, 18, 138, 47);
exebouton.addActionListener(this);
panneau.add(exebouton);
// Text Area
ecran.setEditable(true);
scrollecran.setBounds(150, 42, 467, 252);
container.add(scrollecran);
// Show
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void actionPerformed(ActionEvent e) {
Object test = e.getSource();
if (test.equals(exebouton)) {
counter += 1;
ecran.setText(ecran.getText() + counter + "\n");
}
}
}
My objective is: Instead of repetitively pressing Alt+Enter, I want to hold Alt+Enter to increment the counter "quicker".
You could use a MouseListener, but, personally, I feel it's not the most appropriate means for achieving what it is you are trying to achieve, as it fights against the workings of the button.
Instead, you could attach a change listener to the buttons model and while the button's state remains pressed, cycle a Swing Timer....
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestButton04 {
public static void main(String[] args) {
new TestButton04();
}
private int counter = 0;
private Timer trigger;
private JButton btn;
public TestButton04() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
btn = new JButton("0");
trigger = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
btn.setText(String.valueOf(counter));
}
});
trigger.setCoalesce(true);
trigger.setRepeats(true);
btn.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (btn.getModel().isPressed()) {
trigger.start();
} else {
trigger.stop();
}
}
});
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(btn);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Here's the way you can do it-
private boolean mousePressed;
And a mouse listener-
exebouton.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
mousePressed = true;
new Thread() {
public void run() {
while (mousePressed) {
counter += 1;
ecran.setText(ecran.getText() + counter + "\n");
}
}
}.start();
}
public void mouseReleased(MouseEvent e) {
mousePressed = false;
}
});
That's it.
Related
I need the frame to update and display how many times the Button has been pressed (the button's text to update)
If I can use actionPreformed() to be locked on to specific events (Button press, or the Menu item being pressed), then I think that should help...
Problems:
When Button is pressed it creates more frames
The existing Frame(s) do not update (I only want there to be one frame anyway)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ButtonFrame implements InternalFrameListener, ActionListener
{
JFrame myFrame = null;
private int clicked;
final String F=("Clicked: "+clicked+" Times!");
public static void main(String[] a)
{
(new ButtonFrame()).test();
}
private void test()
{
myFrame = new JFrame("Internal Frame with a Button");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(400,400);
myFrame.setContentPane(new JDesktopPane());
JMenuBar Start_Bar = new JMenuBar();
JMenu Start_Menu = new JMenu("Frame");
JMenuItem Start_Item = new JMenuItem("Start");
Start_Item.addActionListener(this);
Start_Menu.add(Start_Item);
Start_Bar.add(Start_Menu);
myFrame.setJMenuBar(Start_Bar);
myFrame.setVisible(true);
}
public void actionPerformed(ActionEvent Start_Item)
{
JInternalFrame f = new JInternalFrame("Button Frame");
f.setResizable(true);
f.setClosable(false);
f.setMaximizable(true);
f.setIconifiable(true);
f.setSize(200,200);
f.setLocation(100,100);
f.addInternalFrameListener(this);
f.setVisible(true);
Button objButton1;
objButton1=new Button ("Clicked: "+clicked+" Times!");
objButton1.setBounds(20,90,40,50);
f.add(objButton1);
objButton1.addActionListener(this);
myFrame.getContentPane().add(f);
}
public void actionPreformed(ActionEvent objButton1)
{
clicked++;
}
public void internalFrameActivated(InternalFrameEvent e)
{
System.out.println("Internal Button Ready");
}
public void internalFrameClosed(InternalFrameEvent e)
{
System.out.println("Internal frame closed");
}
public void internalFrameClosing(InternalFrameEvent e)
{
System.out.println("Internal frame closing");
}
public void internalFrameDeactivated(InternalFrameEvent e)
{
System.out.println("Internal frame deactivated");
}
public void internalFrameDeiconified(InternalFrameEvent e)
{
System.out.println("Internal frame deiconified");
}
public void internalFrameIconified(InternalFrameEvent e)
{
System.out.println("Internal frame iconified");
}
public void internalFrameOpened(InternalFrameEvent e)
{
System.out.println("Internal frame opened");
}
}
Based on your description, you solution is screaming isolation and separation of code responsibility, the code responsible for managing the button should be separated from the code managing the frame and desktop pane
This way, you can use separate ActionListeners as well as isolate the functionality to a single instance of the button class
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JDesktopPane dp = new JDesktopPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar Start_Bar = new JMenuBar();
JMenu Start_Menu = new JMenu("Frame");
JMenuItem Start_Item = new JMenuItem("Start");
Start_Item.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JInternalFrame f = new JInternalFrame("Button", true, true, true, true);
f.setSize(200, 200);
f.setLocation(100, 100);
f.add(new ButtonPane());
f.setVisible(true);
dp.add(f);
}
});
Start_Menu.add(Start_Item);
Start_Bar.add(Start_Menu);
frame.setJMenuBar(Start_Bar);
frame.add(dp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ButtonPane extends JPanel {
private JButton button;
private int count = 0;
public ButtonPane() {
setLayout(new GridBagLayout());
button = new JButton("0");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
count++;
button.setText(Integer.toString(count));
}
});
add(button);
}
}
}
I am trying to implement a swing frame. In this, I want to display a processing status in a textPanel using a different thread while performing the needed task. I tried the following code. Of course there is something wrong with the logic. Please provide me with the proper approach
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class SampleSwing {
private JFrame frame;
public static JTextField textField;
public static boolean processing=false;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SampleSwing window = new SampleSwing();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SampleSwing() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
textField = new JTextField();
textField.setBounds(0, 31, 434, 20);
frame.getContentPane().add(textField);
textField.setColumns(10);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
processing=true;
Processingstatus ps=new Processingstatus();
ps.start();
/*perform the actual task*/
processing=false;
}
});
btnNewButton.setBounds(174, 74, 89, 23);
frame.getContentPane().add(btnNewButton);
}
}
class Processingstatus extends Thread{
public void run() {
try {
while(SampleSwing.processing) {
SampleSwing.textField.setText("Processing");
Thread.sleep(1000);
SampleSwing.textField.setText("Processing..");
Thread.sleep(1000);
SampleSwing.textField.setText("Processing...");
Thread.sleep(1000);
}
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
First I thought, "you should be using a SwingWorker, as it has methods to handle progress and EDT updates..."
But when I looked closer, you don't actually really care about the process itself, you just want some where to show that a process is running...They are two separate entities, that are only related because one (the UI updates) will run so long as the other is running.
So, instead, I used a javax.swing.Timer. This allows me to schedule an event to occur every n milliseconds and have that triggered in the EDT, nice and clean...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class SampleSwing {
private JFrame frame;
public static JTextField textField;
public static boolean processing = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SampleSwing window = new SampleSwing();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SampleSwing() {
initialize();
}
private Timer processTimer;
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
textField = new JTextField(25);
frame.add(textField, gbc);
processTimer = new Timer(500, new ActionListener() {
private StringBuilder dots = new StringBuilder(3);
#Override
public void actionPerformed(ActionEvent e) {
dots.append(".");
if (dots.length() > 3) {
dots.delete(0, dots.length());
}
textField.setText("Processing" + dots.toString());
}
});
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (!processing) {
processing = true;
processTimer.start();
} else {
processTimer.stop();
processing = false;
textField.setText(null);
}
}
});
frame.add(btnNewButton, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
}
}
ps For the reason why your original code didn't work, see my comment in the above comments section ;)
I have a frame that when i click ok button on tester2 frame, tester1 frame should be seen and when click showbumber button, a random number should be displayed in my label.
But i can't see this generated number while i use sleep method!
Thank for help.
public class tester2 extends JFrame implements ActionListener {
public tester2() {
setTitle("Hello");
setLayout(new FlowLayout());
JButton okButton = new JButton("Ok");
okButton.addActionListener(this);
add(okButton);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(40, 50, 300, 400);
}
#Override
public void actionPerformed(ActionEvent e) {
tester1 tester1 = new tester1(tester2.this);
tester1.setVisible(true);
}
public static void main(String[] args) {
new tester2().setVisible(true);
}
}
tester 1:
public class tester1 extends JDialog implements ActionListener {
JLabel lbl1;
JButton showButton;
public tester1(JFrame owner) {
super(owner, "tester1", true);
showButton = new JButton("Show Number");
showButton.addActionListener(this);
lbl1 = new JLabel(" ");
this.add(showButton);
this.add(lbl1);
this.setBounds(40, 50, 300, 400);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == showButton) {
GenerateNumber();
tester1.this.dispose();
}
}
public void GenerateNumber() {
Random rnd1 = new Random();
try {
Thread.sleep(1000);
lbl1.setText(String.valueOf(rnd1.nextInt(100)));
} catch (InterruptedException inrptdEx) {
}
}
}
If your intention is to close the second frame automatically after a short delay, you should use a javax.swing.Timer instead.
Blocking the EDT will stop it from (amongst other things) processing repaint request, which means your UI can't be updated when you can Thread.sleep
Instead you should use a javax.swing.Timer
public void GenerateNumber() {
Random rnd1 = new Random();
try {
lbl1.setText(String.valueOf(rnd1.nextInt(100)));
} catch (InterruptedException inrptdEx) {
}
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
dispose();
}
});
timer.setRepeats(false);
timer.start();
}
I don't if your dialog shows the showButton and Label before. Because i have to add a panel in order to show them. After that you need a Timer Class to deal with auto dispose.
Your tester1 look now like this
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class tester1 extends JDialog implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
JLabel lbl1;
JButton showButton;
public tester1(JFrame owner) {
super(owner, "tester1", true);
JPanel jPanel = new JPanel();
jPanel.setLayout(new BorderLayout());
this.add(jPanel);
showButton = new JButton("Show Number");
showButton.addActionListener(this);
lbl1 = new JLabel();
jPanel.add(showButton, BorderLayout.NORTH);
jPanel.add(lbl1, BorderLayout.CENTER);
this.setBounds(40, 50, 300, 400);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == showButton) {
GenerateNumber();
}
}
public void GenerateNumber() {
Random rnd1 = new Random();
lbl1.setText(String.valueOf(rnd1.nextInt(1000000)));
Timer timer = new Timer(1000 * 1, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
dispose();
}
});
timer.setRepeats(false);
timer.start();
}
}
I have a couple text fields that I'm tabbing between. On focusLost() I am opening a JOptionPane. I would like the code in focusGained() to be executed AFTER the JOptionPane has been closed. Even though the dialog is modal, focusGained() is being called before the JOptionPane is closed. Is there any way around this?
Found this similar question, but it doesn't seem to have been solved either.
Postpone Event Queue after Focus Lost
Here's a code sample. You'll notice "Focus Gained" is printed before the JOptionPane is closed.
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ShortTest implements FocusListener
{
private void go()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JTextField text1 = new JTextField();
text1.setName("text1");
text1.addFocusListener(this);
JTextField text2 = new JTextField();
text2.setName("text2");
text2.addFocusListener(this);
panel.add(new JLabel("tex1"));
panel.add(text1);
panel.add(new JLabel("text2"));
panel.add(text2);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String [] args)
{
ShortTest test = new ShortTest();
test.go();
}
#Override
public void focusGained(FocusEvent e)
{
if (!e.isTemporary() && (e.getSource() instanceof JTextField))
{
System.out.println("Focus Gained: " + ((JTextField)e.getSource()).getName());
}
}
#Override
public void focusLost(FocusEvent e)
{
if (!e.isTemporary() && (e.getSource() instanceof JTextField))
{
JOptionPane.showOptionDialog(null, ((JTextField)e.getSource()).getName() + " lost focus", "Title", JOptionPane.DEFAULT_OPTION, 0, null, null, null);
}
}
}
Perhaps what you want is not a focus listener (a very low-level construct) but rather an input verifier (a higher level construct). This should respond before the focus has shifted. For example, in the code below the verifier reacts if the user tries to enter non-numeric data into the text field. Yes this can also be done using a DocumentFilter.
import javax.swing.*;
public class VerifierEg extends JPanel {
private static final int FIELD_COUNT = 3;
public VerifierEg() {
InputVerifier inputVerifier = new InputVerifier() {
#Override
public boolean verify(JComponent input) {
final JTextField textField = (JTextField) input;
String text = textField.getText();
for (char c : text.toCharArray()) {
if (!Character.isDigit(c)) {
textField.setText("");
JOptionPane.showMessageDialog(VerifierEg.this, "Text: \""
+ text + "\" must hold only digits", "Text Field Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
}
return true;
}
};
for (int i = 0; i < FIELD_COUNT; i++) {
JTextField field = new JTextField(6);
field.setInputVerifier(inputVerifier);
add(field);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Enter Numbers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new VerifierEg());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit:
The InputVerifier could work for your purpose, even if you're not verifying the input in any specific way. For example, to modify your code:
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.BoxLayout;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ShortTest2 {
private void go() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
InputVerifier inputVerifier = new InputVerifier() {
#Override
public boolean verify(JComponent input) {
JOptionPane.showMessageDialog(frame,
"Focus Lost on " + input.getName());
return true;
}
};
FocusListener focusListener = new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
String name = ((JComponent)e.getSource()).getName();
System.out.println("Focus Lost: " + name );
}
#Override
public void focusGained(FocusEvent e) {
String name = ((JComponent)e.getSource()).getName();
System.out.println("Focus Gained: " + name );
}
};
JTextField[] textFields = new JTextField[2];
for (int i = 0; i < textFields.length; i++) {
JTextField textField = new JTextField(10);
String name = "text " + (i + 1);
textField.setName(name);
textField.setInputVerifier(inputVerifier);
textField.addFocusListener(focusListener);
panel.add(new JLabel(name));
panel.add(textField);
}
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
ShortTest2 test = new ShortTest2();
test.go();
}
}
1+ for your SSCCE by the way!
I am creating a battleship game with 4 classes using sockets. A computer, player message and a menu class. To start the game I run the computer class which is the server then I run the menu class which bring up the menu. Through the menu I click start to create a new player object which looks like this
public static void runPlayer()
{
Player client = new Player(); //creates player
client.createBoard();
client.run();
}
this runs perfectly runs without the menu class if i run the computer class then the player class, the game runs successfully. But when i call the run player method in the menu a window pops up with nothing in it.Here is my Menu class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
import sun.audio.*;
public class Menu {
private javax.swing.JLabel image;
private static final int EXIT_ON_CLOSE = 0;
JFrame frame = new JFrame();
JPanel panel = new JPanel(new BorderLayout());
JLabel statusbar = new JLabel(" Battleship");
JLabel Battleship = new JLabel(" Battleship ");
static AudioPlayer MGP = AudioPlayer.player;
static AudioStream BGM;
AudioData MD;
static ContinuousAudioDataStream loop = null;
public static void waiting (int n)
{
long t0, t1;
t0 = System.currentTimeMillis();
do{
t1 = System.currentTimeMillis();
}
while (t1 - t0 < n);
}
public Menu()
{
frame.setTitle("Battleship");
statusbar.setBorder(BorderFactory.createEtchedBorder(
EtchedBorder.RAISED));
Battleship.setBorder(BorderFactory.createEtchedBorder(
EtchedBorder.RAISED));
panel.setLayout(null);
JButton start = new JButton("Start");
start.setBounds(100, 660, 80, 25);
JButton exit = new JButton("Exit");
exit.setBounds(190, 660, 80, 25);
JButton StopMusic = new JButton("Stop Music");
StopMusic.setBounds(300, 660, 160, 25);
JButton StartMusic = new JButton("Start Music");
StartMusic.setBounds(470, 660, 160, 25);
Battleship.setFont(new Font("Courier New", Font.ITALIC, 36));
Battleship.setForeground(Color.BLACK);
image = new javax.swing.JLabel();
image.setIcon(new javax.swing.ImageIcon("./battleship2.jpg"));
frame.add(image, BorderLayout.EAST);
frame.pack();
frame.add(start);
frame.add(exit);
frame.add(StopMusic);
frame.add(StartMusic);
frame.add(panel);
frame.add(statusbar, BorderLayout.SOUTH);
frame.add(Battleship, BorderLayout.NORTH );
frame.setSize(700, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
music();
start.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
{
frame.dispose(); //closes frame
stopMusic(); //stops music
//waiting(500);
runPlayer();
}}
});
StopMusic.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
{
stopMusic();
}
}
});
StartMusic.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
{
startMusic();
}
}
});
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println( "Ending Game" );
System.exit(0);
}
});}
public static void music()
{
try
{
InputStream test = new FileInputStream("./battle.wav");
BGM = new AudioStream(test);
AudioPlayer.player.start(BGM);
}
catch(FileNotFoundException e){
System.out.print(e.toString());
}
catch(IOException error)
{
System.out.print(error.toString());
}
MGP.start(loop);
}
public void stopMusic()
{
if (BGM != null)
AudioPlayer.player.stop(BGM);
if (loop != null)
AudioPlayer.player.stop(loop);
}
public void startMusic() {
try
{
InputStream test = new FileInputStream("./battle.wav");
BGM = new AudioStream(test);
AudioPlayer.player.start(BGM);
}
catch(FileNotFoundException e){
System.out.print(e.toString());
}
catch(IOException error)
{
System.out.print(error.toString());
}
MGP.start(loop);
}
public static void runPlayer()
{
Player client = new Player(); //creates player
client.createBoard();
client.run();
}
public static void main(String[] args)
{
new Menu();
}
}
I think my problem is somewhere in this listener method
start.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
{
frame.dispose(); //closes frame
stopMusic(); //stops music
//waiting(500);
runPlayer();
}}
});
It's a bit hard to answer this question with the information provided. But I'll have to guess what the runPlayer() method is doing. I'm assuming there's some type of while loop in there that prevents the Event Dispatch Thread from refreshing the new JFrame you created.
Try to place the stopMusic() and runPlayer() in a new thread.
Basically something like this
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.dispose(); // closes frame
new Thread(){
public void run(){
stopMusic(); // stops music
runPlayer();
}
}.start();
}
});
I think the problem lies outside the code you've shown; it could be anything from a missing setVisible() to a synchronization problem. FWIW, I have a few observation about the code:
Build your GUI on the EDT, #David Young just suggested.
Use static constants to avoid repeating yourself.
Don't use spaces to format labels; use the JLabel alignment constants.
Instead of a null layout, use nested layouts to get the result you want.
To avoid calling a public method in the constructor, you've duplicated the code of startMusic(). Instead, invoke it after the constructor completes.
Here's an example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
import sun.audio.*;
public class Menu {
private static final String TITLE = "Battleship";
private static final String SOUND_FILE = "./battle.wav";
private javax.swing.JLabel image;
JFrame frame = new JFrame(TITLE);
JPanel center = new JPanel(new BorderLayout());
JLabel statusbar = new JLabel(TITLE);
JLabel battleship = new JLabel(TITLE, JLabel.CENTER);
static AudioPlayer MGP = AudioPlayer.player;
static AudioStream BGM;
static ContinuousAudioDataStream loop = null;
AudioData MD;
public Menu() {
frame.setTitle("Battleship");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
statusbar.setBorder(BorderFactory.createEtchedBorder(
EtchedBorder.RAISED));
battleship.setBorder(BorderFactory.createEtchedBorder(
EtchedBorder.RAISED));
JButton start = new JButton("Start");
JButton exit = new JButton("Exit");
JButton StopMusic = new JButton("Stop Music");
JButton StartMusic = new JButton("Start Music");
battleship.setFont(new Font("Courier New", Font.ITALIC, 36));
battleship.setForeground(Color.BLACK);
image = new JLabel();
image.setHorizontalAlignment(JLabel.CENTER);
image.setIcon(new ImageIcon("./battleship2.jpg"));
center.add(image, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(start);
panel.add(exit);
panel.add(StopMusic);
panel.add(StartMusic);
center.add(panel, BorderLayout.SOUTH);
frame.add(battleship, BorderLayout.NORTH);
frame.add(center, BorderLayout.CENTER);
frame.add(statusbar, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//frame.dispose();
stopMusic();
runPlayer();
}
});
StopMusic.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stopMusic();
}
});
StartMusic.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
startMusic();
}
});
exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Ending Game");
System.exit(0);
}
});
}
public void stopMusic() {
if (BGM != null) {
AudioPlayer.player.stop(BGM);
}
if (loop != null) {
AudioPlayer.player.stop(loop);
}
}
public void startMusic() {
try {
InputStream test = new FileInputStream(SOUND_FILE);
BGM = new AudioStream(test);
AudioPlayer.player.start(BGM);
MGP.start(loop);
} catch (FileNotFoundException e) {
System.out.print(e.toString());
} catch (IOException error) {
System.out.print(error.toString());
}
}
public static void runPlayer() {
Player client = new Player();
client.createBoard();
client.run();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Menu menu = new Menu();
menu.startMusic();
}
});
}
// stub for missing class
private static class Player {
void createBoard() {}
void run() {}
}
}