Question: Trying to get the same effect as the code below only with JTextArea so I want the JTextArea to be read and spelling suggestions to be recommended every time the user types a new misspelt word.
Below is the working example with 'System.in' which works well.
(Vars userField = JTextArea & dic.txt is a list of the english language for the system to use for suggestions)
CODE (1)
public SpellCheckExample() {
try {
SpellDictionary dictionary = new SpellDictionaryHashMap(new File(dic.txt));
spellCheck = new SpellChecker(dictionary);
spellCheck.addSpellCheckListener(this);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print("Enter text to spell check: ");
String line = in.readLine();
if (line.length() <= 0)
break;
spellCheck.checkSpelling(new StringWordTokenizer(line));
}
} catch (Exception e) {
e.printStackTrace();
}
}
What I have Been trying:
CODE (2)
public void spellChecker() throws IOException{
String userName = System.getProperty("user.home");
SpellDictionary dictionary = new SpellDictionaryHashMap(new File(userName+"/NetBeansProjects/"+"/project/src/dic.txt"));
SpellChecker spellCheck = new SpellChecker(dictionary);
spellCheck.addSpellCheckListener(this);
try{
StringReader sr = new StringReader(userField.getText());
BufferedReader br = new BufferedReader(sr);
while(true){
String line = br.readLine();
if(line.length()<=0)
break;
spellCheck.checkSpelling(new StringWordTokenizer(line));
}
}catch(IOException e){
e.printStackTrace();
}
}
March 3rd 2016 (Update)
public void spellChecker() throws IOException{
// getting context from my dic.txt file for the suggestions etc.
SpellDictionary dictionary = new SpellDictionaryHashMap(new File("/Users/myname/NetBeansProjects/LifeSaver/src/dic.txt"));
SpellChecker spellCheck = new SpellChecker(dictionary);
// jt = JTextField already defined in constructors and attemtpting to pass this into system and
InputStream is = new ByteArrayInputStream(jt.getText().getBytes(Charset.forName("UTF-8")));
//spellCheck.checkSpelling(new StringWordTokenizer(line)); ""ORIGINAL"""
// reccomending cast to wordfinder
spellCheck.checkSpelling(new StringWordTokenizer(is);
}
You don't want to try to drop console UI code into an event-driven GUI, as it will never work like that. Instead you need to use GUI events to trigger your actions, not readln's.
The first thing you must decide on is which event you wish to use to trigger your spell check. For my money, I'd get the user's input in a JTextField, not a JTextArea since with the former, we can easily trap <enter> key presses by adding an ActionListener on the JTextField. You can always use both, and then once the text is spell checked, move it to the JTextArea, but this is exactly what I'd recommend:
use a JTextField,
add an ActionListener to the JTextField to be notified whenever the field has focus and enter is pressed,
within this listener, extract the text from the JTextField, by calling getText() on the field
Then run your spell check code on extracted text,
and output the result into a nearby JTextArea.
Take a look at Concurrency in Swing for reasons why your current approach won't work, then have a look at Listening for Changes on a Document and Implementing a Document Filter for some possible solutions
As someone is bound to mention it, DON'T use a KeyListener, it's not an appropriate solution for the problem
Put simpler, Swing is a single threaded, event driven framework. So anything you do which blocks the Event Dispatching Thread, will prevent it from processing new events, including paint events, making your UI unresponsive
As an event driven environment, you need to register interested in been notified when some event occurs (this is an example of Observer Pattern) and then take appropriate actions based on those events.
Remember though, you can not make changes to a Document via a DocumentListener, so be careful there
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.)
I have a simple GUI that has a jTextField that waits for the user to put in something. After a button is clicked, the program:
reads the input, saves it in a String variable;
opens a new GUI (that is in a separate class file), which contains an empty jLabel, and passes the String variable to it, changing the jLabel text to it.
The problem is that no matter how hard I try to reconfigure the code, adding things like repaint(), revalidate(), etc., the jLabel in the second GUI stays empty. Using a System.out.println(jLabel.getText()) reveals that the text value is indeed changed, but not displayed. How do I "refresh" this jLabel, so it'd show what I want it to? I'm aware I could add an event, though I don't want the user to click anything to refresh the GUI, the values should be there as it's initiated. I've read trough several similar posts, but found that the solutions don't work for me.
The code of first GUI's button click event:
private void sbuttonActionPerformed(java.awt.event.ActionEvent evt) {
errortext.setText("");
Search = sfield.getText();
Transl = hashes.find(Search);
if (Transl.equals("0")) errortext.setText("Word not found in database.");
else {
ws.run(Search, Transl); // <- this opens the second GUI, with two String parameters I want to display in the second GUI;
}
}
The code of the second GUI (activeword and translation are the jLabels that are giving me trouble.):
public void run(String Search, String Transl) {
WordScreen init = new WordScreen(); //initialise the second GUI;
init.setVisible(true);
activeword.setText(Search);
translation.setText(Transl);
}
Any reply is very welcome! Please ask me for more information about the code if necessary, I will make sure to reply as soon as possible!
Best solution: change WordScreen's constructor to accept the two Strings of interest:
From this:
public void run(String Search, String Transl) {
WordScreen init = new WordScreen(); //initialise the second GUI;
init.setVisible(true);
activeword.setText(Search);
translation.setText(Transl);
}
to this:
public void run(String search, String transl) {
WordScreen init = new WordScreen(search, transl);
init.setVisible(true);
}
Then in the WordScreen constructor use those Strings where needed:
public WordScreen(String search, String transl) {
JLabel someLabel = new JLabel(search);
JLabel otherLabel = new JLabel(transl);
// put them where needed
}
Note that I cannot create a comprehensive answer without your posting a decent MRE
As an aside, you will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
I have rename dialog for rename file
String renameTo = JOptionPane.showInputDialog(gui, "New Name", currentFile.getName());
it works this way, but I have a problem.
the problem is that I set the default value with the extension of the file
but I just want the file name to be selected.
sample : my file name = yusuf.png
I want select only yusuf like;
There is a lot going on inside JOptionPane, it's one of the things that makes it so powerful, it also makes it a little inflexible to.
Two immediate problems are apparent...
You can't gain direct access to the JTextField been used to get input from the user
The JOptionPane wants to control which components have focus when the dialog is first shown.
Setting up the JTextField is actually straight forward...
String text = "yusuf.png";
int endIndex = text.lastIndexOf(".");
JTextField field = new JTextField(text, 20);
if (endIndex > 0) {
field.setSelectionStart(0);
field.setSelectionEnd(endIndex);
} else {
field.selectAll();
}
This will basically select all the text from the start of the String up to the last . or all the text if no . can be found.
The difficult part now is taking back focus control from the JOptionPane
// Make a basic JOptionPane instance
JOptionPane pane = new JOptionPane(field,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION,
null);
// Use it's own dialog creation process, it's simpler this way
JDialog dialog = pane.createDialog("Rename");
// When the window is displayed, we want to "steal"
// focus from what the `JOptionPane` has set
// and apply it to our text field
dialog.addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) {
// Set a small "delayed" action
// to occur at some point in the future...
// This way we can circumvent the JOptionPane's
// focus control
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
field.requestFocusInWindow();
}
});
}
});
// Put it on the screen...
dialog.setVisible(true);
dialog.dispose();
// Get the resulting action (what button was activated)
Object value = pane.getValue();
if (value instanceof Integer) {
int result = (int)value;
// OK was actioned, get the new name
if (result == JOptionPane.OK_OPTION) {
String newName = field.getText();
System.out.println("newName = " + newName);
}
}
And, crossing our fingers, we end up with something looking like...
Personally, I'd wrap this up in a nice reusable class/method call which returned the new text or null based on the action of the user, but that's me
Isn't there an easier way?
Of course, I just like showing you the most difficult solution possible ... 😳 (sarcasm) ... it's kind of why I suggested wrapping it up in it's own utility class, so you can re-use it later 😉
I call a class that creates a jframe and waits from user to input some values.
The problem that I experience is that I need to wait these values before to continue.
So the code is something simple like this
Jframe frame= new jframe(); //here I want the program to show the frame and then wait till it will be disposed
// I want a pause here
System.out.println(frame.getvalue);
Till now the only I could do is to froze the frame before can even appear totally.
Any help?
Please keep it simple since I am new to Java.
THANK YOU!
I think you should use JDialog instead of JFrame. Please follow this example
What you're probably looking for is JOptionPane. This is a blocking routine that returns only after the user has entered some value, like so:
public class test
{
public static void main ( String args[] )
{
String input = JOptionPane.showInputDialog(null, "Thing: ",
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
System.out.println ( "won't reach until got input");
System.out.println ( "My value: " + input );
}
}
The great thing about it is you can add Components to it, so you aren't limited to a single input field, but it is still blocking. The following would add two JTextField's to the frame:
public class test
{
public static void main ( String args[] )
{
JTextField input_box = new JTextField(7);
JTextField input_box2 = new JTextField(7);
JComponent[] inputs = new JComponent[] {
new JLabel("Thing 1:"),
input_box,
new JLabel("Thing 2:"),
input_box2 };
int rval = JOptionPane.showConfirmDialog(null, inputs,
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
if ( rval == 0)
{
System.out.printf ("%s and %s!", input_box.getText(),
input_box2.getText());
}
}
}
Instead of using a JFrame, consider using a JDialog with modality set to true.
When it comes time to add an 'OK' button or something like that, check out JRootPane.setDefaultButton()
well as you know swing components are not thread safe though you can use SwingWorker to make the waiting in background,
It uses the thread way but it creates a new thread for the waiting ,long term operations in general,
instead of pausing the event dispatch thread so the user can interact with the rest of the application or the rest of the application can continue to work while the waiting goes on.
ofcourse you have to define a way for it to stop the waiting.
check out its documentation here http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
This will cause the current thread to wait 5 seconds:
try {
Thread.currentThread().wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
What is the general approach with Java swing to update a textarea with lines of text (say from a Thread) and then have the text caret flow to the bottom of the textarea as text is being added. Also update the scrollbar so that it is at the bottom.
I was thinking that I would have a stringbuffer and append text to that and then set the string in the textarea and position the scrollbar at the bottom.
Use append() to add the text, then setCaretPosition() to make sure you scroll with it.
myTextPane.append(textFromSomewhere);
myTextPane.setCaretPosition(myTextPane.getDocument().getLength());
The append() method doesn't do what you want?
And although you didn't ask: when you're generating something in a background thread, be sure to use SwingUtilities.invokeLater() to update your components.
From another thread, you should use java.awt.EventQueue.invokeLater to get on the EDT and then everything works.
So:
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
Document doc = text.getDocument();
int origLen = doc.getLength()
try {
doc.insertString(origLen, msg, null);
} catch (BadLocationException exc) {
// Odd APIs forces us to deal with this nonsense.
IndexOutOfBoundsException wrapExc = new IndexOutOfBoundsException();
wrapExc.initCause(exc);
throw wrapExc;
}
// IIRC, Position is a bit odd and
if (origLen == 0) {
text.setCaretPosition(doc.getLength());
}
}});
Should anyone read the API docs for JTextArea.append it claims to be thread-safe. JDK7 removes that unlikely claim (reminder: threading is hard). As a rule, in Swing I tend to always go straight for the model/Document.
I believe if the caret is at the end it should get moved on after an append. The only exception is if there is no text, because of the strange API. If it has been moved, then we probably don't want to update it after the append.
Note: If multiple threads are doing this, you don't necessarily know which will get there first.
If you are updating from a Thread, dont forget to use SwingWorker or some other AWT Thread-safe approach.
You can update the scrollbar without reading doc.length with:
scrollbar.setValue(scrollbar.getMaximum());
Update (wrapped into Invoke later, code from Tom Hawtin)
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
try {
textArea.append(msg);
} catch (BadLocationException exc) {
// Odd APIs forces us to deal with this nonsense.
IndexOutOfBoundsException wrapExc = new IndexOutOfBoundsException();
wrapExc.initCause(exc);
throw wrapExc;
}
JScrollBar bar = scrollPane.getVerticalScrollBar();
bar.setValue(bar.getMaximum());
}});