How to Remove Mask of JFormattedTextField? - java

I've a JFormattedTextField controlled by two RadioButton. In one of RadioButton I set the mask and the other I want to clear the mask and type normally. After set to type normally it doesn't return the value of getText(), the value only return if the mask is setted.
How could fix this problem ?
private void setMask() {
MaskFormatter formatter = null;
try {
txtPesquisar.setValue(null);
if (rbNome.isSelected()) {
//clear mask to type normally
formatter = new MaskFormatter("****************************************");
formatter.setPlaceholderCharacter(' ');
} else {
//set mask
formatter = new MaskFormatter("###.###.###-##");
formatter.setPlaceholderCharacter(' ');
}
txtPesquisar.setFormatterFactory(new DefaultFormatterFactory(formatter));
txtPesquisar.requestFocus();
txtPesquisar.selectAll();
} catch (ParseException ex) {
ex.printStackTrace();
}
}

Be sure to call commitEdit() on your JFormattedTextField before calling getValue(). As per the JFormattedTextField API section on getValue():
Returns the last valid value. Based on the editing policy of the AbstractFormatter this may not return the current value. The currently edited value can be obtained by invoking commitEdit followed by getValue.
Returns:
For example:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.text.ParseException;
import javax.swing.*;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.MaskFormatter;
#SuppressWarnings("serial")
public class TestFormattedField extends JPanel {
private JFormattedTextField txtPesquisar = new JFormattedTextField();
private JRadioButton rbNome = new JRadioButton("None");
private JRadioButton rbFormat = new JRadioButton("Format");
public TestFormattedField() {
txtPesquisar.setColumns(20);
ButtonGroup btnGroup = new ButtonGroup();
btnGroup.add(rbFormat);
btnGroup.add(rbNome);
rbNome.setSelected(true);
rbNome.setMnemonic(KeyEvent.VK_N);
rbFormat.setMnemonic(KeyEvent.VK_F);
add(txtPesquisar);
add(rbFormat);
add(rbNome);
setMask();
add(new JButton(new SetFormatAction()));
add(new JButton(new GetTextAction()));
}
private void setMask() {
MaskFormatter formatter = null;
try {
txtPesquisar.setValue(null);
if (rbNome.isSelected()) {
//clear mask to type normally
formatter = new MaskFormatter("****************************************");
formatter.setPlaceholderCharacter(' ');
} else {
//set mask
formatter = new MaskFormatter("###.###.###-##");
formatter.setPlaceholderCharacter(' ');
}
txtPesquisar.setFormatterFactory(new DefaultFormatterFactory(formatter));
txtPesquisar.requestFocus();
txtPesquisar.selectAll();
} catch (ParseException ex) {
ex.printStackTrace();
}
}
private class SetFormatAction extends AbstractAction {
public SetFormatAction() {
super("Set Format");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
setMask();
}
}
private class GetTextAction extends AbstractAction {
public GetTextAction() {
super("Get Text");
putValue(MNEMONIC_KEY, KeyEvent.VK_G);
}
#Override
public void actionPerformed(ActionEvent e) {
final String text = txtPesquisar.getText();
try {
txtPesquisar.commitEdit();
} catch (ParseException e1) {
String title = "Incomplete Text Entry";
String msg = "Text -- " + text + " is not yet complete";
JOptionPane.showMessageDialog(TestFormattedField.this, msg, title, JOptionPane.ERROR_MESSAGE);
}
Object value = txtPesquisar.getValue();
System.out.println("text: " + text);
System.out.println("value: " + value);
}
}
private static void createAndShowGui() {
TestFormattedField mainPanel = new TestFormattedField();
JFrame frame = new JFrame("Test JFormattedField");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
In the future, please consider taking a little time to create and post a minimal example program or SSCCE since this would be the best and quickest way to get folks to fully understand your problem and then be able to help you. Please see my code as an example of this.

on form constructor after inintcomponets
public Form1() {
initComponents();
MaskFormatter dateMask;
try {
dateMask = new MaskFormatter("|#|#|#|#|#|#|#|#|#|#|");
dateMask.install(JTEXTFORMATEE);
} catch (ParseException ex) {
Logger.getLogger(Forma051.class.getName()).log(Level.SEVERE, null, ex);
}
}

Related

propertychangelistener on a JDateChooser gets triggered 2 times additionally even when the listener is detached while setting the date programatically

I am using JDateChooser for a java swing project I am developing and in this, the date could be set in two ways: by the end user or programmatically.
So I have defined a propertychangelistener in the respective class(the variable trig is initialised to zero and maintains track on how many times a property change is listened).
public class WriteEntry{
private int trig=0;
private Date currentDate = new Date();
public JDateChooser dateChooser = new JDateChooser();
public CustomDate selectedDate = DateConverter.convertDate(currentDate);
private static String filename = StorageSpace.currentpath+CurrentUser.getInstance().getUserName()+"\\"+
Integer.toString(selectedDate.getYear())+"\\"
+Integer.toString(selectedDate.getMonth())+"\\"+Integer.toString(selectedDate.getDay())+".txt";
private JLabel dayinfo = new JLabel("");
private JTextArea contentfield = new JTextArea("");
private PropertyChangeListener lis = new PropertyChangeListener(){
#Override
public void propertyChange(PropertyChangeEvent e) {
System.out.println("triggered "+trig++);
if(dateBoundary()) {
selectedDate = DateConverter.convertDate(dateChooser);
filename = StorageSpace.currentpath+CurrentUser.getInstance().getUserName()+"\\"+
Integer.toString(selectedDate.getYear())+"\\"
+Integer.toString(selectedDate.getMonth())+"\\"+Integer.toString(selectedDate.getDay())+".txt";
}
else {
updateDateChooser(selectedDate);
}
if(isAlreadyWritten())
{
try {
updateEditFields(selectedDate, "content");
} catch (IOException e1) {
e1.printStackTrace();
}
}
else
{
contentfield.setText("Start writing here");
dayinfo.setText("You are making entry for: "+ new SimpleDateFormat("dd/MM/yyyy").format(dateChooser.getDate()));
}
}
};
WriteEntry() //constructor
{
dateChooser.setDateFormatString("dd MM yyyy");
dateChooser.addPropertyChangeListener(lis);
updateEditFields(DateConverter.convertDate(currentDate), "Start");
}
}
And here is the code for dateBoundary():
public static boolean dateBoundary() {
Object[] option = {"I get it","My Bad!"};
if(dateChooser.getDate().compareTo(currentDate)>0) {
JOptionPane.showOptionDialog(HomePage.getFrame(),"message1",
"",JOptionPane.DEFAULT_OPTION,JOptionPane.ERROR_MESSAGE,null,option,option[0]);
return false;
}
if(dateChooser.getDate().compareTo(DateConverter.convertfromCustom(CurrentUser.getInstance().getDob()))<0){
JOptionPane.showOptionDialog(HomePage.getFrame(),"message2",
"",JOptionPane.DEFAULT_OPTION,JOptionPane.ERROR_MESSAGE,null,option,option[0]);
return false;
}
return true;
}
Code for isAlreadyWritten():
public static boolean isAlreadyWritten() {
File f = new File(filename);
if(f.length()!=0)
{
Object[] option = {"Read","Edit"};
JOptionPane.showOptionDialog(HomePage.getFrame(),"You already updated diary for this day. Do you want to edit?",
"",JOptionPane.DEFAULT_OPTION,JOptionPane.INFORMATION_MESSAGE,null,option,option[0]);
return true;
}
else
return false;
}
Code for updateDateChooser():
public static void updateDateChooser(CustomDate date) {
dateChooser.removePropertyChangeListener(lis); //to stop it from getting triggered when date is set programatically
dateChooser.setDate(DateConverter.convertfromCustom(date));
dateChooser.addPropertyChangeListener(lis);
}
Code for updateEditFields():
public static void updateEditFields(CustomDate searchDate, String excontent) {
updateDateChooser(searchDate);
selectedDate = DateConverter.convertDate(dateChooser);
dayinfo.setText("You are editing entry for: "+ new SimpleDateFormat("dd/MM/yyyy").format(dateChooser.getDate()));
contentfield.setText(excontent);
}
Now my dateboundary function is working as expected. whenever a date greater than current date is chosen, the optiondialog gets displayed and its gone after a click, and the datechooser is set to the last selected date, although the propertychange method is called thrice:
once before the dialog is displayed
twice after the dialog gets closed.
But my isAlreadyWritten() is not working as expected and the optiondialog is getting displayed 4 times with propertychange() method being called four times:
once before each time the dialog is displayed.
I want to understand why propertychange is being called 4 times even though the datechooser is detached from the listener when the date is set programatically?
So, I put together this quick snippet and ran it
import com.toedter.calendar.JDateChooser;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JDateChooser dateChooser = new JDateChooser();
dateChooser.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName());
}
});
dateChooser.setDate(new Date());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dateChooser);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I opened the date selector and selected a date. The program outputted...
date
ancestor
date
date
Was me setting the date programmatically
ancestor is it getting added to the container
Was me selecting the date picker
Was me selecting a date
So, as you can see, not only are you getting spammed with a lot of "date" property changes, you're also getting all the "other" property changes as well 😓
So, the first thing you want to do, is limit the the notifications to the "date" property only, something like...
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName());
}
});
This at least means you don't get bother by all the additional information you don't care about.
While you can add and remove the listener, I tend to find it a pain, as I don't always have a reference to the listener(s), instead, I tend to use a state flag instead
private boolean manualDate = false;
//...
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (manualDate) {
return;
}
System.out.println(evt.getPropertyName());
}
});
manualDate = true;
dateChooser.setDate(new Date());
manualDate = false;
Not a big change, but this alone means that you're now down to two event notifications.
Instead, you should compare the oldValue with the newValue of the PropertyChangeEvent
JDateChooser dateChooser = new JDateChooser();
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (manualDate) {
return;
}
Date newDate = (Date) evt.getNewValue();
Date oldDate = (Date) evt.getOldValue();
if (newDate != null && oldDate != null) {
LocalDate newLD = LocalDate.ofInstant(newDate.toInstant(), ZoneId.systemDefault());
LocalDate oldLD = LocalDate.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
if (newLD.equals(oldLD)) {
return;
}
}
System.out.println(evt.getPropertyName());
}
});
And now, we're down to one change event. The only draw back is it won't tell you when they reselect the current date.
A slightly better work flow might be to ignore it all and simply have a JButton that the user can press to perform what ever associated actions you need carried out
Runnable Example...
import com.toedter.calendar.JDateChooser;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
private boolean manualDate;
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JDateChooser dateChooser = new JDateChooser();
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (manualDate) {
return;
}
Date newDate = (Date) evt.getNewValue();
Date oldDate = (Date) evt.getOldValue();
if (newDate != null && oldDate != null) {
LocalDate newLD = LocalDate.ofInstant(newDate.toInstant(), ZoneId.systemDefault());
LocalDate oldLD = LocalDate.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
if (newLD.equals(oldLD)) {
return;
}
}
System.out.println(evt.getPropertyName());
}
});
manualDate = true;
dateChooser.setDate(new Date());
manualDate = false;
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dateChooser);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Restrict Input of JTextField to Double Numbers?

In java , i am trying to make simple currency converter, but for that i need a text field which can restrict input to numbers only and more importantly double numbers. I tried using JFormatedTextField but it only format the input after you have done your input and click elsewhere but i need to restrict TextField to consume() each invalid character while doing input.
Possible Attempts:
Using JFormatedTextField:
JFormatedTextField textField = new JFormatedTextField(new DoubleFormat());
textField.setBounds(190, 49, 146, 33);
frame.getContentPane().add(textField);
textField.setColumns(10);
Using KeyTyped Event:
char c = arg0.getKeyChar();
if(!(Character.isDigit(c) || c == KeyEvent.VK_BACK_SPACE || c== KeyEvent.VK_DELETE)){
arg0.consume();
}
Using KeyTyped Event with regex:
if(!((textField.getText().toString+arg0.getKeyChar()).matches("[0-9]*(.[0-9]*)?"))){
arg0.consume();
}
Second and third attempt were close but then second attempt failed on point values and third attempt always read first character on textField no matter what it is, So any suggestions ? i am not very fond of JAVA GUI so kindly be patient.
If you know how many places before and after decimal point you want, you can also use MaskFormatter. For example:
JFormattedTextField field = new JFormattedTextField(getMaskFormatter("######.##"));
(...)
private MaskFormatter getMaskFormatter(String format) {
MaskFormatter mask = null;
try {
mask = new MaskFormatter(format);
mask.setPlaceholderCharacter('0');
}catch (ParseException ex) {
ex.printStackTrace();
}
return mask;
}
However it will chenge a look of JTextField, so it will be always visible 000000.00 in it.
EDIT
Another way, not too elegant, but in my opinion working. Try with DecumentListener, maybe it will suit your needs:
field = new JFormattedTextField();
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
Runnable format = new Runnable() {
#Override
public void run() {
String text = field.getText();
if(!text.matches("\\d*(\\.\\d{0,2})?")){
field.setText(text.substring(0,text.length()-1));
}
}
};
SwingUtilities.invokeLater(format);
}
#Override
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
}
});
I used regex: \\d*(\\.\\d{0,2})? because two decimal places is enough for currency.
You would need to use a DocumentFilter. Read the section from the Swing tutorial on Implementing a DocumentFilter for an example to get you started.
Your implementation will be more complex because you will need to take the text already in the Document and then insert the new text in the appropriate location in the String and then invoke Double.parseDouble(...) on the String to make sure it is a valid double value.
If the validation succeeds then you continue with the insertion otherwise you can generate beep.
You can add a key listener to the text field and implement the keyReleased() method to determine if they value in the text field is a double after every key stroke by the user.
public class CurrencyJTF extends JFrame {
JButton jButton = new JButton("Unfocus");
final JFormattedTextField textField = new JFormattedTextField(new DecimalFormat());
double lastDouble = 0.0;
public CurrencyJTF() throws HeadlessException {
textField.setColumns(20);
textField.setText(lastDouble + "");
this.setLayout(new FlowLayout());
this.add(textField);
this.add(jButton);
textField.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
handleKeyReleased();
}
});
}
private void handleKeyReleased() {
String text = textField.getText();
if (text.isEmpty()) return;
try {
lastDouble = Double.parseDouble(text);
} catch (NumberFormatException ex) {
textField.setText(lastDouble + ""); // or set to other values you want
}
}
public static void main(String[] args) {
JFrame frame = new CurrencyJTF();
frame.setVisible(true);
frame.pack();
}
}
You can write your own KeyListener something like that:
public class DoubleNumbersKeyListener implements KeyListener {
final HashSet<Character> valid_keys = new HashSet<>();
final ArrayList<Character> sequence = new ArrayList<>();
public DoubleNumbersKeyListener() {
valid_keys.add('.');
valid_keys.add('0');
valid_keys.add('1');
valid_keys.add('2');
valid_keys.add('3');
valid_keys.add('4');
valid_keys.add('5');
valid_keys.add('6');
valid_keys.add('7');
valid_keys.add('8');
valid_keys.add('9');
valid_keys.add((char) KeyEvent.VK_BACK_SPACE);
valid_keys.add((char) KeyEvent.VK_DELETE);
}
#Override
public void keyTyped(KeyEvent event) {
char c = event.getKeyChar();
if (!valid_keys.contains(c)) {
event.consume();
} else {
if (c == KeyEvent.VK_DELETE || c == KeyEvent.VK_BACK_SPACE) {
if (!sequence.isEmpty()) {
char last = sequence.remove(sequence.size() - 1);
if (last == '.') {
valid_keys.add(last);
}
}
} else {
sequence.add(c);
if (c == '.') {
valid_keys.remove(c);
}
}
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}

Card Layout get the current card string [duplicate]

This question already has answers here:
CardLayout get the selected card's name
(2 answers)
Closed 6 years ago.
i'm using cardlayout in application and want to get the name of the current active card
i tried many methods but with no mean, for example this method seems to be no longer exists
panel.getLayout().getActiveItem()
also i tried this but it doesn't work too
Panel card = null;
for (Component comp : cardPanel.getComponents()) {
if (comp.isVisible()) {
System.out.println(card.getName());
}
}
for example: the following stamts adds several panels to a card layout, i want to return 1,2,3,4 or 5 of the currently active card:
cardPanel.add(firstP, "1");
cardPanel.add(secondP, "2");
cardPanel.add(thirdP, "3");
cardPanel.add(fourthP, "4");
cardPanel.add(fifthP, "5");
what's the possible ways to do that?
CardLayout does not expose its own mapping between of components and its keys (here 1, 2, 3, 4...), so using the layout itself will not reveal how the "cards" are hashed.
If you wish to use the getName method, remember that you must set this yourself first as the field is not set by default:
firstPanel.setName("1");
cardPanel.add(firstPanel, firstPanel.getName());
then, using your for loop, you will be able to get the current card String.
there are two ways
determine visible JComponent from current card
putClientProperty (setName, etc) add listeneing byAncestorListener or HierarchyListener
code
(Disclaimer, Notice this is only code example with Thread.sleep(int), and works only in this form, there is designedly locked Event Dispatch Thread)
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
public class CardlayoutTest extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel pnlA, pnlB, pnlC;
public CardLayout card = new CardLayout();
public CardlayoutTest() {
EventHandler eventHandle = new EventHandler();
pnlA = new JPanel(new BorderLayout());
pnlA.add(new JButton("A"), BorderLayout.CENTER);
pnlA.putClientProperty("JPanel", "JPanel_a");
pnlB = new JPanel(new BorderLayout());
pnlB.add(new JButton("B"), BorderLayout.CENTER);
pnlB.putClientProperty("JPanel", "JPanel_b");
pnlC = new JPanel(new BorderLayout());
pnlC.add(new JButton("C"), BorderLayout.CENTER);
pnlC.putClientProperty("JPanel", "JPanel_c");
pnlA.addAncestorListener(eventHandle);
pnlA.addHierarchyListener(eventHandle);
pnlB.addAncestorListener(eventHandle);
pnlB.addHierarchyListener(eventHandle);
pnlC.addAncestorListener(eventHandle);
pnlC.addHierarchyListener(eventHandle);
setLayout(card);
add(pnlA, "A");
add(pnlB, "B");//
add(pnlC, "C");
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
class EventHandler implements AncestorListener, HierarchyListener {
#Override
public void ancestorAdded(AncestorEvent event) {
JComponent comp2 = event.getComponent();
String str = (String) comp2.getClientProperty("JPanel");
System.out.println("ancestorAdded " + str);
}
#Override
public void ancestorMoved(AncestorEvent event) {
JComponent comp2 = event.getComponent();
String str = (String) comp2.getClientProperty("JPanel");
System.out.println("ancestorMoved " + str);
}
#Override
public void ancestorRemoved(AncestorEvent event) {
JComponent comp2 = event.getComponent();
String str = (String) comp2.getClientProperty("JPanel");
System.out.println("ancestorRemoved " + str);
}
#Override
public void hierarchyChanged(HierarchyEvent e) {
JComponent comp2 = (JComponent) e.getComponent();
String str = (String) comp2.getClientProperty("JPanel");
System.out.println("hierarchyChanged " + str);
}
}
public static void main(String[] args) {
CardlayoutTest t = new CardlayoutTest();
t.setSize(300, 200);
System.out.println("CardlayoutTest.main()------------------------ FIRST");
t.card.show(t.getContentPane(), "A");
t.setVisible(true);
System.out.print("\n");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("CardlayoutTest.main()------------------------ SECOND");
t.card.show(t.getContentPane(), "B");
System.out.print("\n");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("CardlayoutTest.main()------------------------ THIRD");
t.card.show(t.getContentPane(), "C");
System.out.print("\n");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("CardlayoutTest.main()------------------------ SECOND");
t.card.show(t.getContentPane(), "B");
System.out.print("\n");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("CardlayoutTest.main()------------------------ FIRST");
t.card.show(t.getContentPane(), "A");
System.out.print("\n");
}
}

uk.co.mmscomputing twain scanner

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();
}

JSpinner Value change Events

How to make the update immediately when the jSpinner value was changed.
ChangeListener listener = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
jLabel.setText(e.getSource());
}
};
spinner1.addChangeListener(listener);
The code above doesnt change the label text automatically, it required you to click again anyplace to update.
The answer is to configure the formatter used in the JFormattedTextField which is a child of the spinner's editor:
formatter.setCommitsOnValidEdit(true);
Unfortunately, getting one's hand on it is as long and dirty as the introductory sentence:
final JSpinner spinner = new JSpinner();
JComponent comp = spinner.getEditor();
JFormattedTextField field = (JFormattedTextField) comp.getComponent(0);
DefaultFormatter formatter = (DefaultFormatter) field.getFormatter();
formatter.setCommitsOnValidEdit(true);
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
LOG.info("value changed: " + spinner.getValue());
}
});
A slightly (but not by much) cleaner way might be to subclass NumberEditor and expose a method which allows the config
The code you show appears correct. For reference, here is a working example.
Addendum: While the JSpinner has focus, the left and right arrow keys move the caret. The up arrow increments and the down arrow decrements the field containing the caret. The change is (effectively) simultaneous in both the spinner and the label.
To access the JFormattedTextField of the JSpinner.DateEditor, use the parent's getTextField() method. A suitable caret listener or text input listener may then be used to update the label as desired.
Addendum: Update to use setCommitsOnValidEdit, as suggested here.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Calendar;
import java.util.Date;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSpinner.DateEditor;
import javax.swing.SpinnerDateModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.DefaultFormatter;
/**
* #see https://stackoverflow.com/questions/2010819
* #see https://stackoverflow.com/questions/3949518
*/
public class JSpinnerTest extends JPanel {
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("JSpinnerTest");
f.add(new JSpinnerTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
});
}
public JSpinnerTest() {
super(new GridLayout(0, 1));
final JLabel label = new JLabel();
final JSpinner spinner = new JSpinner();
Calendar calendar = Calendar.getInstance();
Date initDate = calendar.getTime();
calendar.add(Calendar.YEAR, -5);
Date earliestDate = calendar.getTime();
calendar.add(Calendar.YEAR, 10);
Date latestDate = calendar.getTime();
spinner.setModel(new SpinnerDateModel(
initDate, earliestDate, latestDate, Calendar.MONTH));
DateEditor editor = new JSpinner.DateEditor(spinner, "MMM yyyy");
spinner.setEditor(editor);
JFormattedTextField jtf = editor.getTextField();
DefaultFormatter formatter = (DefaultFormatter) jtf.getFormatter();
formatter.setCommitsOnValidEdit(true);
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
JSpinner s = (JSpinner) e.getSource();
label.setText(s.getValue().toString());
}
});
label.setText(initDate.toString());
this.add(spinner);
this.add(label);
}
}
It might be an late answer but you may use my approach.
As spuas mentioned above the problem is that stateChanged event is fired only when focus is lost or Enter key is pressed.
Using KeyListeners is not an good idea as well.
It would be better to use DocumentListener instead. I modified spuas's example a bit and that's what I got:
JSpinner spinner= new JSpinner();
spinner.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1));
final JTextField jtf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
jtf.getDocument().addDocumentListener(new DocumentListener() {
private volatile int value = 0;
#Override
public void removeUpdate(DocumentEvent e) {
showChangedValue(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
showChangedValue(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
showChangedValue(e);
}
private void showChangedValue(DocumentEvent e){
try {
String text = e.getDocument().getText(0, e.getDocument().getLength());
if (text==null || text.isEmpty()) return;
int val = Integer.parseInt(text).getValue();
if (value!=val){
System.out.println(String.format("changed value: %d",val));
value = val;
}
} catch (BadLocationException | NumberFormatException e1) {
//handle if you want
}
}
});
Problem here is that when you edit the JSpinner value manually by typing from the keyboard, the stateChanged event is not fired until the focus is lost by the JSpinner or until Enter key has been pressed.
If you want to upload the value, a KeyListener is needed which will perform a setValue in the JSpinner for each typed key.
I leave an example here for a JSpinner with a SpinnerNumberModel:
JSpinner spinner= new JSpinner();
spinner.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1));
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
jLabel.setText(spinner.getValue());
}
});
final JTextField jtf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
jtf.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
String text = jtf.getText().replace(",", "");
int oldCaretPos = jtf.getCaretPosition();
try {
Integer newValue = Integer.valueOf(text);
spinner.setValue(newValue);
jtf.setCaretPosition(oldCaretPos);
} catch(NumberFormatException ex) {
//Not a number in text field -> do nothing
}
}
});
The last answer can be rearranged a little to make it a little more flexible. You can simply use this new MyJSpinner in place of any JSpinner. The biggest change is that you can use this new version with any underlying model of the JSpinner (int, double, byte, etc.)
public class MyJSpinner extends JSpinner{
boolean setvalueinprogress=false;
public MyJSpinner()
{
super();
final JTextField jtf = ((JSpinner.DefaultEditor) getEditor()).getTextField();
jtf.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
showChangedValue(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
showChangedValue(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
showChangedValue(e);
}
private void showChangedValue(DocumentEvent e){
try {
if (!setvalueinprogress)
MyJSpinner.this.commitEdit();
} catch (NumberFormatException | ParseException ex) {
//handle if you want
Exceptions.printStackTrace(ex);
}
}
});
}
#Override
public void setValue(Object value) {
setvalueinprogress=true;
super.setValue(value);
setvalueinprogress=false;
}
}
I'm new so I might be breaking some rules and I might be late. But I found some of the answers a bit confusing so I played around in NetBeans IDE and found that if you right click on the jspinner GUI component placed on your jform and go to events-> change, code will be generated for you.

Categories