I'm trying to get locale in which user inputs text into JPasswordField.
For this I'm doing the next:
final JPasswordField passwdField = new JpasswordField();
final InputContext it = InputContext.getInstance();
final JTextArea localeLng = new JTextArea();
...
...(some code)
...
passwdField.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
localeLng.setText(it.getLocale().getLanguage().toUpperCase());
}
});
I have two keyboard layouts En and Ru. When I switch between them it doesn't affect on the localeLng value. This perhaps on Ubuntu with JRE 7up7.
But this perfectly works on Windows 7.
So, in what may resides my problem at all?
My temporal rough solution :)
public void keyReleased(KeyEvent e) {
int key = (int)e.getKeyChar();
if(key>122){
localeLng.setText("!");
localeLng.setBackground(Color.RED);
} else {
localeLng.setText("En");
localeLng.setBackground(Color.BLUE);
}
}
It's probably a good thing to remind that with Java you get a well defined set of methods and classes but different implementations, there are many JVM out there and many OS that offers support for Java, probably each one with its own implementation.
That said, this link will answer your question.
I also suggest to let the user decide what is the right locale, getting the right locale programmatically can be really tricky, especially under Linux.
Related
I have a basic text based Java app. I want the user to be able to enter sensitive info (password) in a text editing session that only exists for that purpose.
A bit like with git you get a temporary session/file in vi (or another set editor) to edit comment and save/quit - then the git process resumes and consumes that file. The file is (probably) deleted or at least forgotten about.
Do not need any advanced editor capabilities, just basic typing, backspace etc.
I want the user to be able to see what they're typing BUT once they have typed a password, it must be erased from screen. So plain STDIN won't work as the input remains on the screen.
How can I do it in Java or for that matter in another language?
I have looked at Scanner (basically STDIN) and Console.readPassword (user cannot see what they type).
Perhaps a solution that involves STDIN and immediate erasure of the typed line could be acceptable. But emulating git/vi interplay is more attractive because it's arguably a bit more standard.
EDIT: I have implemented something close - create temp file and run notepad.exe on that, let user save and close notepad, read from temp file, delete it. Simple but it relies on an external tool, needs to be adjusted to run on linux as well.. I would like something more seamless where the behaviour is emulated within the java app itself
Swing is pretty consistently available, here is an example of a method that opens a window, waits until the window is closed, and returns the text.
import javax.swing.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.awt.EventQueue;
import java.awt.event.*;
public class EditMe{
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
public void showEditor(){
JFrame frame = new JFrame("edit text");
JEditorPane pane = new JEditorPane("txt", "");
frame.add(pane);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener( new WindowAdapter(){
#Override
public void windowClosed(WindowEvent evt){
try{
queue.put(pane.getText());
} catch(InterruptedException e){
//not really possible, but just incase.
throw new RuntimeException(e);
}
}
} );
frame.setSize( 640, 480 );
frame.setVisible(true);
}
public static String getText() throws InterruptedException{
EditMe me = new EditMe();
EventQueue.invokeLater( ()-> me.showEditor() );
return me.queue.take();
}
public static void main(String[] args) throws Exception{
System.out.println("waiting for response");
String s = getText();
System.out.println("response received: \n" + s);
}
}
This would be about equivalent to a notepad solution, but it uses swing that comes with standard jdk's. (There are headless jdk's that don't include swing.)
When I do something like fileText.setText(path) in a JTextField, it works well unless the text is in Hebrew (or combines English and Hebrew). Then I get something like this:
I tried different fonts (even fonts that "Hebrew" is mentioned in them), but it didn't help. How do I fix it?
By the way, it is working properly with the ToolTipText (fileText.setToolTipText(path))
Here's my code:
// browse files or folders
public void browse(JTextField txtField) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedDir = fileChooser.getSelectedFile();
String path = selectedDir.getAbsolutePath();
if (txtField == srcText) {
srcText.setText(path);
srcText.setToolTipText(path);
}
else {
if (txtField == dstText) {
dstText.setText(path);
dstText.setToolTipText(path);
}
}}
}
Not an answer, since your code works well as it is. Please try to your environment.
For me it works flawlessly out of the box with the default font on Windows 7. Java JDK1.8.0_31
public class JTextFieldExample extends JFrame {
private static final long serialVersionUID = 1L;
public JTextFieldExample() {
super("TextField Test Demo");
final Container container = getContentPane();
final JTextField textField=new JTextField("hello \u05DD\u05D5\u05DC\u05E9 Hello \u05DD\u05D5\u05DC\u05E9");
// optionally set RTL
textField.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
container.add(textField);
setSize(300,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(final String args[]) {
new JTextFieldExample();
}
}
Makes a window with a JTextField containing:
hello םולש Hello םולש
(I am sorry if I am using something strange or offensive in Hebrew. I just copied the unicode chars from another page, they claim it means "hello").
I've also tried you code in a test app and that is worked well, too.
Also Hebrew-only, English-Hebrew mixtures work well.
However you may prefer to set the RTL orientation to better match to Hebrew, and I guess in my example, the Hebrew letters are displayed in reverse order disregarding to the actual orientation.
Do the following:
check if the JTextField work well in Hebrew? If so, then there is something odd in the path returned by the file selector
check the path by priting it to the console. Locate chars which can cause problems, e.g. \-es, or broken unicode code points
dump the bytes of the string in hexa. This can reveal e.g. unicode byte ordering marks or broken unicode code points.
I'm developing my own text-like JComponent. It isn't a subclass of JTextComponent, because it isn't using a Document as the model. I'd still like to support the standard mnemonics of cut/copy/paste, but I know that the keystrokes depend on the platform.
Ultimately, I'll let the user edit the keybindings themselves, but for now, I'd like to at least default to something that is sensible.
Is it possible to get it from the LookAndFeel somehow? Or do I need to detect the platform myself and just have a mapping per platform?
I'm using Java 8 if that makes a difference.
There is no LAF property that I'm aware of for this purpose.
However you might be able to use the information from the InputMap of the LAF.
The following works for Windows 8:
import java.awt.*;
import javax.swing.*;
public class PlatformMnemonics
{
public static void main(String[] args)
{
KeyStroke copyKeyStroke = null;
KeyStroke cutKeyStroke = null;
KeyStroke pasteKeyStroke = null;
InputMap im = (InputMap) UIManager.get("TextField.focusInputMap");
for (KeyStroke keyStroke: im.keys())
{
boolean upperCase = Character.isUpperCase( keyStroke.getKeyCode() );
if ( upperCase )
{
String actionMapKey = im.get( keyStroke ).toString();
if ("copy-to-clipboard".equals(actionMapKey))
copyKeyStroke = keyStroke;
else if ("cut-to-clipboard".equals(actionMapKey))
cutKeyStroke = keyStroke;
else if ("paste-from-clipboard".equals(actionMapKey))
pasteKeyStroke = keyStroke;
}
}
System.out.println("Copy KeyStroke: " + copyKeyStroke);
System.out.println("Cut KeyStroke: " + cutKeyStroke);
System.out.println("Paste KeyStroke: " + pasteKeyStroke);
}
}
Note there are actually 3 bindings on Windows for each Action as you can see in the Key Bindings programs that displays all the key bindings for every Swing component. I just displayed the binding I think you are interested in.
So, the closest I found to do what I want is the OS X Integration for Java page from Apple. There is a method on the Toolkit class getMenuShortcutKeyMask(), which will help support what I want.
For example, the following will get the right keystroke for "meta-v" on mac, and "ctrl-v" on windows/linux.
KeyStroke.getKeyStroke(KeyEvent.VK_V,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())
I am currently using Vaadin 7.3+ and want to validate in a text field as the user types in real time.
This is what I tried so far:
textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
#Override
public void textChange(FieldEvents.TextChangeEvent event) {
for (Validator v : textField.getValidators()) {
try {
v.validate(event.getText());
} catch (InvalidValueException e) {
log.warn("validation error: " + e.getMessage() + " and value was: {}", event.getText());
}
}
}
});
The problem is that although all the validators are being executed and validation is being done the red error indicator is not rendered until the focus leaves the field, i.e. the user hits enter or clicks somewhere else. I tried adding textField.markAsDirty but this did not work. Does anyone know of a solution to this problem? Or of a better solution in general for creating a real time validator on a text field?
Thanks in advance for your time and input :-)
Validators in core the Vaadin are not designed to work while typing, which is a shame for a RIA framework. This will hopefully be fixed in upcoming version. Making it work well today with core components is bit tricky, but doable. Your own solution probably has some UX issues if there is some latency between your server and the client - the cursor might jump into unintended place if user starts to retype again while validator is executed. I have worked on this a lot in Viritin add-on. By using its AbstractForm (or raw MBeanFieldGroup) together with MTextField this should work pretty well and without any configuration. You can try that solution with e.g. this example.
the problem here is, that the event sends the text, but does not actually modify the value of the input. the easiest way to go around this would be setting the value. e.g.
addTextChangeListener(new FieldEvents.TextChangeListener() {
#Override
void textChange(FieldEvents.TextChangeEvent event) {
final textField = event.source as TextField
textField.value = event.text
}
})
this would just trigger the change of the field and also the validators and all will go down to the client as expected.
edit
as you stated in the comments, the cursor pos should be kept. You can just validate the text from the event with whatever means you need. Key point here is, to just set the componentError of the field to get the error down the line for the field.
#Override
void textChange(FieldEvents.TextChangeEvent event) {
final tf = event.source as TextField
try {
tf.validate(event.text) // this works in groovy! not java.
tf.setComponentError(null)
}
catch (InvalidValueException e) {
tf.setComponentError(new SystemError(e))
}
}
This straight forward workaround solution seems to work fine although it is quite inelegant.
textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
#Override
public void textChange(FieldEvents.TextChangeEvent event) {
try {
textField.setValue(event.getText());
// workaround cursor position problem
textField.setCursorPosition(event.getCursorPosition());
textField.validate();
} catch (InvalidValueException e) {
log.warn("validation error: " + e.getMessage() + " and value was: {}", delegate.getValue());
}
}
});
Take a look in the Vaadin Documentation. If I get you right it should be fine to set your field in immediate mode. Sometimes it is recommend to allow null values to avoid unnecessary warnings.
TextField field = new TextField("Name");
field.addValidator(new StringLengthValidator(
"The name must be 1-10 letters (was {0})",
1, 10, true));
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(true);
Not much to add to the Title question.
Here's what tabbing to the first box looks like, with cursor before the first character in the field, so that the user will have to delete the character if he wishes to enter his own month, day, or year number:
Here's what I'd like, when the field is tabbed to (or otherwise selected), so the user doesn't have to delete the character(s) presented if he wishes to enter his own year, etc.:
I can accomplish this for a JTextField like so, for example:
txtDateFrom.select(0,99);
But .select() isn't a method for JSpinner.
(I realize that this raises the question, "Why use a spinner?" but the obvious answer is that I'd like both methods of selecting to be available, as is common in design.)
(A much less pressing but related matter... I made an integer array of 100 year-dates [e.g., 2014] named years and used SpinnerListModel(years) because when using the SpinnerNumberModel, a year would be displayed as 2,014. I can live with what I've done, but is there a less-brute-force way? There's no method containing "format" that I could find for this method.)
This works in Java 1.7.0_51, in Windows and Linux. I don't have the ability to test it in OS X.
JSpinner.DefaultEditor editor =
(JSpinner.DefaultEditor) spinner.getEditor();
editor.getTextField().addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent event) {
final JTextField textField = (JTextField) event.getComponent();
EventQueue.invokeLater(new Runnable() {
public void run() {
EventQueue.invokeLater(new Runnable() {
public void run() {
textField.selectAll();
}
});
}
});
}
});
Side note: Have you considered replacing your three JSpinners with a single JSpinner like this?
JSpinner spinner = new JSpinner(new SpinnerDateModel());
spinner.setEditor(new JSpinner.DateEditor(spinner, "MM/dd/yyyy"));
The up/down arrow buttons (and arrow keys) will change whichever field contains the text cursor.
It won't solve your focus issue, but you may decide that the issue is less of an issue.