I have a couple of input methods for writing (Traditional Chinese) Taiwanese that come with the Windows 7. Also, all of the input methods have an option to switch the character width (single byte/double byte characters).
Chinese (Traditional) - New Quick
Chinese (Traditional) - ChangJie
Chinese (Traditional) - Quick
Chinese (Traditional) - Phonetic
Chinese (Traditional) - New Phonetic
Chinese (Traditional) - New ChangJie
If I select one of these input methods in Java application and set the character width to half-width(single byte character mode) i can successfully input text in JTextField. But, if the application displays some dialog box (e.g. JOptionPane) or pop up window, the input method character width will automatically change to full-width(double byte character mode). After that, the user must manually toggle to half-width characters.
I can programmatically switch on or off the input method using the Java class "InputContext", but i can't control if the input method is set to full-width/half-width (single/double byte) character mode.
I thought maybe it could be disabled from the Windows input method settings, but there was no option related to automatic switching of the character width.
The question is: Is there a way to handle (disable) this automatic toggling ?
Here is an example code to test this with the above input methods:
public class Example implements ActionListener {
JFrame f = new JFrame("pasod");
JTextField txt = new JTextField();
Button btn = new Button("Locale");
public Example() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout());
btn.addActionListener(this);
panel.add(btn);
panel.add(txt);
f.add(panel);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setSize(800, 100);
f.setVisible(true);
}
public static void main(String[] args) {
new Example();
}
public void actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(btn, "Neso", "Neso",
JOptionPane.INFORMATION_MESSAGE);
}
}
Thanks.
Ok I've had a trace through the Java source code looking for anything that stands out;
You call JOptionPane.showMessageDialog() this overloads to JOptionPane.showOptionDialog();
public static int showOptionDialog(Component parentComponent,
Object message, String title, int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
throws HeadlessException {
JOptionPane pane = new JOptionPane(message, messageType,
optionType, icon,
options, initialValue);
pane.setInitialValue(initialValue);
pane.setComponentOrientation(((parentComponent == null) ?
getRootFrame() : parentComponent).getComponentOrientation());
int style = styleFromMessageType(messageType);
JDialog dialog = pane.createDialog(parentComponent, title, style);
pane.selectInitialValue();
dialog.show();
//..Result handling code
}
So we look into createDialog();
public JDialog createDialog(String title) throws HeadlessException {
int style = styleFromMessageType(getMessageType());
JDialog dialog = new JDialog((Dialog) null, title, true);
initDialog(dialog, style, null);
return dialog;
}
So we check the constructor/s of JDialog these all call dialogInit();
protected void dialogInit() {
enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);
setLocale( JComponent.getDefaultLocale() );
setRootPane(createRootPane());
setRootPaneCheckingEnabled(true);
if (JDialog.isDefaultLookAndFeelDecorated()) {
boolean supportsWindowDecorations =
UIManager.getLookAndFeel().getSupportsWindowDecorations();
if (supportsWindowDecorations) {
setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
}
}
sun.awt.SunToolkit.checkAndSetPolicy(this, true);
}
Here we've found setLocale( JComponent.getDefaultLocale() );;
So it appears whenever you create a JDialog, whether it be indirect or not the locale of your program is reset to default, I'm guessing this includes resetting your input settings.
There are a few ways you can set the default Locale (programatically, system properties or runtime args); Details found here
Hope that helps you
I did a simple test:
I opened IE, selected a tab, and at the address bar, set Chinese IME to be half width. Then click another tab, the IME change to full width automatically.
So I don't think it had anything to do with Java. It's a Windows behavior.
Related
In my java code below it produces a frame with a jtextrea. This allows for simple text processing. All I want to do is add " Sam". Which is 5 spaces with sam at the end. Every time the user hits enter. You can see also the gif I added below which is exactly what I am looking for.
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
class text11 extends JFrame implements ActionListener {
// JFrame
static JFrame f;
// text area
static JTextArea jt;
// main class
public static void main(String[] args)
{
// create a new frame to store text field and button
f = new JFrame("textfield");
// create a label to display text
// create a object of the text class
text11 te = new text11();
// create a text area, specifying the rows and columns
jt = new JTextArea(" ", 20, 20);
JPanel p = new JPanel();
// add the text area and button to panel
p.add(jt);
f.add(p);
// set the size of frame
f.setSize(300, 300);
f.show();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
String actionKey = "ADD_SAM";
InputMap inputMap = jt.getInputMap(JComponent.WHEN_FOCUSED);
KeyStroke enterPressed = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
inputMap.put(enterPressed, actionKey);
jt.getActionMap().put(actionKey, new TextAction(actionKey) {
#Override
public void actionPerformed(ActionEvent e) {
jt.append(" Sam\n");
}
});
To get input so you know when the use hits enter, you have to create your own KeyListener class. If you don't know how to use it, here is a handy link from the documentation you can use: https://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html.
But simply put, an KeyListener is an interface where you have to specify a few methods, but in your case I think the only one you need is keyPressed(KeyEvent e)(which is called pressed). If you're interested in the others, keyReleased(KeyEvent e) is when a key gets released, and keyType(KeyEvent e) is when it's pressed and released quickly. Then, use JFrames addKeyListener(KeyListener k) to add your custom action listener.
After you did that, you can use JTextArea's setText() and getText() method to append " sam" to the end (the 5 spaces get cut of by stack overflow, I know you want 5 spaces).
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
jt.setText(jt.getText() + " sam");
}
}
If you added the KeyListener correctly, you should be fine!
I'm creating a text game in a Java Applet so I can display it on my website and have people play it there, however I'm having issues with getting any text to show in my TextArea.
Here is my Main class:
package com.game.main;
import java.applet.*;
import java.awt.*;
public class Main extends Applet {
private TextField commandInput;
private TextArea messageDisplay;
private Button button;
public Message messages;
// Initialisation method
public void init() {
super.init();
// Define colours
setBackground(Color.white);
setForeground(Color.black);
Panel appletPanel = new Panel();
// Use a border layout
BorderLayout b = new BorderLayout();
appletPanel.setLayout(b);
add(appletPanel);
this.setSize(800, 400);
// Define UI items
commandInput = new TextField(20);
messageDisplay = new TextArea(20, 60); // 20 rows x 60 chars
button = new Button("Proceed");
Panel inputPanel = new Panel();
// Add components to our layout / panels
inputPanel.add(commandInput);
inputPanel.add(button);
appletPanel.add("North", messageDisplay);
appletPanel.add("South", inputPanel);
messageDisplay.append(messages.getIntro());
}
}
And here is my Messages class (this contains all the messages that when the user hits the button it will append the next message using the getWhateverMessage method:
package com.game.main;
public class Message {
public String currentMessage;
public String getCurrentMessage() {
return currentMessage;
}
public void setCurrentMessage(String message) {
currentMessage = message;
}
public String getIntro() {
return "Welcome, This is a text adventure game created by me, Adam Short, as a little project to " +
"exercise storytelling as well bring a retro style game to you, the player. To play this " +
"game all you need is a keyboard to type your answers into the input box below. Keep your " +
"answers relevant or you won't progress through the game at all. Type your answer into the " +
"input box and hit the Proceed button or enter on your keyboard. Different answers will lead " +
"to different scenearios and sequences of events. Be careful. Ready to go? Type go in the box " +
"and hit Proceed!";
}
}
public Message messages;
...
messageDisplay.append(messages.getIntro());
You define the messages variable which is null, but you never create an instance of the Message class.
Somewhere in your code you need:
messages = new Message();
Either do this when you define the variable or somewhere in your constructor before you use the variable.
appletPanel.add("North", messageDisplay);
appletPanel.add("South", inputPanel);
Also, the above code is wrong. Read theAPI for the add() method. You are recommended to use:
appletPanel.add(messageDisplay, BorderLayout.NORTH);
appletPanel.add(inputPanel, BorderLayout.SOUTH);
camickr is right,you need to make an object of Message class and the variable messages needs to hold a reference to it:
messages =new Message( );
Then only you can access its instance variables and methods.
Is it possible to open and close a messagedialog without the user having to click buttons?
When the user clicks a button on my form, the action from that button goes server side and gathers a list of items, takes a couple of seconds. I want a way to tell the users that the action is in progress. I was thinking a messagedialog with some text. .
Opens the message
MessageDialog.openInformation(shell, "Information", "Getting List From Server");
Then some how closes it
(something like MessageDialog.close)?
I looked at a progress bar but that was more than I really needed.
It might look like a big overhead at first, but I would suggest using an IProgressMonitor which shows the progress of your task.
The user will know whats going on when he/she sees a progress bar, rather than a dialog that looks like the gui is frozen.
Here is an article by Eclipse on how to use progress monitors correctly.
If you really want to go for your idea (which I would not suggest), you can try the following:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
BazMessageDialog dialog = new BazMessageDialog(shell, "Information", null, "Getting List From Server", MessageDialog.INFORMATION, new String[]{"OK", "Cancel"}, 0);
dialog.open();
/* Do your stuff */
dialog.reallyClose();
shell.dispose();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static class BazMessageDialog extends MessageDialog
{
public BazMessageDialog(Shell parentShell, String dialogTitle,
Image dialogTitleImage, String dialogMessage,
int dialogImageType, String[] dialogButtonLabels,
int defaultIndex) {
super(parentShell, dialogTitle, dialogTitleImage, dialogMessage,
dialogImageType, dialogButtonLabels, defaultIndex);
setBlockOnOpen(false);
}
public void reallyClose()
{
cancelPressed();
}
}
This however, will not block your remaining gui, so the user will be able to use it in the meantime.
EDIT:
Just found out, that Opal has something called an InfiniteProgressPanel, which might be something for you. Have a look...
Not sure if this has been asked before, it's a bit difficult to explain.
I have 2 classes, Class A and Class B
Class A creates an instance of Class B (which is a dialog box using JDialog).
The user is then asked for text input (stored in a String variable).
How do I tell Class A that the user has now updated the variable and get a copy of it?
Using Java Swing btw,
Thanks
T
In general, Observer Pattern deals with such cases
If the dialog is modal, then the code is blocked until the dialog is closed:
dialog.setVisible(true);
// blocked here until the dialog is closed. The dialog stores the input in a
// field when OK is clicked in the dialog
if (dialog.getTextInputtedByTheUser() != null) {
...
If the dialog is not modal, then you need to make it call a callback method when the validation happens. This is what MyFrame would contain
private void showDialog(
MyDialog dialog = new MyDialog(this);
dialog.setVisible(true);
}
public void userHasInputSomeText(String text) {
// do whatever you want with the text
System.out.println("User has entered this text in the dialog: " + text);
}
and in MyDialog:
private MyFrame frame;
public MyDialog(MyFrame frame) {
super(frame);
this.frame = frame;
}
...
private void okButtonClicked() {
String text = textField.getText();
frame.userHasInputSomeText(text);
}
In the Nimbus L&F when one presses the Enter key, if a button has focus, that button is clicked whether or not another button has been set as default as in:
getRootPane().setDefaultButton(myButton);
Also, using Key Binding does not work:
Action clickDefault = new AbstractAction("clickDefault") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Got Here");
getRootPane().getDefaultButton().doClick();
}
};
InputMap im = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
im.put(enter, "defaultButton");
getRootPane().getActionMap().put("defaultButton", clickDefault);
I never even see the "Got Here" message, though if I bind to another KeyStroke, such as "P" it functions as expected. So it would seem that the Enter key is being captured before it gets to this event handler.
I also tried modifying the UIDefaults:
im = (InputMap) UIManager.getDefaults().get("Button.focusInputMap");
im.put(enter, null);
im.put(enterRelease, null);
That failed as well. Anyone have any ideas how to accomplish this?
--- Update ---
Further investigation revealed that the InputMap for JButton contains {"pressed Enter": "pressed", "released ENTER": "released"} (as well as bindings for SPACE). The Key Binding of the Component in question has higher precedence than the RootPane's. See my answer below for code that resolves the problem.
I don't use the Nimbus LAF so I'm not sure how it works.
With the Windows LAF the default button automatically changes to be the button that currently has focus. This is indicated by are darker border on the button that has focus. If focus is not on a button, then the darker border will be reset on the default button.
In Windows you can disable this behaviour by using:
UIManager.put("Button.defaultButtonFollowsFocus", Boolean.FALSE);
Now the darker border will remain on the default button and the Enter key will activate the default button. The button with focus can still be clicked by using the space bar.
Ok, finally figured out how to make this work as I wanted. Here's the code I'm using:
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
// Use Nimbus if it's available and we're not on Mac OSX
if (!System.getProperty("os.name").equals("Mac OS X")) {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
((InputMap) UIManager.get("Button.focusInputMap"))
.put(KeyStroke.getKeyStroke("pressed ENTER"), null);
((InputMap) UIManager.get("Button.focusInputMap"))
.put(KeyStroke.getKeyStroke("released ENTER"), null);
break;
}
}
} catch (Exception e) {
// Default Look and Feel will be used
}
}
MainWindow mainWindow = new MainWindow();
mainWindow.setVisible(true);
}
});
}
} // end class Main
One important thing I figured out was that the updates to the InputMap(s) must be made AFTER setting the Look and Feel. I wasn't aware that was required when messing with these things, but then again, I'm new at this whole Look and Feel business.