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.)
Related
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.
Glad to be on this very helpful website. I have a problem with my Java program that will probably either be an easy fix, or impossible to fix.
You know how when you run a program that's open in NetBeans, it shows the output within the NetBeans application? I am trying to create a program that allows anybody who puts it on their computer to execute it, even if they have not installed an IDE like NetBeans or Eclipse. And when somebody executes my program, I want it to show the same thing as when I run it in NetBeans, with the same output and everything. The program doesn't use a GUI or anything like that. I managed to create an executable .jar file with the "Clean and build project" option, and I made a .bat file that successfully executes the program. This should achieve my goal of allowing anyone to run it. When I start up the .bat file, it works, and shows a white-text-black-background screen that runs the program exactly as it ran while in NetBeans.
The problem is that when I run the program (with the .bat file), the text is too small... I've tried looking everywhere for a solution to this, but I could only find discussion about how to make things work with GUIs, or other more complicated things than what my program needs. I am willing to work with GUI stuff if it is necessary, but I don't think it will help, due to what a GUI is. From my understanding, a GUI is not one big thing, but is a user interface composed of smaller parts (such as pop-up input prompts and scroll bars) that are each made by the programmer. I don't need any fancy scroll bars etc., I just need my program to execute like it does when ran in NetBeans (pretty sure this is called the console), and I need to change the text size of the program text when it executes.
I greatly appreciate any help, even if you aren't sure if it will work or not. If the answer requires a lengthy explanation and you don't feel like explaining, that's okay; just tell me what I'd have to learn to figure this out and I can research it if necessary.
I just created one. Try using this one and tell us if it helped or not.
EDIT Added a JTextField to read data. It is more advanced code than the previous one, since it uses concurrency. I tried to make it simple, these are the functions you can use:
MyConsole (): Constructor. Create and show the console
print (String s): Print the s String
println (String s) Print the s String and add a new line
read (): Makes you wait untill the user types and presses Enter
closeConsole (): Closes the console
Here is the code:
public class MyConsole implements ActionListener {
private JFrame frame;
private JTextArea myText;
private JTextField userText;
private String readText;
private Object sync;
/*
* Main and only constructor
*/
public MyConsole() {
// Synchronization object
sync = new Object();
// Create a window to display the console
frame = new JFrame("My Console");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setContentPane(createUI());
frame.setVisible(true);
}
/*
* Creates user interface
*/
private Container createUI() {
// Create a Panel to add all objects
JPanel panel = new JPanel (new BorderLayout());
// Create and set the console
myText = new JTextArea();
myText.setEditable(false);
myText.setAutoscrolls(true);
myText.setBackground(Color.LIGHT_GRAY);
// This will auto scroll the right bar when text is added
DefaultCaret caret = (DefaultCaret) myText.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
// Create the input for the user
userText = new JTextField();
userText.addActionListener(this);
panel.add(new JScrollPane(myText), BorderLayout.CENTER);
panel.add(userText, BorderLayout.SOUTH);
return panel;
}
/*
* Waits until a value is typed in the console and returns it
*/
public String read(){
print("==>");
synchronized (sync) {
try {
sync.wait();
} catch (InterruptedException e) {
return readText = "";
}
}
return readText;
}
/*
* Prints s
*/
public synchronized void print(String s){
// Add the "s" string to the console and
myText.append(s);
}
/*
* Prints s and a new line
*/
public synchronized void println(String s){
this.print(s + "\r\n");
}
/*
* Close the console
*/
public void closeConsole(){
frame.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
// Check if the input is empty
if ( !userText.getText().equals("") ){
readText = userText.getText();
println(" " + readText);
userText.setText("");
synchronized (sync) {
sync.notify();
}
}
}
}
Here is how to use it (an example). It just asks your age and writes something depending on your input:
public static void main(String[] args) {
MyConsole console = new MyConsole();
console.println("Hello! (Type \"0\" to exit)");
int age = 1;
do{
console.println("How old are you ?");
String read = console.read();
try {
age = Integer.valueOf(read);
if ( age >= 18){
console.println("Wow! " + age + " ? You are an adult already!");
}else if ( age > 0 ){
console.println("Oh! " + age + " ? You are such a young boy!");
}else if (age == 0){
console.println("Bye bye!");
}else{
console.println("You can't be " + age + " years old!");
}
}catch (Exception e) {
console.println("Did you write any number there ?");
}
} while ( age != 0 );
console.closeConsole();
}
And here is a image:
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
Today I have another project that involves the program I have written for work and been working on for well over 6 months. There is a lot of code and classes so I'm going to try to explain the best that I can so you can (hopefully) help me.
Currently my program works by reading a file and allowing a user to make some modifications to that file, then a new file is written. This entire process involves a GUI that is better explained as a series of JOptionPanes, some with imbedded panels.
Here is my goal: Each file uploaded comes with a given number of "batches". My program loops through once for each batch. During a loop each of the relevant JOptionPane GUI's is displayed. When all batches are read the program ends and the file is complete.
I have been asked to add a feature where the entire "project" is inside of a JFrame with a new "upload" button. This would allow the user to run the program multiple times without having to open the JAR over and over again. If they select "Upload" they essentially start the program over.
Here is my main class:
package nachamultifive;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import nachamultifive.Buffered_Reader_Writer.BatchCounter;
import nachamultifive.Buffered_Reader_Writer.FileValidation;
import nachamultifive.Buffered_Reader_Writer.MainWriter;
import nachamultifive.GUIs.FileHandling;
import nachamultifive.GUIs.ReturnBuilderGUI;
public class NachaMain
{
public static JFileChooser saveFile;//The output file save location.
public static JFileChooser uploadFile;//The uploaded NACHA file.
public static int batchTotal;//The total number of batches in the file.
public static ArrayList<String> batchHeaders;//An array of all batch headers.
public static int batchCounter;//The counter that displays the current batch number in sequence.
public static String location;
public static void main(String args[]){
FileHandling fHandling = new FileHandling();//The class that handles upload/save of files.
fHandling.getFile();//Allows the user to upload a file.
fHandling.setDirectory();//Allows the user to choose the save location.
saveFile=fHandling.saveFile;//Sets the file save location as static with the main class.
uploadFile=fHandling.uploadFile;//Sets the uploaded file as static with the main class.
BatchCounter bCounter = new BatchCounter();//The class that handles counting the batches.
bCounter.getBatches();//Counts the total number of batches.
batchTotal=BatchCounter.BatchTotal;//Sets the total number of batches as static with the main class.
batchHeaders=bCounter.batchHeaders;//Sets the batch header array as static with the main class.
MainWriter mWriter = new MainWriter();//The class that handles all writing functions for the new file.
mWriter.writeNacha();//Writes the output file.
location = MainWriter.location;
System.out.println("NachaMain Location=" + location);
FileValidation fValidation = new FileValidation();//The class that handles validating the output ACH file.
fValidation.validateNacha();//Method to validate the ACH file.
ReturnBuilderGUI gui = new ReturnBuilderGUI();//Class used for GUI's.
gui.displayFileOption();//Method used to display the ACH output and error report name.
gui.showSavedErrors();//Method to display the error report.
}
}
Essentially each of the classes calls modifies the input file. Inside of the mWriter class you will see this bit of code:
ReturnBuilderGUI gui = new ReturnBuilderGUI();//The GUI class.
ReturnBuilderGUI.displayGUI();//Calls the GUI to display the initial double list GUI.
Calling that class calls the entire GUI for that loop. (The mWriter class loops for each batch). When the ReturnBuilder class is called this is the basic code layout:
public static void displayGUI(){//Method to display the GUI.
final JButton createReturnButton = new JButton("Create Return");
createReturnButton.addActionListener(new ActionListener(){
public void actionPerformed(final ActionEvent ae){
if(verifyBatch==true){
initialScreenDecisions="NONE";//The user did not choose to add any entry details to the output list.
MainWriter.finishedCounter=true;//The boolean counter to trigger that the return is finished goes to true.
while(MainWriter.entryDetails.size()>0){//Removes all entry details from the input list.
MainWriter.entryDetails.remove(0);
}
while(output.size()>0){//Removes all entry details from the output list..
output.remove(0);
}
JOptionPane.getRootFrame().dispose();
}else {
JOptionPane.showMessageDialog(null, "No batches have been completed!");
}
}
});
final Object[] createR = new Object[] { "Confirm",createReturnButton };
int result = JOptionPane.showOptionDialog(null, getPanel(),"Return Builder", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE, null, createR, "default");
System.out.println(verifyBatch);
//Creates a JOptionPane for the first GUI featuring 7 buttons and 2 lists..
}
The getPanel() method inside of that JOptionsPane calls the panel that has some buttons and lists. Depending on what the user chooses some more JOptionPane's will appear that give the user more options. When they are finished the initial mWriter class will loop again (assuming there are more batches in the input file) and the ReturnBuilder class will be called again restarting the process.
Now, I can't for the life of me figure out a way to make all this happen inside of a JFrame that remains before and after all these other things happen without having to restructure my code.
I don't know if I've given you guys enough information to work with. My only idea right now is that I feel like I need to create a JFrame in the ReturnBuilder class and add the JOptionsPane to it, but then when the ReturnBuilder class is called again later I'm sure the JFrame would just open again and be duplicate.
Any ideas?
It really looks to me that you need to use Cardlayout and flip to the next card at each step. When you are done, reset by flipping to the first card. CardLayout is cyclic, so it will flip to the first card automatically.
public class CardExample extends JFrame {
CardExample() {
JPanel main = new JPanel(new BorderLayout());
CardLayout cl = new CardLayout();
main.setLayout(cl);
for (int i = 0; i < 4; i++)
main.add(new StepPanel(i));
JButton next = new JButton("Next");
next.addActionListener(e -> cl.next(main));
add(main);
add(next, BorderLayout.PAGE_END);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
class StepPanel extends JPanel {
StepPanel(int i){
add(new JLabel("Step " + i));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new CardExample());
}
}
All of this is instead of JOptionPanes, which is usually more comfortable for a step-by-step user interaction (see, for example, installers). Just customize each of what I called StepPanels and at the end you can use a "load and reset" button instead of "next".
I want to connect sharp network scanner using morena api and twain. Everything is ok if scanner is reachable but when scanner is not reachable, jni library opens a select scanner window. I think it is twain ds screen, I want to disable this screen. If scanner is not reachable, I want to throw error instead of open select device window. When I stop application, this screen also close so I think it depends on java thread. Question is, how can I stop this window's thread without stop whole program. I can run main method in another thread, and I can find this thread id, but when I stop this thread it is not close select device window.
import SK.gnome.morena.Morena;
import SK.gnome.morena.MorenaException;
import SK.gnome.morena.MorenaImage;
import SK.gnome.morena.MorenaSource;
import SK.gnome.twain.TwainManager;
import SK.gnome.twain.TwainSource;
import javax.swing.*;
public class HelloWorld
{ public static void main(String[] args) throws MorenaException
{
TwainSource[] list = null;
try {
list = TwainManager.listSources();
} catch (Exception var4) {
list = null;
}
MorenaSource source= list[1];
System.err.println("Selected source is "+source);
if (source!=null)
{ source.maskUnsupportedCapabilityException(false); // Lesson 3
source.maskBadValueException(false); // Lesson 3
source.setVisible(false); // Lesson 2
source.setColorMode(); // Lesson 2
source.setResolution(300); // Lesson 2
((TwainSource)source).setUnits(TwainSource.TWUN_CENTIMETERS);
source.setFrame(0, 0, 7.8, 10.5);
System.err.println("Image resolution is "+source.getResolution());
MorenaImage image=new MorenaImage(source);
System.err.println("Size of acquired image is "
+image.getWidth()+" x "
+image.getHeight()+" x "
+image.getPixelSize());
}
Morena.close();
}
}
Do you ever want the window itself to pop up? If not you can try TwainManager.getDefaultSource() instead of hardcoding list[1], or TwainManager.listSources() to either build your own selection or evaluate for 0 results and throw your own error.
To use TwainManager.getDefaultSource():
MorenaSource source = TwainManager.listSources();
See Morena's TWAIN JTP Support for more info.