i have made a simple auto clicker, but when i run it the screen goes black so i cant stop it etc. i dont have a clue what i have done wrong. I thought maybe i had to set focus, but i am not sure.
Code:
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.UIManager;
import javax.swing.JRadioButton;
public class AutoClicker1 extends JFrame {
private JPanel contentPane;
private JTextField textField;
public static int rate;
public static boolean go = false;
public static int time;
public static int multiplyer;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AutoClicker1 frame = new AutoClicker1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public AutoClicker1() {
setTitle("Auto Clicker");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 361, 154);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNoOfClicks = new JLabel("Interval between clicks");
lblNoOfClicks.setBounds(10, 25, 149, 14);
contentPane.add(lblNoOfClicks);
textField = new JTextField();
textField.setBounds(10, 55, 139, 20);
contentPane.add(textField);
textField.setColumns(10);
JButton btnStopf = new JButton("Stop(F11)");
btnStopf.setBounds(203, 45, 89, 23);
contentPane.add(btnStopf);
JButton button = new JButton("Stop(F11)");
button.setBounds(203, 81, 89, 23);
contentPane.add(button);
final JRadioButton rdbtnSeconds = new JRadioButton("Seconds");
rdbtnSeconds.setBounds(6, 81, 65, 23);
contentPane.add(rdbtnSeconds);
final JRadioButton rdbtnMilliseconds = new JRadioButton("Milliseconds");
rdbtnMilliseconds.setBounds(71, 81, 109, 23);
contentPane.add(rdbtnMilliseconds);
btnStopf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
go = false;
}
});
JButton btnStart = new JButton("Start(F10)");
btnStart.setBounds(203, 11, 89, 23);
contentPane.add(btnStart);
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
go = true;
if (rdbtnMilliseconds.isSelected()) {
autoClick();
} else {
if (rdbtnSeconds.isSelected()) {
multiplyer = 1000;
autoClick();
}
}
}
});
}
private void autoClick() {
requestFocus();
rate = Integer.parseInt(textField.getText());
time = (rate * multiplyer);
System.out.print(time);
try {
Robot robot = new Robot();
while (true) {
try {
Thread.sleep(rate);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
} catch (InterruptedException ex) {}
}
} catch (AWTException e) {}
}
private void keyListner(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_F10) {
System.out.print("pressed F10");
go = true;
}
if (key == KeyEvent.VK_F11) {
go = false;
}
}
private void setTheme() {
try {
UIManager
.setLookAndFeel("com.seaglasslookandfeel.SeaGlassLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkRate() {
if (rate < 500) {
rate = 0;
}
}
}
You are blocking the Event Dispatch Thread in autoClick() with the while(true), instead of that you can use a Swing Timer.
I suggest not using keyListener for listen only 2 keys, you can use keybindings for that purpose. Also you shouldn't call directly setBounds rely in a proper LayoutManager to position in screen.
You break out of the program loop in your Main method when you enter the wile loop in your AutoClick method.
You could instead run your program in a "game loop".
In the main method what I would do is create a method called run()
public void run()
{
int FPS = 60;
float startTime = System.currentTimeInMillis();
while(started)
{
float currentTime = System.currentTimeInMillis();
float passedTime = currentTime - startTime;
startTime = System.currentTimeInMillis();
if(passedTime > (float) 1000/FPS)
{
update();
}
}
}
and then in the update method put the logic of the program. I know it is a totally different approach to how you are currently doing it but in my opinion it allows for more flexibility.
For example in your action listener you could have it invoke a "startClick()" method
where it sets a boolean value to true and initializes what you intialzie currently in the autoclick method. Then your update() method would look like this:
public void update()
{
if(boolean) //boolean value that startClick sets to true
{
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
}
This way the program isn't stuck in an infinite while-loop and you can control how often it updateswith the FPS variable.
Related
Hi so I have this template program and basically what I need to do is:
When the More Bricks button is pressed a new window opens. When that window there is a button in there and when that is pressed the brick variable should be reset and the label should be reset as well in the original window needs to be reset to its original number. How would I go about this?
This is the first class
import javax.swing.*;
import java.awt.event.*;
public class Brick {
private JFrame firstbricks;
int price = 0;
int bricks = 20;
public static void main(String[] args) {
Brick window = new Brick();
window.firstbricks.setVisible(true);
}
public Brick() {
firstbricks = new JFrame();
firstbricks.setBounds(0, 0, 272, 130);
firstbricks.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
firstbricks.getContentPane().setLayout(null);
JLabel lblBricks = new JLabel("20 remaining");
lblBricks.setBounds(20, 54, 128, 23);
firstbricks.getContentPane().add(lblBricks);
JButton btnBricks = new JButton("Bricks");
btnBricks.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
bricks--;
if (bricks <= 20) {
lblBricks.setText(bricks + " remaining");
price += 4;
}
}
});
btnBricks.setBounds(10, 11, 104, 32);
firstbricks.getContentPane().add(btnBricks);
JButton btnExtra = new JButton("More Bricks");
btnExtra.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
MoreBricks info = new MoreBricks();
}
});
btnExtra.setBounds(131, 11, 115, 32);
firstbricks.getContentPane().add(btnExtra);
}
}
And here is the second window class which I want the labels to be changed from:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MoreBricks {
private JFrame MoreBricks;
public MoreBricks() {
makeFrame();
}
private void makeFrame() {
MoreBricks = new JFrame();
MoreBricks.setBounds(100, 100, 156, 114);
MoreBricks.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
MoreBricks.getContentPane().setLayout(null);
MoreBricks.setVisible(true);
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
reset.setBounds(10, 11, 104, 34);
MoreBricks.getContentPane().add(reset);
}
}
Easy solution (but perhaps not the best), is MoreBricks constructor takes a Brick instance in as the constructor:
public class MoreBricks {
private JFrame MoreBricks;
private Brick _brick;
public MoreBricks(Brick b) {
_brick = brick;
makeFrame();
}
Then your Reset button just does something like the following:
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
MoreBricks.this._bricks.ResetBrickCount();
}
Ideally you have a "model" class in which all the state of your game (e.g. number of bricks) is encapsulated into a single class. Then whenever the model changes, all the dependent "views" are notified of the change and update themselves to reflect the right values and state on the screen.
I am currently making a very simple Java GUI application, but have run into the problem that my variables are unable to update. The application is a simple basketball scorekeeper and the score integers do not update nor does the text of the labels showing them. There are no errors so I am unsure as of why nothing is updating. The code:
ScoreWindow.java
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.SpringLayout;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.FlowLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class ScoreWindow implements ScoreListener {
private JFrame frmScorewindow;
public volatile JLabel homeScoreLabel;
public JLabel awayScoreLabel;
public volatile int homeScore, awayScore;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScoreWindow window = new ScoreWindow();
window.frmScorewindow.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ScoreWindow() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
// Init Scores
homeScore = 0;
awayScore = 0;
frmScorewindow = new JFrame();
frmScorewindow.setResizable(false);
frmScorewindow.setTitle("Score Keeper");
frmScorewindow.setBounds(100, 100, 551, 348);
frmScorewindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmScorewindow.getContentPane().setLayout(null);
JButton homeScore2 = new JButton("+2");
homeScore2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.homeScore(2);
}
});
homeScore2.setBounds(110, 129, 117, 29);
frmScorewindow.getContentPane().add(homeScore2);
JButton homeScore3 = new JButton("+3");
homeScore3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.homeScore(3);
}
});
homeScore3.setBounds(110, 156, 117, 29);
frmScorewindow.getContentPane().add(homeScore3);
JButton awayScore2 = new JButton("+2");
awayScore2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.awayScore(2);
}
});
awayScore2.setBounds(332, 129, 117, 29);
frmScorewindow.getContentPane().add(awayScore2);
JButton awayScore3 = new JButton("+3");
awayScore3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.awayScore(3);
}
});
awayScore3.setBounds(332, 156, 117, 29);
frmScorewindow.getContentPane().add(awayScore3);
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.reset();
}
});
resetButton.setBounds(225, 220, 117, 29);
frmScorewindow.getContentPane().add(resetButton);
homeScoreLabel = new JLabel("000");
homeScoreLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 24));
homeScoreLabel.setHorizontalAlignment(SwingConstants.CENTER);
homeScoreLabel.setBounds(138, 88, 61, 29);
frmScorewindow.getContentPane().add(homeScoreLabel);
awayScoreLabel = new JLabel("000");
awayScoreLabel.setHorizontalAlignment(SwingConstants.CENTER);
awayScoreLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 24));
awayScoreLabel.setBounds(361, 88, 61, 29);
frmScorewindow.getContentPane().add(awayScoreLabel);
JLabel lblHome = new JLabel("Home");
lblHome.setHorizontalAlignment(SwingConstants.CENTER);
lblHome.setBounds(138, 60, 61, 16);
frmScorewindow.getContentPane().add(lblHome);
JLabel lblAway = new JLabel("Away");
lblAway.setHorizontalAlignment(SwingConstants.CENTER);
lblAway.setBounds(361, 60, 61, 16);
frmScorewindow.getContentPane().add(lblAway);
JLabel title = new JLabel("Score Keeper App");
title.setHorizontalAlignment(SwingConstants.CENTER);
title.setBounds(180, 33, 200, 16);
frmScorewindow.getContentPane().add(title);
}
#Override
public void reset() {
print("reset();");
homeScore = 0;
awayScore = 0;
awayScoreLabel.setText("" + awayScore);
homeScoreLabel.setText("" + homeScore);
}
#Override
public void awayScore(int n) {
print("awayScore();");
awayScore+=n;
awayScoreLabel.setText("" + awayScore);
}
#Override
public void homeScore(int n) {
print("homeScore();");
print(homeScoreLabel.getText());
homeScore = homeScore + n;
homeScoreLabel.setText("" + homeScore);
homeScoreLabel.repaint();
homeScoreLabel.revalidate();
}
static void print(Object o) {
System.out.println(o);
}
}
ScoreListener.java
public interface ScoreListener {
public void reset();
public void awayScore(int n);
public void homeScore(int n);
}
Thank you!!
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScoreWindow window = new ScoreWindow();
window.frmScorewindow.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
You create your window with the above code.
JButton homeScore2 = new JButton("+2");
homeScore2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScoreListener listener = new ScoreWindow();
listener.homeScore(2);
}
});
But then you create a second instance of the window.
Don't do this. You only need to create once instance of your class. All other code to reference this instance.
Your ActionListner class is defined in the ScoreWindow class you you can just reference the "homeScore()" method directly.
So, I have got this problem in my Java Swing project where I am making a bot that automatically runs through a whileloop and outputs a text that the user can define in a textfield.
Here you can see my code for adding a textline into a jlabel into my frame:
btnAddTalking = new JButton("Add");
btnAddTalking.setBounds(144, 211, 146, 23);
btnAddTalking.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!txtTalk.getText().equals("")) {
JLabel newLabel = new JLabel(txtTalk.getText());
newLabel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent arg0) {
frame.remove(newLabel);
frame.repaint();
}
});
newLabel.setHorizontalAlignment(SwingConstants.CENTER);
newLabel.setBounds(159, yLabel, 101, 20);
frame.getContentPane().add(newLabel);
yLabel = yLabel + 20;
frame.getContentPane().setLayout(null);
frame.repaint();
Talk.addTalk(txtTalk.getText());
}
}
});
frame.getContentPane().add(btnAddTalking);
frame.getContentPane().add(lblNewLabel);
frame.getContentPane().add(lblDelayInMs);
After that I start my bot by pressing the following button:
btnStartTalking = new JButton("Start AutoTalk");
btnStartTalking.setBounds(144, 143, 146, 23);
btnStartTalking.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int robotDelay = Integer.parseInt(timeTalk.getText());
Talk.action = "start";
robotTalk = txtTalk.getText();
if (rdbtnRed.isSelected() == true) {
robotTalk = "red:" + txtTalk.getText();
} else if (rdbtnFlash.isSelected() == true) {
robotTalk = "flash1:" + txtTalk.getText();
} else if (rdbtnGlow.isSelected() == true) {
robotTalk = "glow1:" + txtTalk.getText();
}
autoTalkStart = new Runnable() {
public void run() {
try {
btnStartTalking.setEnabled(false);
btnStopTalking.setEnabled(true);
btnAddTalking.setEnabled(false);
Talk test = new Talk(robotDelay);
} catch (AWTException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
new Thread(autoTalkStart).start();
}
});
Via that button I start a thread which runs through a code that outputs the string. But after I've runned that Thread, my frame doesn't show newly-added jlabels anymore that you've added by clicking the btnAddTalking-button after you've run the Thread by clicking on the btnStartTalking-button! So, my question is: does anyone now how that's even possible (why my UI doesn't update anymore after i've run the thread)?
Greetz,
Jarnov
Here you can see my whole code for the two classes (class 1):
import java.awt.EventQueue;
import java.awt.event.InputEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import com.sun.glass.events.KeyEvent;
import com.sun.glass.ui.Robot;
import java.awt.AWTException;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JLabel;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.GroupLayout.Alignment;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import javax.swing.JRadioButton;
public class AutoTalker {
private static JFrame frame;
private JTextField txtTalk;
private JTextField timeTalk;
public String robotTalk;
private JButton btnStopTalking;
private JButton btnAddTalking;
private JButton btnStartTalking;
private int yLabel = 266;
private Runnable autoTalkStart;
/**
* Launch the application.
*/
public static void NewFrame() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AutoTalker window = new AutoTalker();
window.frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
* #return
*/
public AutoTalker() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 415);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("AutoTalker");
frame.getContentPane().setLayout(null);
JRadioButton rdbtnGlow = new JRadioButton("Glow");
rdbtnGlow.setBounds(6, 113, 64, 23);
rdbtnGlow.setActionCommand("glow");
frame.getContentPane().add(rdbtnGlow);
JRadioButton rdbtnFlash = new JRadioButton("Flash");
rdbtnFlash.setBounds(182, 113, 69, 23);
rdbtnGlow.setActionCommand("flash");
frame.getContentPane().add(rdbtnFlash);
JRadioButton rdbtnRed = new JRadioButton("Red");
rdbtnRed.setBounds(364, 113, 64, 23);
rdbtnGlow.setActionCommand("red");
frame.getContentPane().add(rdbtnRed);
final ButtonGroup rdbtnPressed = new ButtonGroup();
rdbtnPressed.add(rdbtnRed);
rdbtnPressed.add(rdbtnFlash);
rdbtnPressed.add(rdbtnGlow);
txtTalk = new JTextField();
txtTalk.setBounds(130, 28, 173, 20);
txtTalk.setColumns(10);
btnStopTalking = new JButton("Stop AutoTalk");
btnStopTalking.setBounds(144, 177, 146, 23);
btnStopTalking.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Talk.action = "stop";
btnStartTalking.setEnabled(true);
btnStopTalking.setEnabled(false);
btnAddTalking.setEnabled(true);
frame.repaint();
}
});
btnStartTalking = new JButton("Start AutoTalk");
btnStartTalking.setBounds(144, 143, 146, 23);
btnStartTalking.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int robotDelay = Integer.parseInt(timeTalk.getText());
Talk.action = "start";
robotTalk = txtTalk.getText();
if (rdbtnRed.isSelected() == true) {
robotTalk = "red:" + txtTalk.getText();
} else if (rdbtnFlash.isSelected() == true) {
robotTalk = "flash1:" + txtTalk.getText();
} else if (rdbtnGlow.isSelected() == true) {
robotTalk = "glow1:" + txtTalk.getText();
}
autoTalkStart = new Runnable() {
public void run() {
try {
btnStartTalking.setEnabled(false);
btnStopTalking.setEnabled(true);
btnAddTalking.setEnabled(false);
Talk test = new Talk(robotDelay);
} catch (AWTException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
new Thread(autoTalkStart).start();
frame.repaint();
}
});
timeTalk = new JTextField();
timeTalk.setBounds(174, 71, 86, 20);
timeTalk.setColumns(10);
JLabel lblNewLabel = new JLabel("Text:");
lblNewLabel.setBounds(24, 28, 46, 20);
JLabel lblDelayInMs = new JLabel("Delay in ms:");
lblDelayInMs.setBounds(24, 71, 101, 20);
frame.getContentPane().add(txtTalk);
frame.getContentPane().add(btnStartTalking);
frame.getContentPane().add(btnStopTalking);
frame.getContentPane().add(timeTalk);
btnAddTalking = new JButton("Add");
btnAddTalking.setBounds(144, 211, 146, 23);
btnAddTalking.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!txtTalk.getText().equals("")) {
JLabel newLabel = new JLabel(txtTalk.getText());
newLabel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent arg0) {
frame.remove(newLabel);
frame.repaint();
}
});
newLabel.setHorizontalAlignment(SwingConstants.CENTER);
newLabel.setBounds(159, yLabel, 101, 20);
frame.getContentPane().add(newLabel);
yLabel = yLabel + 20;
frame.getContentPane().setLayout(null);
frame.repaint();
Talk.addTalk(txtTalk.getText());
}
}
});
frame.getContentPane().add(btnAddTalking);
frame.getContentPane().add(lblNewLabel);
frame.getContentPane().add(lblDelayInMs);
btnStopTalking.setEnabled(false);
}
}
class 2:
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.ArrayList;
public class Talk extends AutoTalker {
Robot robot = new Robot();
public static String action;
public static ArrayList<String> Talks = new ArrayList<String>();
public Talk(int wait) throws AWTException, InterruptedException {
robot.delay(5000);
while(action == "start") {
for(int i = 0; i < Talks.size();i++) {
String text = Talks.get(i);
type(text);
robot.delay(wait);
}
}
}
public static void addTalk(String text) {
Talks.add(text);
}
private void type(String s)
{
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
switch(c) {
case '!':
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_1);
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_1);
break;
case ':':
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_SEMICOLON);
robot.keyRelease(KeyEvent.VK_SEMICOLON);
robot.keyRelease(KeyEvent.VK_SHIFT);
break;
default:
robot.keyPress(Character.toUpperCase(c));
break;
}
robot.delay(10);
}
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
robot.delay(10);
}
}
Use instead
invalidate();
validate();
I am trying to make a rubix cube timer for my friend. To start the timer you hold down space bar, and once you let go it starts. I am having a problem though, when I hold down the space bar the timer starts at whatever time it is. I want to be able to reset it to 0 but whenever I try to do that everything glitches out. Could anyone tell me how to fix it, or how to do this in a more efficient way? Thanks!
package dev.suns.rubix_timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class RubixTimerMain extends JFrame {
private JPanel contentPane;
private JLabel labelTimer;
private Timer timer;
public RubixTimerMain() {
createWindow();
}
public static void main(String[] args) {
new RubixTimerMain();
}
private void createWindow() {
// setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(Toolkit.getDefaultToolkit().getScreenSize());
setLocationRelativeTo(null);
setExtendedState(JFrame.MAXIMIZED_BOTH);
contentPane = new JPanel();
contentPane.setBackground(new Color(201, 77, 83));
contentPane.setLayout(null);
setContentPane(contentPane);
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
startTimer();
}
}
});
JLabel lblMinimize = new JLabel("-");
lblMinimize.setBounds(1835, -20, 16, 95);
lblMinimize.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
setState(JFrame.ICONIFIED);
}
#Override
public void mouseEntered(MouseEvent e) {
lblMinimize.setForeground(Color.BLACK);
}
#Override
public void mouseExited(MouseEvent e) {
lblMinimize.setForeground(Color.WHITE);
}
});
lblMinimize.setForeground(Color.WHITE);
lblMinimize.setFont(new Font("Segoe UI", Font.PLAIN, 40));
contentPane.add(lblMinimize);
JLabel lblX = new JLabel("X");
lblX.setBounds(1873, 0, 24, 54);
lblX.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
#Override
public void mouseEntered(MouseEvent e) {
lblX.setForeground(Color.BLACK);
}
#Override
public void mouseExited(MouseEvent e) {
lblX.setForeground(Color.WHITE);
}
});
lblX.setFont(new Font("Segoe UI", Font.PLAIN, 40));
lblX.setHorizontalAlignment(SwingConstants.CENTER);
lblX.setForeground(Color.WHITE);
contentPane.add(lblX);
labelTimer = new JLabel("0.0.0");
labelTimer.setHorizontalAlignment(SwingConstants.CENTER);
labelTimer.setFont(new Font("DINPro-Bold", Font.PLAIN, 200));
labelTimer.setForeground(Color.WHITE);
labelTimer.setBounds(371, 134, 1418, 653);
contentPane.add(labelTimer);
setVisible(true);
}
This is where I have the timer code. I have tried to reset cal to 0 in several different places but it is not working.
private void startTimer() {
new Thread()
{
public void run()
{
while(true)
{
Calendar cal = new GregorianCalendar();
int minutes = cal.get(Calendar.MINUTE);
int seconds = cal.get(Calendar.SECOND);
int milliseconds = cal.get(Calendar.MILLISECOND);
labelTimer.setText(minutes + "." + seconds + "." + milliseconds);
}
}
}.start();
}
}
In order to be able to stop the timer thread you need to have some means of communicating between the main thread and the timer thread. A synchronized member variable of the RubixTimerMain class can do that:
private Boolean isStopped = new Boolean(true);
Then you can add two methods. One stops the timer by setting the variable, the other one checks the current state of the variable.
private void stopTimer(){
synchronized(isStopped){
isStopped = true;
}
}
private boolean isTimerRunning(){
boolean result = false;
synchronized(isStopped){
result = !isStopped;
}
return result;
}
You will want to change the listener event of the space key (in createWindow) like this so that it starts and stops the timing:
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
if (isTimerRunning()){
stopTimer();
} else {
startTimer();
}
}
}
});
Finally you need to adapt your thread function so that it only runs if the stopped state variable is false. Notice that it uses the isTimerRunning method instead of directly accessing the variable. Also the error of displaying the wrong time is fixed by converting the value of the GregorianCalendar into milliseconds first, then subtracting the recorded start time from the current time.
private void startTimer() {
new Thread()
{
public void run()
{
long timeStart = new GregorianCalendar().getTimeInMillis();
synchronized(isStopped){
isStopped = false;
}
while(isTimerRunning())
{
long timeNow = new GregorianCalendar().getTimeInMillis() - timeStart;
long milliseconds = (timeNow % 1000);
timeNow = (long) Math.floor(timeNow * 0.001f);
long seconds = (timeNow % 60);
timeNow = (long)Math.floor((float)timeNow / 60f);
long minutes = timeNow;
labelTimer.setText(minutes + "." + seconds + "." + milliseconds);
}
}
}.start();
}
One problem may be that you're not interacting with labelTimer on the EDT (Event Dispatch Thread).
In Swing, all interactions with UI objects must happen on this thread.
What happens if you make sure your call to setText happens within an invocation of SwingUtilities#invokeLater: https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)
So here is my GUI as you can see.
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Frame1 {
private JFrame frame;
private JTextField textFieldnum1;
private JTextField textFieldnum2;
private JTextField textFieldAns;
private Termostat thermo;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Frame1 window = new Frame1();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Frame1() {
initialize();
}
private void initialize() {
thermo = new Termostat();
frame = new JFrame();
frame.setBounds(100, 100, 696, 250);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
textFieldnum1 = new JTextField();
textFieldnum1.setBounds(176, 11, 147, 46);
frame.getContentPane().add(textFieldnum1);
textFieldnum1.setColumns(10);
textFieldnum2 = new JTextField();
textFieldnum2.setBounds(176, 154, 147, 46);
frame.getContentPane().add(textFieldnum2);
textFieldnum2.setColumns(10);
JButton btnNewButton = new JButton("Convert to celcius");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
double myf = thermo.convertToCelcius(Double.parseDouble(textFieldnum1.getText()));
textFieldAns.setText(String.valueOf(myf));
}
});
btnNewButton.setBounds(0, 0, 171, 68);
frame.getContentPane().add(btnNewButton);
JButton btnNewButton_1 = new JButton("Convert to fahrenheit");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
textFieldAns.setText(String.valueOf(myf));
}
});
btnNewButton_1.setBounds(0, 143, 171, 68);
frame.getContentPane().add(btnNewButton_1);
textFieldAns = new JTextField();
textFieldAns.setBounds(354, 90, 147, 46);
frame.getContentPane().add(textFieldAns);
textFieldAns.setColumns(10);
JLabel lblNewLabel = new JLabel("Converted");
lblNewLabel.setBounds(285, 94, 112, 38);
frame.getContentPane().add(lblNewLabel);
}
}
And here comes my problem. When i made my class that i wanna run the input in to calculate celcius to fahrenheit, i dont want it to crash when i type anything else than numbers. but i cant get it to work so i need you guys help to get the try catch to work.
Im very thankful for all help i get.
import javax.swing.JOptionPane;
public class Termostat {
public double convertToCelcius(double input) {
double far = 0;
try {
far = (input - 32) * 5 / 9;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Wrong input");
return far;
}
return far;
}
public double convertToFahrenheit(double input) {
double cel = 1;
try {
cel = (input * 9 / 5) + 32;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Wrong input");
return cel;
}
return cel;
}
}
This is the line where you get probably an Exception:
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
So guard it with a NumberFormatException (parseDouble).
You can use the NumberUtil.isNumber(str) to check if the input is a number. Here is more information
you must use try catch when you want to parse text field texts to Double using this method Double.parseDouble(text)
write them them like this and remove your try catches inside your convertToFahrenheit and convertToCelcius methods
JButton btnNewButton_1 = new JButton("Convert to fahrenheit");
btnNewButton_1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
try { // start trying to parse input string to double
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
textFieldAns.setText(String.valueOf(myf));
} catch (NumberFormatException ex) { // catch the exception that you mentioned
JOptionPane.showMessageDialog(null, "Wrong input");
textFieldAns.setText("");
}
}
});