The class is called operating systems and I have to make a simulated clock that reads information at certain time and does something with it but I am only asking about the clock part here. Right now, I have 4 buttons which are run, tick, read, and show status. I have an input, an output, and a timer text field. I have a clockstarter class that starts the clock when the program starts and writes it in the console. I'm supposed to have two threads so that while that is happening I can click "run" and the timer textfield starts continuously counting or if run is not clicked, I can manually add time with tick. I need help getting it to show in the text field.
public class ClockStarter implements Runnable {
private Thread thread;
private int currentTime;
private javax.swing.JTextField time;
public ClockStarter(javax.swing.JTextField t){
System.out.println("Clock Starter Constructor");
currentTime = -1;
time = t;
thread = new Thread(this);
thread.start();
}
public void run(){
while(true){
incrementTime();
System.out.println("Clock Starter Current Time ");
time = ("" + getCurrentTime());// I need to fix this line
try{Thread.sleep(1000);} catch(Exception e){}
}
}
public void incrementTime(){
currentTime++;
}
public int getCurrentTime(){
return currentTime;
}
}
Do not use Thread.sleep() as it will freeze your Swing application.
Instead you should use a javax.swing.Timer.
See the Java tutorial How to Use Swing Timers and Lesson: Concurrency in Swing for more information and examples.
Please read the Swing tutorial How to Use Text Fields:
A text field is a basic text control that enables the user to type a small amount of text. When the user indicates that text entry is complete (usually by pressing Enter), the text field fires an action event. If you need to obtain more than one line of input from the user, use a text area.
Example Code
/* TextDemo.java requires no other files. */
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TextDemo extends JPanel implements ActionListener {
protected JTextField textField;
protected JTextArea textArea;
private final static String newline = "\n";
public TextDemo() {
super(new GridBagLayout());
textField = new JTextField(20);
textField.addActionListener(this);
textArea = new JTextArea(5, 20);
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
//Add Components to this panel.
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(scrollPane, c);
}
public void actionPerformed(ActionEvent evt) {
String text = textField.getText();
textArea.append(text + newline);
textField.selectAll();
//Make sure the new text is visible, even if there
//was a selection in the text area.
textArea.setCaretPosition(textArea.getDocument().getLength());
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add contents to the window.
frame.add(new TextDemo());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Related
Im creating a programme using java. I want the user to enter some text, then push the button so the text entered shows in the label. However, I have 2 problems. First, the text are isn´t displaying when I execute the app. Second, I don´t know how to allow the user to type in the area. Im new in java so that´s why Im asking. Here is the code. Thank you.
import javax.swing.*;
import java.awt.event.*;
class Boton extends JFrame implements ActionListener {
JButton boton;
JTextArea textArea = new JTextArea();
JLabel etiqueta = new JLabel();
public Boton() {
setLayout(null);
boton = new JButton("Escribir");
boton.setBounds(100, 150, 100, 30);
boton.addActionListener(this);
add(boton);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boton) {
try {
String texto = textArea.getText();
etiqueta.setText(texto);
Thread.sleep(3000);
System.exit(0);
} catch (Exception excep) {
System.exit(0);
}
}
}
}
public class Main{
public static void main(String[] ar) {
Boton boton1 =new Boton();
boton1.setBounds(0,0,450,350);
boton1.setVisible(true);
boton1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Problems:
You never add the JTextArea into your GUI, and if it doesn't show, a user cannot directly interact with it.
You are calling Thread.sleep on the Swing event thread, and this will put the entire application to sleep, meaning the text that you added will not show.
Other issues include use of null layouts and setBounds -- avoid doing this.
Solutions:
Set the JTextArea's column and row properties so that it sizes well.
Since your JTextArea's text is going into a JLabel, a component that only allows a single line of text, I wonder if you should be using a JTextArea at all. Perhaps a JTextField would work better since it allows user input but only one line of text.
Add the JTextArea to a JScrollPane (its viewport actually) and add that to your GUI. Then the user can interact directly with it. This is most easily done by passing the JTextArea into a JScrollPane's constructor.
Get rid of the Thread.sleep and instead, if you want to use a delay, use a Swing Timer. check out the tutorial here
For example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Main2 {
public static void main(String[] args) {
// create GUI in a thread-safe manner
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
BotonExample mainPanel = new BotonExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class BotonExample extends JPanel {
private JLabel etiqueta = new JLabel(" ");
private JButton boton = new JButton("Escribir");
// jtext area rows and column properties
private int rows = 5;
private int columns = 30;
private JTextArea textArea = new JTextArea(rows, columns);
public BotonExample() {
// alt-e will activate button
boton.setMnemonic(KeyEvent.VK_E);
boton.addActionListener(e -> {
boton.setEnabled(false); // prevent button from re-activating
String text = textArea.getText();
etiqueta.setText(text);
// delay for timer
int delay = 3000;
Timer timer = new Timer(delay, e2 -> {
// get current window and dispose ofit
Window window = SwingUtilities.getWindowAncestor(boton);
window.dispose();
});
timer.setRepeats(false);
timer.start(); // start timer
});
// create JPanels to add to GUI
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
topPanel.add(new JLabel("Etiqueta:"));
topPanel.add(etiqueta);
JPanel bottomPanel = new JPanel();
bottomPanel.add(boton);
JScrollPane scrollPane = new JScrollPane(textArea);
// use layout manager and add components
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
}
textarea.setText("Text"); // this will insert text into the text area
textarea.setVisable(true); // this will display the text area so you can type in it
textarea.setSize(500,500); // set size of the textarea so it actually shows
The user should be able to type in the TA when it is displayed and just do a getText to pull the text
I don't have a lot of experience with KeyListeners but I used one in my application and it works fine except I need to wait for input before my program can continue. For this I made a while loop that loops until the String temp is not null (which would mean there would be input).
The problem is there is no way to type in the JTextField (called input). Below is code from my two methods that are supposed to work together so that the text in my JTextField (input) can be returned (as temp). I'm not sure why this doesn't work or how to fix it.
The keyPressed method for my KeyListener:
public void keyPressed(KeyEvent e)
{
//only sends text if the enter key is pressed
if (e.getKeyCode()==KeyEvent.VK_ENTER)
{
//if there really is text
if (!input.getText().equals(""))
{
//String temp is changed from null to input
temp=input.getText();
//text sent to another JTextField
output.append(temp+"\n");
//input no longer has text
input.setText("");
}
}
}
The method thats trying to get text, also in my KeyListener class
public String getTemp()
{
booleans isNull=temp==null;
//loops until temp is not null
while (isNull)
{
//unnecessary line of code, only used so the loop not empty
isNull=checkTemp();
}
return temp;
}
public boolean checkTemp()
{
return temp==null;
}
Your while loop is a common console program construct, but understand that you're not creating a console program here but rather an event-driven GUI, and in this situation, the while loop fights against the Swing GUI library, and you need to get rid of it. Instead of a while loop with continual polling you now want to respond to events, and if you're listening for user input into a JTextField do not use a KeyListener as this low-level listener can cause unwanted side effects. Instead add a DocumentListener to the JTextField's Document.
Edit: You're listening for the enter key, and so the solution is even easier: add an ActionListener to the JTextField!
e.g.,
input.addActionListener(e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
});
More complete example:
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ChatBox extends JPanel {
private static final int COLS = 40;
private JTextField input = new JTextField(COLS);
private JTextArea output = new JTextArea(20, COLS);
private JButton submitButton = new JButton("Submit");
public ChatBox() {
output.setFocusable(false); // user can't get into output
JScrollPane scrollPane = new JScrollPane(output);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
ActionListener inputListener = e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
input.requestFocusInWindow();
};
input.addActionListener(inputListener);
submitButton.addActionListener(inputListener);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
bottomPanel.add(input);
bottomPanel.add(submitButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
ChatBox mainPanel = new ChatBox();
JFrame frame = new JFrame("Chat Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This question already has answers here:
Java swing GUI freezes
(5 answers)
Closed 7 years ago.
I have some Java classes that should simulate an old calculating machine. One of them is a JFrame, called GUI, with a JTabbedPane. The calculating process should take some time, so I have included Thread.sleep(int). The problem is that while the calculating function is working, the tabs of the JTabbedPane in my GUI can't be selected.
Here is some code:
import java.util.*;
import java.awt.*;
public class Engine
{
private GUI gui;
private Store store;
private Mill mill;
public static void main(String[] args) {
Engine e = new Engine();
}
public Engine() {
gui = new GUI(this);
mill = new Mill(this);
store = new Store(this);
store.draw(); // affects GUI elements
}
public void read(String operations) {
clearStatus(); // affects GUI elements
try {
String[] op = operations.split("\n");
for (int i = 0; i < op.length; i++) {
setStatus(op[i]); // affects GUI elements
if (op[i].length() == 0) { // empty line
continue;
}
int number = Integer.parseInt(op[i]);
store.addNumber(number);
Thread.sleep(200);
}
store.draw(); // affects GUI elements
} catch(Exception e) {
System.out.println(e);
}
}
public void clearStatus() {
gui.statusLabel.setText("");
}
public void setStatus(String msg) {
gui.statusLabel.setText(msg);
}
}
Here's my GUI (this is a short version):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUI extends JFrame
{
private Engine engine;
// Swing
JTabbedPane tabs;
JPanel mill;
JTextArea input, store;
JLabel statusLabel;
JButton sendInput;
public GUI(Engine e)
{
engine = e;
input = new JTextArea();
sendInput = new JButton("Run");
sendInput.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pressInputButton(evt);
}
});
JPanel inputPanel = new JPanel();
inputPanel.add(input, BorderLayout.CENTER);
inputPanel.add(sendInput, BorderLayout.SOUTH);
mill = new JPanel();
statusLabel = new JLabel();
mill.add(statusLabel);
store = new JTextArea();
JTextPane helpPane = new JTextPane();
helpPane.setText("[...]");
tabs = new JTabbedPane();
tabs.addTab("Input", inputPanel);
tabs.addTab("Mill", mill);
tabs.addTab("Store", new JScrollPane(store));
tabs.addTab("Help", helpPanel);
add(tabs, BorderLayout.CENTER);
setVisible(true);
pack();
}
public void pressInputButton(ActionEvent evt) {
engine.read(input.getText());
}
}
What #sorifiend means is, calling sleep() from an event handler will "lock up" your application's event dispatch thread. The application will not respond to any other user input until the event handler function returns.
If you want the application to be responsive while the calculator is "working", then what you need to do is:
Record that the state of the calculator is "working"
Disable whatever buttons you don't want the user to press while the calculator is "working", --OR-- change the handlers for those buttons to do something different (simulate jamming the machine?) if they are pressed while in the "working" state.
Submit a timer event for some time in the near future (however long the calculation is supposed to take.)
In the handler for the timer event, display the result of the calculation, re-enable the disabled buttons, and change the state from "working" back to "idle" (or whatever).
so I am trying to make a small java program to count the number of characters in a given string.
Right now, my code works in the console output, but it is not updating the text field I have created in a JFrame and I am unsure why. Can someone please explain this to me?
BTW: I have set "onPress" to true, so the button doesn't really have an effect right now, I'm just trying to test the functionality of the program before I implement button functionality.
Thank you :)! Here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class characterCounterTwov2 extends JFrame {
static boolean onPress = true;
public characterCounterTwov2(){
/*******************/
/* Local Variables */
/*******************/
//creates a new Jframe to put our frame objets in
JFrame frame = new JFrame();
//creates a text field frame object
JTextField txtField = new JTextField("Enter your text here", 25);
//stores the string of the the jtextfield into a variable text
String text = txtField.getText();
//creates a text field that is uneditable with the word "characters"
String charString = "Characters: ";
JTextField charField = new JTextField(charString, 25);
charField.setEditable(false);
//integer to count the characters
int charCounter = 0;
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(charCounter);
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
//calculate button
JButton calcButton = new JButton("Calculate");
calcButton.addActionListener(new calcButtonFunc());
/*******************/
/* Frame Setup */
/*******************/
//sets the layout of the frame
frame.setLayout(new BorderLayout());
//add's elements to the frame
frame.add(txtField, BorderLayout.NORTH);
frame.add(charField, BorderLayout.CENTER);
frame.add(charFieldTwo, BorderLayout.SOUTH);
frame.add(calcButton, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//begin while loop
//infinite while loop
System.out.println("Entering main while loop");
while(true)
{
while(onPress == true)
{
System.out.println("text length is:" + charCount);
for(int i = 0; i < text.length(); i++)
{
charCounter++;
System.out.println("Number of characters:" + charCounter);
}
//charCount = Integer.toString(charCounter);
onPress = false;
}
}
}
static class calcButtonFunc implements ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent event)
{
onPress = true;
}
}
public static void main(String[] args){
new characterCounterTwov2();
System.out.println("End of program. Should not get here");
}
}
~~~~~~~~~
EDIT
I was given a lot of helpful tips by Hovercraft Full of Eels, and cleaned up my code. I am still having a problem with calculating the character count on button press, and having it reflect in the GUI. I am thinking my bug lies within the line "text = txtField.getText();" inside my button listener class.
Here is my updated code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class characterCounterTwov4{
//creates a new Jframe to put our frame objets in
JFrame frame = new JFrame();
//creates a text field frame object
JTextField txtField = new JTextField(25);
//stores the string of the the jtextfield into a variable text
String text = txtField.getText();
//creates a text field that is uneditable with the word "characters"
String charString = "Characters: ";
JTextField charField = new JTextField(charString, 25);
public characterCounterTwov4(){
charField.setEditable(false);
//integer to count the characters
int charCounter = 0;
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(text.length());
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
//calculate button
JButton calcButton = new JButton("Calculate");
calcButton.addActionListener(new ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent event)
{
System.out.println("button pressed");
//stores the string of the the jtextfield into a variable text
text = txtField.getText();
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(text.length());
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
}
});
/*******************/
/* Frame Setup */
/*******************/
//sets the layout of the frame
frame.setLayout(new BorderLayout());
//add's elements to the frame
frame.add(txtField, BorderLayout.NORTH);
frame.add(charField, BorderLayout.CENTER);
frame.add(charFieldTwo, BorderLayout.SOUTH);
frame.add(calcButton, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args){
new characterCounterTwov4();
System.out.println("End of program. Should not get here");
}
}
Your code is not structured for correct Swing GUI event-driven programming but rather looks like a linear console program that is being shoe-horned into a GUI. Get rid of that while loop, get rid of that static boolean variable. Instead give your class a non-static (instance) int counter variable and a JTextField non-static variable and simply increment your counter in the actionPerformed method and display the results in the JTextField (or JLabel if you prefer).
So the actionPerformed could look something like:
public void actionPerformed(ActionEVent e) {
counter++; // increment the counter variable
charCount.setText("Count: " + counter); // display the results
}
and again, counter and charCount are non-static and are declared and initialized in the class, not inside of the constructor or any method.
Edit
Additional notes:
Why does your class extend JFrame when you don't use it as a JFrame?
In general, it's a good idea to start all Swing proggrams on the Swing Event Dispatch Thread or EDT. This can be done by passing a Runnable with your start-up code in it to the SwingUtilities static method invokeLater(...).
For example:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
// create and display your GUI from in here
MainGui mainGui = new MainGui();
JFrame mainFrame = new JFrame("Main GUI");
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.add(mainGui);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
Edit 2
Oops, I read your requirements wrong. You need to count the chars in a String, and so you will need another class instance JTextField, one to hold the user's String, get rid of the counter instance field since it no longer will be needed, and then in the actionPerformed method, simply get the String from the JTextField, get its length, and display the length in another JTextField or in a JLabel, again your choice.
Edit 3
Your code is now almost there!
Problems:
The charFieldTwo variable is a non-final local variable. To be able to use it in your anonymous inner class, either make it final, and note that doing this won't harm its ability to work since it is a reference variable, not a primite,
Or you could move its declaration out of the constructor, like you do the other variables.
Once you've done this, it is easy to call charFieldTwo.setText(charCount); on it at the bottom of your ActionListener, and you're pretty much done.
I am writing a wizard of sorts and would like to switch what is displayed using methods. Every time I run this code I get a null pointer exception.
public class EventDispatch {
public static void main(String [] args){
WizardScreen wiz = new WizardScreen();
new Thread(wiz).start();
wiz.welcomeScreen();
}
}
public class WizardScreen implements Runnable{
protected JFrame wizardFrame;
protected JPanel contentPane;
protected JButton newQuote;
protected JButton openQuote;
protected JLabel title;
GridBagConstraints c;
public WizardScreen(){
wizardFrame = new JFrame();
contentPane = new JPanel(new GridBagLayout());
wizardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wizardFrame.setSize(550, 450);
wizardFrame.setResizable(false);
wizardFrame.setLocationRelativeTo(null);
wizardFrame.setTitle("Welcome!");
wizardFrame.setContentPane(contentPane);
wizardFrame.setVisible(true);
}
#Override
public void run() {
System.out.println("Running wizardScreen");
}
public void welcomeScreen(){
title = new JLabel("Welcome to ExSoft Quote Calculator Alpha 1.0");
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = .5;
contentPane.add(title, c);
wizardFrame.validate();
contentPane.repaint();
}
}
What am I doing wrong?
Take a walk through your code...
First, you create an instance of WizardScreen this initialises
wizardFrame
contentPane
Second, you start a Thread...
Third, you call welcomeScreen on the instance of WizardScreen, this initialises...
title
It then tries to access the gridx property of c...which hasn't yet been initialised...
You should have checked the information that the NullPointerException was giving you...
Exception in thread "main" java.lang.NullPointerException
at eventdispatch.EventDispatch$WizardScreen.welcomeScreen(EventDispatch.java:52)
at eventdispatch.EventDispatch.main(EventDispatch.java:20)
It clear states where the exception occurred, this is invaluable information both to you and us.
Beware, Swing is not thread safe, all interactions and modifications to the UI are expected to occur from within the context of the Event Dispatching Thread. See Concurrency in Swing
FYI:
It's generally advisable to use pack of setSize, which should be done last, right before you call setVisible. Also beware, that using setResizable(false) changes the size of the window...
wizardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//wizardFrame.setSize(550, 450);
//wizardFrame.setResizable(false);
//wizardFrame.setLocationRelativeTo(null);
wizardFrame.setTitle("Welcome!");
wizardFrame.setContentPane(contentPane);
wizardFrame.setResizable(false);
wizardFrame.pack();
wizardFrame.setLocationRelativeTo(null);
wizardFrame.setVisible(true);