Java: Double-Click a JSlider to Reset - java

I have a JSlider that sets the speed of my metronome, from 40 - 200, where 120 is the default, in the middle.
When the user clicks the metronome button, the metronome plays at the speed displayed on the JSlider - the user drags the slider to the right, the speed of the metronome increases, and it decreases if they slide it to the left.
How do I add functionality so that if the user double-clicks on the JSlider button, it defaults back to 120 - in the middle?
Here is my code:
public Metronome() {
tempoChooser = new JSlider();
metronomeButton = new JToggleButton();
JLabel metText = new JLabel("Metronome:");
add(metText);
...
tempoChooser.setMaximum(200);
tempoChooser.setMinimum(40);
tempoChooser.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
tempoChooserStateChanged(evt);
}
});
add(tempoChooser);
...
}
private void tempoChooserStateChanged(javax.swing.event.ChangeEvent evt) {
final int tempo = tempoChooser.getValue();
if (((JSlider) evt.getSource()).getValueIsAdjusting()) {
setMetronomeButtonText(tempo);
} else {
processTempoChange(tempo);
}
}
thanks in advance!

This should help you out: http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
You need to read up on that and implement MouseListener. You can use int getClickCount() to count how many times the user has clicked, which will help you read double clicks.
Hope this helps!

Even though I dont see a question, my gues is you are looking for MouseListener.

Not simple job, you have to add javax.swing.Timer and listening if during fixed period Mouse cliked once or twice times, for example

I recently wrote something similar so I could differentiate between single and double left mouse-button clicks:
private Timer timer;
#Override
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1){
if (timer == null) {
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() { // timer expired before another click received, therefore = single click
this.cancel();
timer = null;
/* single-click actions in here */
}
}, (Integer) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval"));
}
else { // received another click before previous click (timer) expired, therefore = double click
timer.cancel();
timer = null;
/* double-click actions in here */
}
}
}

Related

JAVA SWING - Creating Animation using Swing Timer

I am trying to setup a program that enables the user to display a transition when clicking the next and previous button. When pressing next, the swing timer should trigger and start the animation. When transitioning, there should be a flag that states it is in the transition period. The Swing timer should fire once every tenth of a second and essentially last 1 second.
public class guiCreation {
static Timer timer;
static boolean flag = false;
private static void guiInterface() {
next.addActionListener(new ActionListener(){
timer = new Timer(1000, this);
public void actionPerformed(ActionEvent e){
nextGest();
}
});
//should go to the next tab
previous.addActionListener(new ActionListener(){
//if the list gets to the beginning, disable button
public void actionPerformed(ActionEvent e){
prevGest();
}
});
}
public static void nextGest() {
timer.start();
previous.setEnabled(true);
next.setEnabled(true);
//if the list gets to the end, disable button
if (cardLayout.isNextCardAvailable()) {
status.setText(" Next button has been clicked");
//System.out.println("This is the" + size);
cardLayout.next(cardPanel);
next.setEnabled(cardLayout.isNextCardAvailable());
}
}
public static void prevGest() {
if (cardLayout.isPreviousCardAvailable()) {
timer.start();
next.setEnabled(true);
previous.setEnabled(true);
status.setText(" Previous button has been clicked");
cardLayout.previous(cardPanel);
previous.setEnabled(cardLayout.isPreviousCardAvailable());
}
}
}
This: "The Swing timer should fire once every tenth of a second ..." -- does not agree with this: timer = new Timer(1000, this); Your Timer is firing once every second, not every 10th of a second.
Instead, you should:
Create a new Timer(100, ...), one that fires every 10th of a second
Store in an instance field the start time in msecs when the Timer begins (likely do this in your button's ActionListener)
Within the Timer's ActionListener get the current mSecs and use this to check the elapsed time
Stop the Timer via ((Timer) e.getSource()).stop(); once 1 full second has elapsed
No need for a flag, since all you need to do is to check if the Timer isn't null and if it .isRunning(). e.g., if (timer != null && timer.isRunning()) { -- then the animation is proceeding.
Unrelated suggestion:
Get out of the static world and into the instance world. You're programming in Java, a language that is built to use OOPs from the ground up, and you don't want to fight against the OOPs paradigm.

Make a seek bar for media player.

I am making a media player using JMF, I want to use my own control components
Can anyone please help me in making a seek bar for media player so that it can play song according to the slider position.
Just suggest me some logic, I can figure out the coding part afterwards
if(player!=null){
long durationNanoseconds =
(player.getDuration().getNanoseconds());
durationbar.setMaximum((int) player.getDuration().getSeconds());
int duration=(int) player.getDuration().getSeconds();
int percent = durationbar.getValue();
long t = (durationNanoseconds / duration) * percent;
Time newTime = new Time(t);
player.stop();
player.setMediaTime(newTime);
player.start();
mousedrag=true;
Here is the code. Now how can I make the slider move along with the song?
Slider works when I drag/click on it, but it doesn't move with the song.
The problem with using a slider for this is that when the slider position is moved programmatically, it fires events. When an event is fired on a slider, it typically means the app. has to do something, such as move the song position. The effect is a never ending loop. There is probably a way around this by setting flags and ignoring some events, but I decided to go a different way.
Instead I used a JProgressBar to indicate the location in the track, and a MouseListener to detect when the user clicks on a separate position. Update the progress bar use a Swing Timer that checks the track location every 50-200 milliseconds. When a MouseEvent is detected, reposition the track.
The bar can be seen in the upper right of this GUI. Hovering over it will produce a tool tip showing the time in the track at that mouse position.
You could use a JSlider.
You can learn more from the Slider tutorial
You don't have to revalidate the container in order to change the slider.
Use these lines each time a new player is created:
slider.setMinimum(0);
slider.setMaximum(duration);
slider.setValue(0);
new UpdateWorker(duration).execute();
where duration is the variable holding the duration of the song in seconds.
And here is the code (used as inner class) which updates the slider:
private class UpdateWorker extends SwingWorker<Void, Integer> {
private int duration;
public UpdateWorker(int duration) {
this.duration = duration;
}
#Override
protected Void doInBackground() throws Exception {
for (int i = 1; i <= duration; i++) {
Thread.sleep(1000);
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> chunks) {
slider.setValue(chunks.get(0));
}
}
Now the slider will move to the right until the end of the song.
Also note that unless you want to use a custom slider, JMF provides a simple (and working) slider via player.getVisualComponent() (see this example).
UPDATE
In order to pause/resume the worker thread (and thus the slider and the song), here is an example with a button that sets the appropriate flags.
private boolean isPaused = false;
JButton pause = new JButton("Pause");
pause.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getSource();
if (!isPaused) {
isPaused = true;
source.setText("Resume");
} else {
isPaused = false;
source.setText("Pause");
}
}
});
The method doInBackground should be changed to something like that:
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i <= duration; i++) {
if (!isPaused) {
publish(i);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
while (isPaused) {
try {
Thread.sleep(50);
continue;
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
Modify it accordingly to pause/resume the song along with the slider.
You should also consider #AndrewThompson's answer.

Flashing color of a JTextField

I have a JTextField that is cleared if it has invalid content. I would like the background to flash red one or two times to indicate to the user that this has happened. I have tried:
field.setBackground(Color.RED);
field.setBackground(Color.WHITE);
But it is red for such a brief time that it cannot possibly be seen. Any tips?
The correct solution, almost arrive at by just eric, is to use a Swing Timer, since all the code in the Timer's ActionListener will be called on the Swing event thread, and this can prevent intermittent and frustrating errors from occurring. For example:
public void flashMyField(final JTextField field, Color flashColor,
final int timerDelay, int totalTime) {
final int totalCount = totalTime / timerDelay;
javax.swing.Timer timer = new javax.swing.Timer(timerDelay, new ActionListener(){
int count = 0;
public void actionPerformed(ActionEvent evt) {
if (count % 2 == 0) {
field.setBackground(flashColor);
} else {
field.setBackground(null);
if (count >= totalCount) {
((Timer)evt.getSource()).stop();
}
}
count++;
}
});
timer.start();
}
And it would be called via flashMyField(someTextField, Color.RED, 500, 2000);
Caveat: code has been neither compiled nor tested.
You need to extend public class Timer
Do it like so:
private class FlashTask extends TimerTask{
public void run(){
// set colors here
}
}
You can set Timer to execute in whatever intervals you prefer to create the flashing effect
From documentation:
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
Schedules the specified task for repeated fixed-rate execution, beginning after the specified delay.

Multiple swing timers

I have (what should be) a simple problem to tackle and I'm open to other ways to solve it. I am open to other solutions.
The problem:
We are using java swing to display the graphics of a turn-based, tile-based game. I'm using jlabels with icons, absolutely positioned.
To animate the movement, I am using a swing timer that updates the location by 4 pixels at a time, slowly moving the sprite right, left, etc.
To achieve this initially, I was running a timer, which works wonderfully. The problem comes in when I try to move down, then move right.
The sprite moves down, never moves right, and if I watch the execution with some console printing, it's clear to see that both timers are running at the same time. I've done a fair amount of digging on the internet and I wasn't able to find a way to tell a swing timer not to execute until the first timer has stopped, and if I try to busy-wait until one timer finishes (yuck) the UI never displays at all (clearly a step in the wrong direction.)
Now I can convert away from timers altogether and either have the sprite teleport to its new location, or use some awful busy-wait movement scheme, but I'm hoping some kind soul has a solution.
In short: I need a way to run a swing timer for a set period of time, stop it, and then start a new timer, so that they do not overlap. Preferably this method would allow each timer to be in its own method, and I could then call the methods one after the other.
Thanks in advance for any advice you might have.
Edit: Expanded example code. If a full scsse is a requirement for your advice then I'm sorry to have wasted your time, because the full code is a beast. This sample code does not work at all as it stands, sorry, but it should illustrate the point.
So. We have two functions, each with a timer that runs an animation cycle, one for moving down and right diagonally, one for moving straight down.
public class TestClass {
static int counter = 0;
static int counter2 = 0;
static Timer timerC;
static Timer timerX;
public static void main(String[] args) {
moveC();
moveX();
}
public static void moveC() {
int delay = 200; // milliseconds
timerC = new Timer(delay, null);
timerC.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (counter < 32) {
counter = counter + 4;
System.out.println("*C*");
} else {
timerC.stop();
System.out.println("*C STOP*");
}
}
});
timerC.start();
}
public static void moveX() {
int delay = 200; // milliseconds
timerX = new Timer(delay, null);
timerX.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (counter < 32) {
counter = counter + 4;
System.out.println("*X*");
} else {
timerX.stop();
System.out.println("*X STOP*");
}
}
});
timerX.start();
}
}
What I would want to see here eventually would be
*C*
*C*
*C*
*C*
*C STOP*
*X*
*X*
*X*
*X*
*X STOP*
What I actually get is
*C*
*X*
*C*
*X*
*C*
*X*
*C*
*X*
*C STOP*
*X STOP*
The point I'm trying to get at here is running one animation cycle to completion, then the other.
Thanks again.
Don't use multiple Timers, but rather only one Timer that deals with each direction as it's needed. You need some type of queue to hold the direction information, either a formal queue or a collection that you use as a queue (first in, first out), and then have your Timer extract the direction from this queue as it's running. For example, here I use my JList's model as my queue by removing and using the Direction that was added first (at the top of the JList):
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class TimerPlay extends JPanel {
private DefaultListModel directionJListModel = new DefaultListModel();
private JList directionJList = new JList(directionJListModel);
JButton startTimerButton = new JButton(
new StartTimerBtnAction("Start Timer"));
public TimerPlay() {
ActionListener directionBtnListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent actEvt) {
String actionCommand = actEvt.getActionCommand();
Direction dir = Direction.valueOf(actionCommand);
if (dir != null) {
directionJListModel.addElement(dir);
}
}
};
JPanel directionBtnPanel = new JPanel(new GridLayout(0, 1, 0, 10));
for (Direction dir : Direction.values()) {
JButton dirBtn = new JButton(dir.toString());
dirBtn.addActionListener(directionBtnListener);
directionBtnPanel.add(dirBtn);
}
add(directionBtnPanel);
add(new JScrollPane(directionJList));
add(startTimerButton);
}
private class StartTimerBtnAction extends AbstractAction {
protected static final int MAX_COUNT = 20;
public StartTimerBtnAction(String title) {
super(title);
}
#Override
public void actionPerformed(ActionEvent arg0) {
startTimerButton.setEnabled(false);
int delay = 100;
new Timer(delay, new ActionListener() {
private int count = 0;
private Direction dir = null;
#Override
public void actionPerformed(ActionEvent e) {
if (count == MAX_COUNT) {
count = 0; // restart
return;
} else if (count == 0) {
if (directionJListModel.size() == 0) {
((Timer)e.getSource()).stop();
startTimerButton.setEnabled(true);
return;
}
// extract from "queue"
dir = (Direction) directionJListModel.remove(0);
}
System.out.println(dir); // do movement here
count++;
}
}).start();
}
}
private static void createAndShowGui() {
TimerPlay mainPanel = new TimerPlay();
JFrame frame = new JFrame("TimerPlay");
frame.setDefaultCloseOperation(JFrame.EXIT_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();
}
});
}
}
enum Direction {
UP, DOWN, LEFT, RIGHT;
}
For reference, this example manages four instances of Timer, two of which run (interleaved) while hovering in any corner. You might compare it to your approach. This related answer discusses animation in a similar tile-based game.
put all Icons in some form of array
create a single Swing Timer with a short delay
in Swing ActionListener, take each `Icon from the array, getBounds from screen, move Icon one step
repeat until target reached.

Stopping a Swing timer until the user clicks

I'm writing a card game. Right now I'm having problems with mouse handling. Below is the timer that handles the game flow of drawing and discarding cards.
final Timer timer = new Timer(1000, null);
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.players[p].drawCard();
if(p==0) // player zero is the human player
{
timer.stop();
// ...
b.players[p].discardCard(i);
timer.start();
}
else
b.players[p].discardCard(0);
p=(p+1)%4;
b.repaint();
}
});
The thing is that I want to stop the timer, wait until the user clicks the card he wants to discard, then start the timer again. b implements MouseListener in a basic way:
public void mouseClicked(MouseEvent arg0)
{
clickX = arg0.getX();
clickY = arg0.getY();
}
There's also the xYtoCardIndex() method somewhere out there.
What do I do here? I assume I have to do nothing in a nonblocking way, right?
In pseudo-code, in your MouseEventListener :
public void mouseClicked(MouseEvent arg0)
{
clickX = arg0.getX();
clickY = arg0.getY();
Card discarded = getCard(clickX,clickY);
b.players[p].discardCard(discarded);
// The card has been discarded, I can start my timer again.
timer.start();
}
In your drawCard function :
public void drawCard() {
// Stop the timer
timer.stop();
// Do the drawing.
}
This way, when the player draws a card, the timer stops until a card is discarded.
First, your code is not compiled:
b.players[p].discardCard(int i); contains a syntax error int i.
Second, I do not really understand the problem. Stop the timer when you want, implement your listener (i.e. mouse listener) that starts the timer.
Or probably I did not understand your question?
BTW I have just checked Timer API. It does not have neither start nor stop methods. You have to deal with specific tasks to control execution.

Categories