I have a program that processes some files. From time to time, I need to stop it in the middle of processing, but am having difficulty with how to accomplish that. I have seen several possibilities, but I'm not sure which to pursue. Is it multithreading, like in a game? I found some information on cancelling, but it seems like it only applies while data is being inputted? I'm including the code for my gui below as maybe I just did something wrong?
To be clear, the goal is to stop the program no matter where it is in processing...
private JRadioButton blockButton, unblockButton;
private JButton btnCancel;
private ButtonGroup group;
private JLabel text;
private JButton enter;
public Gui(){
super("Download CORS files");
setLayout(null);
text = new JLabel("Would you like to download data in a block of days or intermittently over time?");
add(text);
blockButton = new JRadioButton("Block of Days", true);
unblockButton = new JRadioButton("Intermittent Days", false);
btnCancel = new JButton("Cancel run");
add(blockButton);
add(unblockButton);
add(btnCancel);
group = new ButtonGroup();
group.add(blockButton);
group.add(unblockButton);
// Get the size of the screen
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
// Determine the new location of the window
int w = this.getSize().width;
int h = this.getSize().height;
int x = ((dim.width-w)/2)-200;
int y = ((dim.height-h)/2)-200;
// Move the window
this.setLocation(x, y);
enter = new JButton("Enter");
enter.addActionListener(this);
add(enter);
text.setBounds(5,5,700,25);
blockButton.setBounds(5, 25, 300, 25);
unblockButton.setBounds(5,50, 300, 25);
enter.setBounds(75,100,100,20);
btnCancel.setBounds(300,100,100,20);
btnCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
Two ways to stop processing, depending on the situation
Stop processing I/O: If you need to break out of an I/O process, IMO the best way to do this is to close the Stream(s), especially for Reader threads. You may get an IOException thrown, but this is what Exceptions are for
Intense computation/processing: If you want to stop an intense processing loop, you should call Thread.interrupt() on the processing Thread. If you have written the processing code, you can check on Thread.interrupted() status somewhere in your loop/code. On the other hand, if you are using 3rd party code, this may or may not work
Related
This question already has answers here:
Java - checking if parseInt throws exception
(8 answers)
Closed 1 year ago.
So I tried to look a bit in forums and StackOverflow but nothing worked for me I need when enter is pressed to stop my code this is my code `
JFrame f;
JTextField I;
// JButton
JToggleButton b;
// label to display text
JLabel l;
f = new JFrame("AutoClicker");
i = new JTextField("100");
// create a label to display text
l = new JLabel("clicks/seconds");
// create a new buttons
b = new JToggleButton("Start");
// create a panel to add buttons
JPanel p = new JPanel();
// add buttons and textfield to panel
p.add(b);
p.add(i);
p.add(l);
// setbackground of panel
p.setBackground(Color.red);
// add panel to frame
f.add(p);
// set the size of frame
f.setSize(280, 80);
f.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int jml = Integer.parseInt(i.getText());
if(jml < 50)
{
jml = 50;
}
AutoClicker(jml);
}
});
}
static void AutoClicker(int jml)
{
while(true)
{
try{
Robot r = new Robot();
int button = InputEvent.BUTTON1_DOWN_MASK;
r.mousePress(button);
Thread.sleep(jml);
r.mouseRelease(button);
Thread.sleep(jml);
}
catch(Exception e){
e.printStackTrace();
System.out.println("not good");
}
}
}
}`
I tried to add a KeyListener but it did not work.
I don't understand why it doesn't work so if you can just help me know why it doesn't work it would be much apreciated.
KeyListener isn't going to solve the problem of the fact that you are simply not handling the potential of Integer.parseInt to throw an exception - I mean, how can it convert "" or "This is not a number" to an int. In those cases it throws an exception
The JavaDocs clearly state
Throws:NumberFormatException - if the string does not contain a
parsable integer.
Go back and have a look at the original error you were getting from your previous question on this exact topic
java.lang.NumberFormatException: For input string: "Enter"
It's telling you exactly what the problem is - the text "Enter" can not be converted to an int value.
YOU have to handle this possibility. No offence, but this is honestly basic Java 101. See Catching and Handling Exceptions
Another option which "might" help is to use a formatted text field
You also don't seem to have a firm grip on the concept of what a "event driven environment" is or what the potential risk of what doing something like while (true) will do if executed within the context of the Event Dispatching Thread. This makes me think you've got yourself in over all head.
You're going to want to learn about Concurrency in Swing as AutoClicker should never be called within the context of the Event Dispatching Thread, which is going to lead you another area of complexity, concurrency and all the joys that brings.
Updated
Wow, you changed the title. Maybe a better description of the problem you're trying to solve would have a gotten a better answer. In short, you can't, not natively in Java anyway. The only way you can detect keyboard input out side of the app is using native integration, JNA/JNI. Plenty of examples about, for example
In first, I'm using Eclipse IDE. So my question is: I create a progress bar, but I want to make it load according to the place where the program is. I have a refresh button, and when I click it my entire program update. What I want is a progress bar that accompanying the process of updating and ends when it ends.
Sorry if my English isn't the best, but I'm a young Portuguese developer.
my btn code
JButton btnActualizar = new JButton("\u21BB");
btnActualizar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
TxtIpExternoLoja.setText(" ");
TxtSSIDLoja.setText(" ");
TxtFirewallLoja.setText(" ");
TxtIpLojaEtho.setText(" ");
TxtMaskLojaEtho.setText(" ");
TxtGWLojaEtho.setText(" ");
TxtDns1LojaEtho.setText(" ");
TxtDns2LojaEtho.setText(" ");
TxtIpLojaWlan.setText(" ");
TxtMaskLojaWlan.setText(" ");
TxtGwLojaWlan.setText(" ");
TxtDns1LojaWlan.setText(" ");
TxtDns2LojaWlan.setText(" ");
TxtIpLojaVpn.setText(" ");
TxtMaskLojaVpn.setText(" ");
TxtGwLojaVpn.setText(" ");
TxtDns1LojaVpn.setText(" ");
TxtDns2LojaVpn.setText(" ");
// DefaultTableModel model = (DefaultTableModel)
// tablePing.getModel();
// model.setRowCount(0);
TxtTime.setText(" ");
i = 0;
t.start();
btnActualizar.setEnabled(false);
update();
}
});
my progressbar code:
JProgressBar progressBar = new JProgressBar(0, 15);
GridBagConstraints gbc_progressBar = new GridBagConstraints();
gbc_progressBar.insets = new Insets(0, 0, 0, 5);
gbc_progressBar.gridx = 3;
gbc_progressBar.gridy = 0;
PanelBotoes.add(progressBar, gbc_progressBar);
GridBagConstraints gbc_btnImprimir = new GridBagConstraints();
gbc_btnImprimir.insets = new Insets(0, 0, 0, 5);
gbc_btnImprimir.gridx = 5;
gbc_btnImprimir.gridy = 0;
PanelBotoes.add(btnImprimir, gbc_btnImprimir);
progressBar.setStringPainted(true);
progressBar.setValue(0);
t = new Timer(interval, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (i == 15) {
t.stop();
btnActualizar.setEnabled(true);
} else {
i++;
progressBar.setValue(i);
}
}
});
Take a look at this page: https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html.
Specifically, the section on "Using Determinate Progress Bars" should be what you are looking for. The example code is a little complex, but probably about as simple as it can get with this stuff.
Take note: the example uses a SwingWorker (more on those here) to update the progress value. This is because the progress bar is drawn in the Swing thread and won't be updated if the process is running on that thread too.
You will need to update your program on a thread which is not the Swing thread.
Edit 1 - For your question update with code
So it looks like you've got the idea with the progress bar code. I've not run it, but what you've got looks like it should work. Your next step is to replace the timer with the update() methods process.
To do this you'll need to do the following:
Make sure your update() method is running in a thread separate from the swing thread (something like a SwingWorker could be used here).
From within the update thread you need to call progressBar.setValue(x) when you want to update the bar, where x = how far your process has got.
Add some more calls to progressBar.setValue(x) in the update thread. You can put these wherever you like, but it's probably best to put them before and after long processes.
Note: you have to use threads for progress bars. This means you could run into things like deadlock and race conditions. Be careful!
I am notdoing a school project, so please do not be alarmed. I am doing some private programming to brush up. My program, a program of type .java, creates a form that asks for the boundaries and quantities of a lottery-drawing activity and acts on the generating based on the input.
Here's my problem. On the WIndows 2000 computer where I coded the program, shows itself, perfectly. That's only half the story. When I tried to put it on another computer, the program shows a blank window; it compiles and runs, but it shows a blank window. Now, I do consider version numbers to be factors, so I will provide the versions and ask for confirmation if those are the root of the evil.
On my original computer, which is Windows 2000, the version is 1.6.0_31-b05. The other computer, which is Windows 7 dual-booted with Linux Mint 17.2, is running 1.8.0_60-b27 and 1.8.0_00 respectively.
My program is not finished yet, but I'll worry about that later. What I'm hoping to do now is to get the program, such as it is, to run on the platforms of all my computers. Since Java is known for its portability, I expect it to run on all my computers. Is that a misconception?
Anyways, here's the code:
//Import class libraries
import javax.swing.*;
import javax.swing.JOptionPane;
import java.awt.*;
import java.awt.event.*;
public class Lotterygui //Begin class
{
//VARIABLES FOR DATA COLLECTION
private JTextField lowerRange; //Lowest number
private JTextField higherRange; //Highest number
private JTextField quantity; //How many numbers to generate
private JTextArea displayArea; //What to display when the program is in use
//ADD WARNING CONSTANT FOR INVALID INPUT
private final String WARNING = "Please fill out valid data "
+ "and not leave anything out. "
+ "Also,do not enter any "
+ "zeroes.";
public Lotterygui()
{
//GUI CONFIGURATION
//Frame settings
JFrame jfrFrame = new JFrame("Lottery Program");
jfrFrame.setSize(300,400);
jfrFrame.setLocationRelativeTo (null);
jfrFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrFrame.setVisible(true);
jfrFrame.setResizable(false);
//Panel to hold the user input controls in place
JPanel jplInputs = new JPanel();
jplInputs.setLayout(new GridLayout(4, 2));
//CREATE INPUT CONTROLS
//Lowest range
JLabel jlblLowerRange = new JLabel("Lowest");
lowerRange = new JTextField();
//Highest range
JLabel jlblHigherRange = new JLabel("Highest");
higherRange = new JTextField();
//Quantity
JLabel jlblQuantity = new JLabel("Quantity");
quantity = new JTextField();
//Buttons and their respective action associations
//Generate numbers button
JButton jbtnGenerate = new JButton("Generate");
ActionListener alGenerate = new listenGenerate();
jbtnGenerate.addActionListener(alGenerate);
//Reset all values button
JButton jbtnReset = new JButton("Reset");
ActionListener alReset = new listenReset();
jbtnReset.addActionListener(alReset);
//ADD CONTROLS TO FORM
jplInputs.add(jlblLowerRange);
jplInputs.add(lowerRange);
jplInputs.add(jlblHigherRange);
jplInputs.add(higherRange);
jplInputs.add(jlblQuantity);
jplInputs.add(quantity);
jplInputs.add(jbtnGenerate);
jplInputs.add(jbtnReset);
//CREATE DISPLAY AREA AND ADD
//The display area used for showing generated numbers
displayArea = new JTextArea();
displayArea.setLineWrap(true);
displayArea.setText(WARNING);
//The control that sets autoscrolling for the display area
JScrollPane jspDisplayArea = new JScrollPane(displayArea);
jfrFrame.add(jspDisplayArea);
//Add the JPanels to the window
jfrFrame.add(jplInputs, BorderLayout.NORTH);
jfrFrame.add(jspDisplayArea);
}//END lotteryGUI constructor
//MAIN Method
public static void main (String[] args)
{
//CALL UP lotteryGUI CLASS
new Lotterygui();
}//END Main method
//GENERATE BUTTONS ACTION
private class listenGenerate implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//DECLARE VARIABLES
int low; //Lowest number
int high; //Highest number
int qty; //How many numbers
try //Monitor the input of above variables in the form
{
low = Integer.parseInt(lowerRange.getText());
high = Integer.parseInt(higherRange.getText());
qty = Integer.parseInt(quantity.getText());
}
catch (NumberFormatException nfe)
{
//RESET ALL FORM VALUES
reset();
//RESET VARIABLE VALUES
low = 0;
high = 0;
qty = 0;
}//END format errors try-catch
//CHECK IF PROGRAM CAN CONTINUE
if (low != 0 || high != 0 || qty != 0) //If valid
{
//Action pending
displayArea.setText("Generate here - incomplete");
}
else //If there are more one or more errors in the input
{
//ISSUE WARNING
JOptionPane.showMessageDialog(null, WARNING);
}//END IF continue CHECK
}//END actionPerformed method
}//END listenGenerate class
I've been looking up and down at the code. Can this that I did not reference any of the layouts outlined in import? I know it's not JPanel as I did try that can still the problem existed. Anything that will help me will be appreciated. Thank you.
You're calling
jfrFrame.setVisible(true);
first and then adding a bunch of components to the JFrame, and that's backwards and can result in a GUI that does not render components until it is resized or minimized and restored. In fact try this -- run your program, then minimize the blank GUI and restore it, and I'll bet you'll see your components.
I suggest that you swap this order around -- call jfrFrame.setVisible(true); last after adding everything to the GUI.
I am writing a GUI that is supposed to write lines and circles to a panel and I am supposed to use sliders to change how fast they add to the panel. I am supposed to add a clear button that will clear the entire panel and then when I move the sliders they should make the circles and lines begin to write on the panel again. There should be a specific stop point at the beginning of the sliders. We have been told to do this without actionlisteners on the sliders. I am having some trouble understanding how to make that work.
Below are the requirements for the assignment:
Write a Swing program that provides the following functionality:
Draw random length lines of random color at random coordinates with pauses between the drawing of each line.
Allow the user to set the length of the pause between lines with a slider. Have the slowest value actually stop drawing lines (i.e., it slows to a stop once it is at that value on the slider).
Have a clear button that clears all the lines & circles. Be sure that the clear button is operational at all times.
Draw random size circles of random color at random coordinates with pauses between the drawing of each circle. (Use draw, not fill.)
Allow the user to set the length of the pause between circles with a slider. Have the slowest value actually stop drawing circles (i.e., it slows to a stop once it is at that value on the slider). This is independent of the lines' speed.
The circles and lines are both drawn independently, each in their own Thread.
Do not use Timer for this, extend Thread and/or Runnable.
public class OhMy extends JFrame
{
private static final int MAX_COLOR = 225;
private static final long STOP_SLEEP = 0;
public OhMy()
{
this.setTitle("Oh My Window");
Container canvas = this.getContentPane();
canvas.setLayout(new GridLayout(2,1));
JPanel panControl = new JPanel(new GridLayout(1,1));
JPanel panDraw = new JPanel(new GridLayout(1,1));
canvas.add(panControl);
canvas.add(panDraw);
panControl.add(createPanControl());
panDraw.add(createPanDraw());
this.setSize(800, 600);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel createPanControl()
{
JPanel panControl = new JPanel();
JLabel lines = new JLabel("Lines");
panControl.add(lines);
lines.setForeground(Color.RED);
JSlider sldSpeedLines = new JSlider(1, 30, 5);
panControl.add(sldSpeedLines);
JButton btnClear = new JButton("Clear");
panControl.add(btnClear);
btnClear.setForeground(Color.RED);
JSlider sldSpeedCircles = new JSlider(0, 30, 5);
panControl.add(sldSpeedCircles);
JLabel circles = new JLabel("Circles");
panControl.add(circles);
circles.setForeground(Color.RED);
btnClear.addActionListener((e)->
{
repaint();
});
return panControl;
}
private JPanel createPanDraw()
{
JPanel panDraw = new JPanel();
class LinesThread extends Thread
{
#Override
public void run()
{
try
{
Graphics g = panDraw.getGraphics();
while(g == null)
{
Thread.sleep(STOP_SLEEP);
g = panDraw.getGraphics();
}
Random rand = new Random();
int red = rand.nextInt(MAX_COLOR);
int green = rand.nextInt(MAX_COLOR);
int blue = rand.nextInt(MAX_COLOR);
Color color = new Color(red, green, blue);
int x1 = rand.nextInt(panDraw.getWidth());
int y1 = rand.nextInt(panDraw.getHeight());
int x2 = rand.nextInt(panDraw.getWidth());
int y2 = rand.nextInt(panDraw.getHeight());
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
catch(InterruptedException e1)
{
//awake now
}
}
}
return panDraw;
}
/**
* #param args
*/
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new OhMy();
}
});
}
}
You state:
"We have been told to do this without actionlisteners on the sliders..."
Good, because JSliders won't accept an ActionListener.
JSliders will accept a ChangeListener though, but you likely don't even need to use this.
Instead, give the clear button an ActionListener (you've no way to get around using ActionListeners at all).
In that ActionListener, reset the drawing and get the values from the JSliders by simply calling getValue() on it.
Don't get your Graphics object by calling getGraphics() on the JPanel since the Graphics object thus obtained will not be stable risking a broken image, or worse, a NullPointerException (to see what I mean, minimize and restore your current application while its drawing).
Instead either draw on a BufferedImage that is displayed in the JPanel's paintComponent method or draw directly in paintComponent itself.
Avoid using a Thread and Thread.sleep, but instead use a Swing Timer -- it's much easier this way to be sure that your code is threading appropriately.
Use this value to adjust the speed of your Swing Timer.
Edit
Thanks to Abishek Manoharan for pointing out problems in my answer...
If the JSliders need to change the speed of drawing while the drawing is proceeding, then you will in fact need to use ChangeListener on the slider.
In that listener change a field that will tell the Thread how long to sleep.
I see that you're also required to use background threads. If so, then be sure to make all Swing calls on the Swing event thread. So if you're in the background thread and need to make a Swing call, then queue it on the Swing event thread by calling SwingUtilities.invokeLater(...) and pass in a Runnable that has your Swing call.
I am attempting to write a program that will loop through lots of images and apply various operations to them and then store use the result to train a self organizing map, i wish to write a front end to this program that for each image i am processing it will display the original and it will display the resultant image after i have applied the operations to it, so far i have written a GUI and from what i have researched it should display the image ( which i have scaled because some can be rather large ) on the left of the screen but nothing is displayed apart from the text labels i was hoping for some incite into what is going wrong as i am new to programming GUI's.
This is what i get when i run the program, what i would like is a image displayed below the "Origonal Image" label
This portion of code just handles the initialization as you can see an panel is added to the frame all the program is inside here. When the panel is initialized the following code is run, note that this is inside the ImageComparatorPanel class
public ImageComparatorPanel() throws FileNotFoundException, UnsupportedEncodingException
{
setLayout(new BorderLayout());
origonalImage = new JLabel( new ImageIcon() );
leftTitle = new JLabel("Origonal Image");
rightTitle = new JLabel("Shrunken Image");
ButtonListener listener = new ButtonListener();
start = new JButton("Start!");
start.addActionListener(listener);
JPanel left = new JPanel();
left.add(leftTitle);
left.add(origonalImage);
//add(leftTitle, BorderLayout.WEST);
//add(origonalImage, BorderLayout.WEST);
add(left, BorderLayout.WEST);
add(rightTitle, BorderLayout.EAST);
add(start, BorderLayout.NORTH);
setPreferredSize(new Dimension(800,800));
}
in the main part of my program ( the bit that is executed when the start button is pressed ) the bit of code that is supposed to update the image is as follows
origonalImage.setIcon(getImage(imagePath));
the getImage function opens the image and shrinks it so that it will fit on the panel the code for this is ( thought i should include this just in case...
public ImageIcon getImage(String URL) throws IOException
{
double scale = 0.5;
File f = new File(URL);
Image image = ImageIO.read(f);
ImageIcon icon = new ImageIcon(image);
int h = icon.getIconHeight();
int w = icon.getIconWidth();
Image newImg = icon.getImage();
Image scaled = newImg.getScaledInstance((int)(w * scale), (int)(h * scale), Image.SCALE_SMOOTH);
ImageIcon newIcon = new ImageIcon(scaled);
return newIcon;
}
How can i change this so on each iteration of the loop in the RUN function the image displayed in the GUI will be updated?
You state:
How can i change this so on each iteration of the loop in the RUN function the image displayed in the GUI will be updated?
To change a GUI's visible state every x msecs, you need to either use a Swing Timer or a background thread such as a SwingWorker.
The Timer would be used if your code being called intermittently is not long running and does not tie up the Swing event thread (the Event Dispatch Thread or EDT) inordinately. If the code being called periodically does take time to run, then this technique will tie up the EDT making your GUI completely unresponsive. In this case, use the SwingWorker when you do in fact need to do heavy processing between image changes, and then use the SwingWorker's publish/process method pair to obtain and display updated images. A properly created SwingWorker will run the heavy lifting code in a thread background to the EDT, but will allow you to make Swing calls on the EDT when necessary.
If your main problem is just that no images are showing, then you're going about solving this wrong: you shouldn't be trying to solve this in a huge complex program but instead create a small program that just tries to show an image and nothing else. Solve each small sub-problem in a step-wise fashion, and only when solved, add it to the greater whole, the large program.