i have a problem trying to stop my Timer. I have two different classes, the first contains the button that starts and stop the button and the second is the chrono class. Here is the button:
btnStopstart = new JButton("START");
btnStopstart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
Chrono1 cn = new Chrono1(chrono);
String texte = btnStopstart.getText();
if(texte.equals("START")){
btnStopstart.setText("STOP");
try {
cn.Editchrono(texte);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}else if(texte.equals("STOP")){
btnStopstart.setText("START");
cn.Editchrono(texte);
}
}
});
And here is the chrono class:
public class Chrono1 {
private static int sec;
private JTextField chrono;
public Chrono1(JTextField chrono){
this.chrono = chrono;
}
public void Editchrono(String txt){
/* Le timer */
int delais=1000;
ActionListener tache_timer;
tache_timer = new ActionListener(){
public void actionPerformed(ActionEvent e){
sec++;
if(sec == 15 ){
//Conditions
}
if(sec == 16){
/*On realise une pause de 1 sec */
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//mettre les conditions ici
sec = 0;
}
//System.out.println(sec);
chrono.setText("" + sec);
}
};
final Timer timer1= new Timer(delais,tache_timer);
if(txt.equals("START")){
timer1.start();
}else if(txt.equals("STOP")){
timer1.stop();
//sec = 0;
}
}
}
Thank you for the help.
You're calling stop() on a Swing Timer all right, but not on the Timer instance that's running. Rather you're calling stop() on a completely new Timer instance, one that's not even running, and one that is completely unrelated to the Timer that is in fact running. You need to give the Chrono1 class a Timer field, say called timer, set this field to reference the running Timer when it starts, and call stop on this field (if not null) when stop is called. You also need to create one and only one Chrono1 object.
e.g.,
public class Chrono1 {
private static int sec;
private JTextField chrono;
private Timer timer1; // ***** added ***
public Chrono1(JTextField chrono){
this.chrono = chrono;
}
public void Editchrono(String txt){
int delais=1000;
ActionListener tache_timer;
tache_timer = new ActionListener(){
public void actionPerformed(ActionEvent e){
// .... etc.....
}
};
if(txt.equals("START")) {
// **** note changes? ****
// final Timer timer1= new Timer(delais,tache_timer); // ** no **
timer1= new Timer(delais,tache_timer); // ** yes! **
timer1.start();
}else if(txt.equals("STOP")){
if (timer1 != null && timer1.isRunning()) {
timer1.stop();
}
//sec = 0;
}
}
}
Also this guy shouldn't be re-created:
Chrono1 cn = new Chrono1(chrono);
And so this should be a private instance field of either the whole class or of the inner ActionListener class and not re-created with each button push.
e.g., make the changes below:
btnStopstart.addActionListener(new ActionListener(){
private Chrono1 cn = new Chrono1(chrono); // **** add this
public void actionPerformed(ActionEvent e) {
// Chrono1 cn = new Chrono1(chrono); // **** remove this
String texte = btnStopstart.getText();
if(texte.equals("START")){
btnStopstart.setText("STOP");
try {
cn.Editchrono(texte);
} catch (Exception e1) {
e1.printStackTrace();
}
} else if(texte.equals("STOP")) {
btnStopstart.setText("START");
cn.Editchrono(texte);
}
}
});
Related
I have a GUI created in a class called MainFrame. One of the JPanels of the GUI displays the current time and date, by second. When the user decides to use the GUI to analyze data, it invokes a class that processes data. When the data process is happening, the timer pauses, then resumes when the dataprocess is over. How can I have the timer continuously run even if the program is running? The timer is its own thread, but I do not understand where to start a thread for a JPanel.
Here are some code cut-outs
App.java (app to start the entire GUI)
public class App {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainFrame();
}
});
}
}
MainFrame (class that handles the JPanels and dataprocess impl)
public class MainFrame extends JFrame {
private DataProcess dataProcess = null;
...
...
private StatusPanel statusPanel;
...
...
public MainFrame() {
...
setJMenuBar(createFrameMenu());
initializeVariables();
constructLayout();
createFileChooser();
constructAppWindow();
}
private void initializeVariables() {
this.dataProcess = new DataProcess();
...
this.statusPanel = new StatusPanel();
...
}
private void constructLayout() {
JPanel layoutPanel = new JPanel();
layoutPanel.setLayout(new GridLayout(0, 3));
layoutPanel.add(dataControlsPanel());
setLayout(new BorderLayout());
add(layoutPanel, BorderLayout.CENTER);
add(statusPanel, BorderLayout.PAGE_END);
}
StatusPanel (panel that shows timer etc)
public class StatusPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JLabel statusLabel;
private JLabel timeLabel;
private Timer timer;
public StatusPanel() {
initializeVariables();
constructLayout();
startTimer();
}
private void constructLayout() {
setLayout(new FlowLayout(FlowLayout.CENTER));
add(statusLabel);// , FlowLayout.CENTER
add(timeLabel);
}
public void startTimer() {
this.timer.start();
}
public void stopTimer() {
this.timer.setRunning(false);
}
private void initializeVariables() {
this.statusLabel = new JLabel();
this.timeLabel = new JLabel();
this.statusLabel.setText(StringConstants.STATUS_PANEL_TEXT);
this.timer = new Timer(timeLabel);
}
}
Timer.java (timer that is used in StatusPanel)
public class Timer extends Thread {
private boolean isRunning;
private JLabel timeLabel;
private SimpleDateFormat timeFormat;
public Timer(JLabel timeLabel) {
initializeVariables(timeLabel);
}
private void initializeVariables(JLabel timeLabel) {
this.timeLabel = timeLabel;
this.timeFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy");
this.isRunning = true;
}
#Override
public void run() {
while (isRunning) {
Calendar calendar = Calendar.getInstance();
Date currentTime = calendar.getTime();
timeLabel.setText(timeFormat.format(currentTime));
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
}
Data process is done in the dataControlsPanel by use of actionlisteners.
When the user decides to use the GUI to analyze data, it invokes a class that processes data. When the data process is happening, the timer pauses, then resumes when the dataprocess is over. How can I have the timer continuously run even if the program is running
First of all, your timer should be a javax.swing.Timer or "Swing" Timer. This is built to work specifically on the Swing event thread and so should avoid many of the Swing threading problems that your current code shows -- for example, here: timeLabel.setText(timeFormat.format(currentTime)); -- this makes a Swing call from a background thread and is dangerous code. Next
The processing code should go into a SwingWorker. When the worker executes, you can pause the Swing Timer by calling stop() on the Timer, or simply let the timer to continue to run. When the SwingWorker has completed its action -- something I usually listen for with a PropertyChangeListener added to the SwingWorker, listening for its state property to change to SwingWorker.StateValue.DONE, call get() on the worker to extract any data it holds and more importantly to capture any exceptions that might be thrown.
For example:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyApp extends JPanel {
// display the date/time
private static final String DATE_FORMAT = "HH:mm:ss dd-MM-yyyy";
private static final DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
// timer updates measures seconds, but updates every 0.2 sec's to be sure
private static final int TIMER_DELAY = 200;
// JLabel that shows the date/time
private JLabel timeLabel = new JLabel("", SwingConstants.CENTER);
// JButton's Action / listener. This starts long-running data processing
private Action dataProcessAction = new DataProcessAction("Process Data");
// the SwingWorker that the above Action executes:
private LongRunningSwProcess longRunningProcess;
// label to display the count coming from the process above
private JLabel countLabel = new JLabel("00");
public MyApp() {
// create a simple GUI
JPanel dataProcessingPanel = new JPanel();
dataProcessingPanel.add(new JButton(dataProcessAction)); // button that starts process
dataProcessingPanel.add(new JLabel("Count:"));
dataProcessingPanel.add(countLabel);
setLayout(new BorderLayout());
add(timeLabel, BorderLayout.PAGE_START);
add(dataProcessingPanel);
showTimeLabelCurrentTime();
// create and start Swing Timer
new Timer(TIMER_DELAY, new TimerListener()).start();
}
// display count from swing worker
public void setCount(int newValue) {
countLabel.setText(String.format("%02d", newValue));
}
// clean up code after SwingWorker finishes
public void longRunningProcessDone() {
// re-enable JButton's action
dataProcessAction.setEnabled(true);
if (longRunningProcess != null) {
try {
// handle any exceptions that might get thrown from the SW
longRunningProcess.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
// display the current time in our timeLabel JLabel
private void showTimeLabelCurrentTime() {
long currentTime = System.currentTimeMillis();
Date date = new Date(currentTime);
timeLabel.setText(dateFormat.format(date));
}
// Timer's ActionListener is simple -- display the current time in the timeLabel
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
showTimeLabelCurrentTime();
}
}
// JButton's action. This starts the long-running SwingWorker
private class DataProcessAction extends AbstractAction {
public DataProcessAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
setEnabled(false); // first disable the button's action
countLabel.setText("00"); // reset count label
// then create SwingWorker and listen to its changes
longRunningProcess = new LongRunningSwProcess();
longRunningProcess.addPropertyChangeListener(new DataProcessListener());
// execute the swingworker
longRunningProcess.execute();
}
}
// listen for state changes in our SwingWorker
private class DataProcessListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(LongRunningSwProcess.COUNT)) {
setCount((int)evt.getNewValue());
} else if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
longRunningProcessDone();
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("My App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyApp());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
// mock up of SwingWorker for long-running action
class LongRunningSwProcess extends SwingWorker<Void, Integer> {
public static final String COUNT = "count";
private static final int MIN_TIME_OUT = 5;
private static final int MAX_TIME_OUT = 10;
private int count = 0;
#Override
protected Void doInBackground() throws Exception {
// all this mock up does is increment a count field
// every second until timeOut reached
int timeOut = MIN_TIME_OUT + (int) (Math.random() * (MAX_TIME_OUT - MIN_TIME_OUT));
for (int i = 0; i < timeOut; i++) {
setCount(i);
TimeUnit.SECONDS.sleep(1);
}
return null;
}
// make count a "bounded" property -- one that will notify listeners if changed
public void setCount(int count) {
int oldValue = this.count;
int newValue = count;
this.count = newValue;
firePropertyChange(COUNT, oldValue, newValue);
}
public int getCount() {
return count;
}
}
Ive been trying a while and cant work out a way to get the text out of a textbox only after the barcode scanner has finished scanning. I am using Swing Framework and Java. My Code works if the text is pasted (Ctrl + V) into the JTextbox but the barcode scanner just does not work as my methods run for every couple of characters of the barcode in turn.
textField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
// warn();
}
public void removeUpdate(DocumentEvent e) {
// warn();
}
public void insertUpdate(DocumentEvent e) {
warn();
}
public void warn() {
input = textField.getText();
SwingUtilities.invokeLater(doUpdate);
}
});
Where input is a variable which I use
The doUpdate method which gets executed is here
final Runnable doUpdate = new Runnable() {
#Override
public void run() {
System.out.println(input + " Is being processed");
textField.setText("");
System.out.println(input.length());
lblStatus.setIcon(new ImageIcon(Main.class
.getResource("/com/daniel/status2.png")));
// frame.getContentPane().add(lblStatus2, BorderLayout.EAST);
if (input.length() <= 4) {
lblStatus.setIcon(new ImageIcon(Main.class
.getResource("/com/daniel/status3.png")));
return;
}
// TODO START
if (!content.containsKey(input)) {
content.put(input, "1");
} else {
Integer i = Integer.valueOf(content.get(input));
i++;
lblStatus.setIcon(new ImageIcon(Main.class.getResource(i
+ ".png")));
playSound(i + "");
if (i.equals(6)) {
i = 0;
}
content.put(input, String.valueOf(i));
}
System.out.println(content.get(input));
Properties properties = new Properties();
for (Entry<String, String> entry : content.entrySet()) {
properties.put((String) entry.getKey(), entry.getValue());
}
try {
properties.store(new FileOutputStream(path
+ "data.properties"), null);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
All Im asking is how do I run a method with a String from the text box only after the barcode reader has finished
It's been a while since I used a barcode reader, but when I did each scan was a line. That is, each scan was a sequence of characters terminated by the new line character. So, you could test the input and only invoke doUpdate when you detect the new line character. That said, you might need to set a property on the text box to allow the new line character and remove it when detected.
You need someway to inject a delay between each update of the DocumentListener and the time your inspect/use the value from the text field.
A simple solution is to use a Swing Timer with a short delay (you can play around with this to find the threashold which is most useful to you). Each time the DocumentListener is notified, you simply reset the timer (start it again), so that it won't trigger until after the delay you specified has occurred, at which time you can read the text from the field.
public class TestPane extends JPanel {
private Timer updateTimer;
private JTextField field;
private JLabel label;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
updateTimer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(field.getText());
}
});
updateTimer.setRepeats(false);
label = new JLabel("...");
field = new JTextField(14);
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
processUpdate();
}
#Override
public void removeUpdate(DocumentEvent e) {
processUpdate();
}
#Override
public void changedUpdate(DocumentEvent e) {
processUpdate();
}
});
add(field, gbc);
add(label, gbc);
}
protected void processUpdate() {
updateTimer.restart();
}
}
You could test this using Robot, which can be used to inject key strokes into the event queue with a specified delay, or just run your scanner at it.
See How to use Swing Timers for more details
You should also attach a ActionListener to the field and see if the scanner triggers the ActionListener, which would be a simpler solution over all
i have a thread running which keeps repainting the maze recursively until the exit is reached. The method below is responsible for repainting the maze.
private void moveFromStep(int x, int y) {
if(step){
if(isWall(x,y))
return ;
if(isVisited(x,y))
return ;
if(isGoal(x,y)){
free = true;
JOptionPane.showMessageDialog(this, "Solution Complete: finish reachable");
}
if(!free){
step = false;
setVisited(x,y);
repaint();
//try {Thread.sleep(3000);} catch (Exception e) { }
//try {wait();} catch (Exception e) { }
moveFromStep(x-1,y);
moveFromStep(x+1,y);
moveFromStep(x,y-1);
moveFromStep(x,y+1);
}
}
}
now i have a JPanel running separately and i want to repaint it step by step.
i want to do this by using a "Step" button. So like the maze is printed step by step when "Step" button is pressed. The code below is the action listener for the buttons
public void actionPerformed(ActionEvent event) {
String action = event.getActionCommand();
MazeStep mazeStep = new MazeStep();
Thread mazeThreadStep = null;
if (action.equals("Load Maze")) {
mazeAnim.readFile(getName());
//mazeStep = new MazeStep();
mazeStep.readFile(getName());
}
else if(action.equals("Start")){
JFrame world = new JFrame();
mazeStep = new MazeStep();
mazeStep.readFile(getName());
world.setSize(300, 300);
world.setTitle("Maze solver");
world.setContentPane(mazeStep);
world.setVisible(true);
mazeThreadStep = new Thread(mazeStep);
mazeThreadStep.start();
}
if(action.equals("Step")){
mazeStep.step = true;
synchronized (mazeThreadStep) {
mazeThreadStep.notify();
}
}
}
So can anyone help me what could be done in order to achieve this plz.
I'm trying to figure out why the text field isn't updating. I'm aware that using SwingWorker will probably fix this problem, but I can't understand why it doesn't work in the first place.
public class waitExample {
private JFrame frame;
private JTextField txtLeadingText;
private String one = "update string 1";
private String two = "update string 2";
private String three = "update string 3";
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
waitExample window = new waitExample();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public waitExample() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
txtLeadingText = new JTextField();
txtLeadingText.setHorizontalAlignment(SwingConstants.CENTER);
txtLeadingText.setText("leading text");
frame.getContentPane().add(txtLeadingText, BorderLayout.SOUTH);
txtLeadingText.setColumns(10);
JButton btnClickMeTo = new JButton("CLICK ME TO UPDATE TEXT");
btnClickMeTo.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
try {
updateOne();
Thread.sleep(1000);
updateTwo();
Thread.sleep(1000);
updateThree();
Thread.sleep(1000);
updateLast();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(btnClickMeTo, BorderLayout.CENTER);
}
private void updateOne() {
txtLeadingText.setText(one);
}
private void updateTwo() {
txtLeadingText.setText(two);
}
private void updateThree() {
txtLeadingText.setText(three);
}
private void updateLast() {
txtLeadingText.setText("default text");
}
}
From what I understand, the default Thread will prevent any GUI updates. That shouldn't matter because I am setting the textField BEFORE the Thread.sleep.
Why doesn't the text field update? Shouldn't the text be set, then the Thread wait?
EDIT: As per the answers, the above code has been updated.
You are invoking Thread.sleep(1000); on EDT. This means that when your method will end - only then the repaint() will fire (at some point in time later).
Until then your GUI is freezed.
Consider that this is going on one thread (so processing is straightforward):
txtLeadingText.setText(one);
Thread.sleep(1000);
txtLeadingText.setText(two);
Thread.sleep(1000);
txtLeadingText.setText(three);
Thread.sleep(1000);
...
<returning from updateText()>
<processing other events on button click>
...
// some time later
<Swing finds out that GUI needs repaint: calls rapaint()>
This is what you should do (I didn't compile or test it):
public class MyRunnable implements Runnable {
private List<String> strsToSet;
public MyRunnable(List<String> strsToSet) {
this.strsToSet = strsToSet;
}
#Override
public void run() {
try {
if(strsToSet.size() > 0) {
final String str = strsToSet.get(0);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
txtLeadingText.setText(str);
}
});
Thread.sleep(1000);
List<String> newList = new LinkedList<String>(strsToSet);
newList.remove(0);
new Thread(new MyRunnable(newList)).start();
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
new Thread(new MyRunnable(Arrays.asList(one, two, three))).start();
It is hard to do in Swing but in contrast in dynamically languages (like Groovy) it would go as simple as that (you'll get a better grasp of what is going on):
edt {
textField.setText(one)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(two)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(three)
}
}
}
}
}
The GUI event loop updates the screen, but it can't update the screen until you return.
I suggest you avoid doing any blocking operations in the GUI event thread.
I am using this mmscomputing library as java applet to scan an image or document.
Using swings,awt i created one scan button which is acquiring scanner by calling scanner.acquire() method of mmscomputing jar..
and then placing that scanned image into jpanel for displaying.
Problem is, first time when i start my applet and hitting my scan button..scanning works fine..Twain states it goes into are: 3,4,5,6,7,5,4,3
then second time,hitting my scan button again ..
Twain states it goes into are: 3,4,5,4,3
It's not going into image transfer ready and transferring state and thus not into below CODE IF loop
if (type.equals(ScannerIOMetadata.ACQUIRED))
so i am not able to see the new scanned image into my jpanel second time...
then third time, hitting my scan button .. again it works fine.. getting into all states.
So i mean, For alternatively turns or restarting the java applet again ..it works.
what would be the issue.. ?
I want, every time when i hit scan button it should get me a new image into Jpanel.. but it's doing alternative times.
can i forcefully explicitly set or change twain states to come into 6th and 7th states..
or is there some twain source initialisation problem occurs second time?
because restarting applet is doing fine every time.. or some way to reinitialise applet objects everytime on clicking scan button..as it would feel like I am restarting applet everytime on clicking scan button...
I am not getting it..
Below is the sample code:
import uk.co.mmscomputing.device.twain.TwainConstants;
import uk.co.mmscomputing.device.twain.TwainIOMetadata;
import uk.co.mmscomputing.device.twain.TwainSource;
import uk.co.mmscomputing.device.twain.TwainSourceManager;
public class XXCrop extends JApplet implements PlugIn, ScannerListener
{
private JToolBar jtoolbar = new JToolBar("Toolbar", JToolBar.HORIZONTAL);
ImagePanel ipanel;
Image im =null;
BufferedImage imageforCrop;
ImagePlus imp=null;
int imageWidth;
int imageHeight;
private static final long serialVersionUID = 1L;
Container content = null;
private JPanel jContentPane = null;
private JButton jButton = null;
private JButton jButton1 = null;
JCheckBox clipBox = null;
JPanel crpdpanel=null;
JPanel cpanel=null;
private Scanner scanner=null;
private TwainSource ts ;
private boolean is20;
ImagePanel imagePanel,imagePanel2 ;
public static void main(String[] args) {
new XXCrop().setVisible(true);
}
public void run(String arg0) {
new XXCrop().setVisible(false);
repaint();
}
/**
* This is the default constructor
*/
public XXCrop() {
super();
init();
try {
scanner = Scanner.getDevice();
if(scanner!=null)
{
scanner.addListener(this);
}
} catch (Exception e)
{
e.printStackTrace();
}
}
/**
* This method initializes this
*
* #return void
*/
public void init()
{
this.setSize(1200, 600);
this.setLayout(null);
//this.revalidate();
this.setContentPane(getJContentPane());
}
private JToolBar getJToolBar()
{
jtoolbar.add(getJButton1());
jtoolbar.add(getJButton());
jtoolbar.setName("My Toolbar");
jtoolbar.addSeparator();
Rectangle r=new Rectangle(0, 0,1024, 30 );
jtoolbar.setBounds(r);
return jtoolbar;
}
private JPanel getJContentPane()
{
if (jContentPane == null)
{
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.add(getJToolBar());
}
return jContentPane;
}
private JButton getJButton() {
if (jButton == null) {
jButton = new JButton();
jButton.setBounds(new Rectangle(4, 16, 131, 42));
jButton.setText("Select Device");
jButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
if (scanner.isBusy() == false) {
selectDevice();
}
}
});
}
return jButton;
}
/* Select the twain source! */
public void selectDevice() {
try {
scanner.select();
} catch (ScannerIOException e1) {
IJ.error(e1.toString());
}
}
private JButton getJButton1()
{
if (jButton1 == null) {
jButton1 = new JButton();
jButton1.setBounds(new Rectangle(35,0, 30, 30));
jButton1.setText("Scan");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e)
{//jContentPane.remove(crpdpanel);
//jContentPane.removeAll();
//jContentPane.repaint();
//jContentPane.revalidate();
getScan();
}
});
}
return jButton1;
}
public void getScan()
{
try
{
//scanner = Scanner.getDevice();
//scanner.addListener(this);
scanner.acquire();
}
catch (ScannerIOException e1)
{
IJ.showMessage("Access denied! \nTwain dialog maybe already opened!");
e1.printStackTrace();
}
}
public Image getImage()
{
Image image = imp.getImage();
return image;
}
/*Image cimg;
public Image getCimg()
{
return cimg;
}*/
public void update(ScannerIOMetadata.Type type, ScannerIOMetadata metadata) {
if (type.equals(ScannerIOMetadata.ACQUIRED))
{
//imagePanel.revalidate();
//imagePanel.repaint();
//imagePanel.invalidate();
//jContentPane.remove(ipanel);
//ipanel.repaint();
if(imp!=null)
{
jContentPane.remove(ipanel);
jContentPane.remove(cpanel);
jContentPane.remove(crpdpanel);
}
imp = new ImagePlus("Scan", metadata.getImage());
//imp.show();
im = imp.getImage();
//imagePanel = new ImagePanel(im,imageWidth,imageHeight);
imagePanel = new ImagePanel(im);
imagePanel.updateUI();
imagePanel.repaint();
imagePanel.revalidate();
ClipMover mover = new ClipMover(imagePanel);
imagePanel.addMouseListener(mover);
imagePanel.addMouseMotionListener(mover);
ipanel = imagePanel.getPanel();
ipanel.setBorder(new LineBorder(Color.blue,1));
ipanel.setBorder(BorderFactory.createTitledBorder("Scanned Image"));
ipanel.setBounds(0, 30,600, 600);
ipanel.repaint();
ipanel.revalidate();
ipanel.updateUI();
jContentPane.add(ipanel);
jContentPane.getRootPane().revalidate();
jContentPane.updateUI();
//jContentPane.repaint();
// cimg=imagePanel.getCimg();
// ImagePanel cpanel = (ImagePanel) imagePanel.getUIPanel();
/*
cpanel.setBounds(700, 30,600, 800);
jContentPane.add(imagePanel.getUIPanel());
*/
cpanel = imagePanel.getUIPanel();
cpanel.setBounds(700, 30,300, 150);
cpanel.repaint();
cpanel.setBorder(new LineBorder(Color.blue,1));
cpanel.setBorder(BorderFactory.createTitledBorder("Cropping Image"));
jContentPane.add(cpanel);
jContentPane.repaint();
jContentPane.revalidate();
metadata.setImage(null);
try {
new uk.co.mmscomputing.concurrent.Semaphore(0, true).tryAcquire(2000, null);
} catch (InterruptedException e) {
IJ.error(e.getMessage());
}
}
else if (type.equals(ScannerIOMetadata.NEGOTIATE)) {
ScannerDevice device = metadata.getDevice();
try {
device.setResolution(100);
} catch (ScannerIOException e) {
IJ.error(e.getMessage());
}
try{
device.setShowUserInterface(false);
// device.setShowProgressBar(true);
// device.setRegionOfInterest(0,0,210.0,300.0);
device.setResolution(100); }catch(Exception e){
e.printStackTrace(); }
}
else if (type.equals(ScannerIOMetadata.STATECHANGE)) {
System.out.println("Scanner State "+metadata.getStateStr());
System.out.println("Scanner State "+metadata.getState());
//switch (metadata.ACQUIRED){};
ts = ((TwainIOMetadata)metadata).getSource();
//ts.setCancel(false);
//ts.getState()
//TwainConstants.STATE_TRANSFERREADY
((TwainIOMetadata)metadata).setState(6);
if ((metadata.getLastState() == 3) && (metadata.getState() == 4)){}
// IJ.error(metadata.getStateStr());
}
else if (type.equals(ScannerIOMetadata.EXCEPTION)) {
IJ.error(metadata.getException().toString());
}
}
public void stop(){ // execute before System.exit
if(scanner!=null){ // make sure user waits for scanner to finish!
scanner.waitToExit();
ts.setCancel(true);
try {
scanner.setCancel(true);
} catch (ScannerIOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I'm not an expert, but when ScannerIOMetadata.STATECHANGE shouldn't you check if the scanning is complete?
And if it is you should initialize the scanner again.
Something like that:
if (metadata.isFinished())
{
twainScanner = (TwainScanner) Scanner.getDevice();
}