Is there an alternative to JPasswordField? - java

When typing a passphrase like
yeast bulk seize is shows pain
everybody can hear tapping the space bar, so it seems logical to display the spaces in the password field, too. So I'd like something capable of showing
***** **** ***** ** ***** ****
instead of
******************************
This would make typing easier while hardly decreasing the security.
UPDATE
Think twice before you update Riduidel's comment. When Bruce Schneier writes "It's time to show most passwords in clear text", then showing a small part of it must be correct, too. Especially showing a part which may get captured simply by listening.

Here's a variation that uses setEchoChar() to make the password visible for a predefined time: three seconds for example.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.Timer;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/** #see http://stackoverflow.com/questions/5339702 */
public class PasswordTest {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
JFrame jf = new JFrame("Test Password");
JPasswordField jpwd = new JPasswordField();
TimedPasswordListener tpl = new TimedPasswordListener(jpwd);
jpwd.getDocument().addDocumentListener(tpl);
jf.add(jpwd);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
jf.pack();
jf.setVisible(true);
}
}
class TimedPasswordListener implements DocumentListener, ActionListener {
private Timer timer = new Timer(3000, this);
private char echoChar;
private JPasswordField pwf;
public TimedPasswordListener(JPasswordField jp) {
pwf = jp;
timer.setRepeats(false);
}
public void insertUpdate(DocumentEvent e) {
showText(e);
}
public void removeUpdate(DocumentEvent e) {
showText(e);
}
public void changedUpdate(DocumentEvent e) {}
public void showText(DocumentEvent e) {
if (0 != pwf.getEchoChar()) {
echoChar = pwf.getEchoChar();
}
pwf.setEchoChar((char) 0);
timer.restart();
}
public void actionPerformed(ActionEvent e) {
pwf.setEchoChar(echoChar);
}
}

Was thinking JPasswordField was simply a JTextField simply overriding the renderer component, but it seems not to be the case.
So, instead of changing the renderer (like it would be the case if JTextField had such a component), you'll have to use a JTextField with a custom Document holding two strings :
Password text as written by user
Displayed password
You'll have to make sure all Document modifying methods change the password text, while all rendering methods use the displayed one.

Related

Inheritence of a JButton Java - Overriding Method Issue

I am wanting to set the visibility of a JButton to false in another class. So what I am doing is overriding the boolean function I created in StudentAccount named getWriteBtnVisibility() to change the visibility of the button in the HW class. So basically I want to make the JButton invisible in the StudentAccount. Since I want that button to be visible when a different type of account is logged in.
However, the way I am doing it seems not to be working. I have debugged my code and not understanding why it is not overriding the function. If I can get some guidance, I'd greatly appreciate it.
StudentAccount:
import java.awt.EventQueue;
public class StudentAccount extends AccountTemplate {
/**
* Launch the application.
*/
#Override
public String getHomeworkBtnName() {
return "Submit Assignment";
}
#Override
public boolean getWriteBtnVisibility() {
return false;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
StudentAccount window = new StudentAccount();
window.frmAccountTemplate.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
AccountTemplate:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class AccountTemplate extends HW {
protected JFrame frmAccountTemplate;
/**
* Launch the application.
*/
public String getHomeworkBtnName() {
return "Hw";
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AccountTemplate window = new AccountTemplate();
window.frmAccountTemplate.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public AccountTemplate() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
protected void initialize() {
frmAccountTemplate = new JFrame();
frmAccountTemplate.setTitle(getFrameTitleName());
frmAccountTemplate.setBounds(100, 100, 450, 300);
frmAccountTemplate.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmAccountTemplate.getContentPane().setLayout(null);
JButton btnAssignment = new JButton(getHomeworkBtnName());
btnAssignment.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frmAccountTemplate.dispose();
HW.main(null);
}
});
btnAssignment.setFont(new Font("Tahoma", Font.BOLD, 16));
btnAssignment.setBounds(15, 51, 200, 29);
frmAccountTemplate.getContentPane().add(btnAssignment);
}
}
HW:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.filechooser.FileSystemView;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.awt.event.ActionEvent;
public class HW {
public JFrame frmHw;
/**
* Launch the application.
*/
public boolean getWriteBtnVisibility() {
return true;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HW window = new HW();
window.frmHw.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public HW() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
protected void initialize() {
frmHw = new JFrame();
frmHw.setTitle("HW");
frmHw.setBounds(100, 100, 450, 300);
frmHw.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmHw.getContentPane().setLayout(null);
JTextArea jTextArea1 = new JTextArea();
jTextArea1.setBounds(9, 11, 328, 197);
frmHw.getContentPane().add(jTextArea1);
JScrollPane scrollBar = new JScrollPane(jTextArea1);
scrollBar.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollBar.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
frmHw.getContentPane().add(scrollBar);
scrollBar.setBounds(13, 39, 413, 189);
JButton btnWriteText = new JButton("Write Text");
btnWriteText.setVisible(getWriteBtnVisibility());
btnWriteText.setBounds(154, 11, 115, 24);
frmHw.getContentPane().add(btnWriteText);
}
}
When you made AccountTemplate extend the HW class, every method that was redefined in AccountTemplate overrided the original method from HW. The getWriteBtnVisibility is checked from within the HW's initialize method, but AccountTemplate's initialize method overrides it. Now StudentAccount inherits the overridden method which does not check for the getWriteBtnVisibility boolean and so the visibility is not modified.
If I understand correctly what you're trying to do is to extend the layout using inheritance, however to do that you need to create seperate methods that create and initialize the interface components and call them as required from class. Now you've only created a seperate method for the button name and visibility, but the method that checks for the visibility boolean has been overridden and no longer gets called.
You will have to redesign your architecture so that:
There is only one JFrame field (unless you want multiple interfaces)
There is only one method that creates the JFrame and sets up the title
All generic interface components are created using a seperate (final) method and can be called when required by the class that inherits it
A simple example
class HW {
public JFrame frame;
public String getFrameName() {
return "HW";
}
public boolean getHWBtnVisibility {return true;}
void setupHWComponents() {
JTextField field = new JTextField();
// ...
this.frame.getContentPane().add(field);
JButton button = new JButton("HW");
button.setVisible(getHWBtnVisibility());
// ...
}
void initFrame() {
this.frame = new JFrame(getFrameName());
// ....
}
void initialize() {
initFrame();
setupHWComponents();
}
}
And
class AccountTemplate {
public void setupTemplateComponents() {
JTextField loginField = new JTextField("login");
super.frame.getContentPane().add(loginField);
// ...
}
#Override
public void initialize() {
// Setup Frame and HW components
// If you dont want HW components, replace with initFrame()
super.initialize();
setupTemplateComponents();
}
}
Then the StudentAccount class can likewise choose what components to use and initialize and which ones it doesn't want and then it can add its own components to the frame.
The initialize method that matters, that sets the button's visibility is the one that is called from the HW class, and that method is only called from within AccountTemplate's button's ActionListener here:
public void actionPerformed(ActionEvent e) {
frmAccountTemplate.dispose();
HW.main(null);
}
Notice that it is a call to the HW main method, and so it is a HW instance that is being created when this happens (since that is what HW main creates), not a StudentAccount instance. This is why your inheritance doesn't work -- there is no inheritance happening when the button is created.
Having said that, I have to state that this code is overly complex, much more than it needs to be, and misuses inheritance in a way that only serves to confuse. Don't use inheritance (or absolute positioning and null layouts) since you're just complicating things needlessly. Simply your code and you will thank me.
If this were my project,
I would create distinct JPanels (not JFrames) for each type of GUI
I would use inheritance only for the program's model, the logical non-GUI aspects of the code, and not for the views (the GUI classes), and would use it very cautiously.
I would swap views using a CardLayout and not swap JFrames

Make a JTextField recieve input even with windows not focused

I'm working on a small personal project.
I have two JFrame windows, Viewer and Console.
Viewer only contains a subclass of JPanel, and it should respond to mouse input (clicking, mostly).
Console contains a button, a JTextField (the input), and a JTextArea (the output).
I need to make sure than when I press keys on my keyboard, the corresponding text appears in the Console JTextField, not only when the focus is held by the JTextField, but also when it's held any other component in my app.
In other words, I want the JTextField to accept input even right after I clicked on the Viewer frame.
Is this feasible?
In case that matters, I'm running win 8 x64 and I don't really care about portability (I'm the only one that will ever look at or use this code).
EDIT: here is an example of my code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class main {
public static Viewer v;
public static Console c;
public static void main(String[] args) {
v=new Viewer();
c=new Console();
}
static class Viewer extends JFrame {
public Viewer(){
setSize(600,600);
getContentPane().add(new myPanel());
addMouseListener(new mouse());
setVisible(true);
}
}
static class myPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255)));
g.fillRect(0, 0, 600, 600);
}
}
static class Console extends JFrame {
public Console(){
setSize(600,200);
JTextField text=new JTextField();
getContentPane().add(text);
setVisible(true);
}
}
static class mouse implements MouseListener{
#Override
public void mouseClicked(MouseEvent arg0) {
v.repaint();
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
}
In this example, after I click on the big window to change its color, if I want to write stuff in the other window I have to click on it first.
Can I suggest the KeyboardFocusManager? I've found this to be the easiest way to achieve what I believe you are trying to achieve
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
new KeyEventDispatcher() {
public void dispatchKeyEvent(KeyEvent ke) {
//TODO: fill this in
}
});
One inelegant solution is to create a KeyListener, which feeds typed characters to your console, although how exactly this happens depends on how you create your components. For the sake of this example I'll pretend to do it through a static method in your Console class (preferably you'd have access to an instance of Console):
public class ApplicationKeyListener implements KeyListener {
public ApplicationKeyListener() {
}
// Other necessary methods...
public void keyPressed(KeyEvent e) {
char pressed = e.getKeyChar();
Console.feedChar(pressed);
}
}
And then in Console, make sure your JTextField object is global and static, then set up the feedChar() method.
public class Console extends JFrame {
private static JTextField consoleTextField;
public Console() {
consoleTextField = new JTextField();
// ...
}
public static feedChar(char c) {
consoleTextField.setText(consoleTextField.getText() + c.toString());
}
}
Then finally you'd have to add this listener to all JFrames and their children.
public class Viewer extends JFrame {
public Viewer() {
ApplicationKeyListener kl = new ApplicationKeyListener();
addKeyListener(kl);
for (Component child : this.getComponents()) {
child.addKeyListener(kl);
}
}
}

Detect CTRL+V in Swing App but keep original function

Wrting a chat application, I want the user to be able to send images out of his/her clipboard. For this, I would like to catch any CTRL+Vkeyboard input. Since pasting text should be possible as by default, the original ctrl+v-function (pasting text) must not be overridden.
I see can two approaches, of which none works for me:
1st: Taken from the official Java documentation: KEY LISTENER
editorPane.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
e.getKeyChar()
// when I press ctrl+v, ^ this is falsely a white square character, looks like (U+25A1). Plain v without ctrl does work.
e.getKeyCode()
// ^ this is falsely 0
// (e.getModifiersEx() correctly returns InputEvent.CTRL_DOWN_MASK)
}
2nd: KEY BINDING
InputMap iMap = editorPane.getInputMap(condition);
ActionMap aMap = editorPane.getActionMap();
iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), "ctrlV");
aMap.put("ctrlV", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// works, but overrides natural ctrl+v function!
}
});
Any ideas?
Note: I am using a "foreign" keyboard layout (German). But I can't see why this should make any difference - I would pretty much like to have my application work internationally.
Cheers
edit. Alt+SomeKey however is correctly recognized by the KeyListener
edit2. after changing keyboard layout to US, problem persists.
Stick to Keybindings: KeyListener is a low-level API, while Keybindings will provide you consistent, predictable and robust behaviour.
The solution here is quite easy. You can simply combine the actions yourself by adding a CombinedAction class that will execute the "original" action bound to CTRL+V and the "custom" action you want to execute.
See a small example below combining both actions (here my custom action is a Sysout):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
public class TestEditorPane {
private JEditorPane editorPane;
public static class CombinedAction implements ActionListener {
private final ActionListener action1;
private final ActionListener action2;
public CombinedAction(ActionListener action1, ActionListener action2) {
super();
this.action1 = action1;
this.action2 = action2;
}
#Override
public void actionPerformed(ActionEvent e) {
if (action1 != null) {
action1.actionPerformed(e);
}
if (action2 != null) {
action2.actionPerformed(e);
}
}
}
public TestEditorPane() {
}
private void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JTEXTBOX
editorPane = new JEditorPane();
KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
final ActionListener ctrlVAction = editorPane.getActionForKeyStroke(ctrlV);
editorPane.registerKeyboardAction(new CombinedAction(ctrlVAction, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("This is my action on CTRL+V");
}
}), ctrlV, JComponent.WHEN_FOCUSED);
// JSCROLLPANE
JScrollPane scroll1 = new JScrollPane(editorPane);
scroll1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
frame.add(scroll1);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestEditorPane test = new TestEditorPane();
test.initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

What kind of voodoo is necessary to get the glassPane visible and valid for an JInternalFrame?

I have a project where I use JDesktopPane for the main application and a bunch of JInternalFrames for a series of independent analyses.
Certain bits of the analyses are time-consuming thus I run them on SwingWorkers, but I would like to both disable the GUI (so no actions are queued) and inform the user that some action is going on and that it's normal.
Previously I have used a custom GlassPane for that purpose, and it has worked nicely before. Now I am experiencing some issues, using the same class as before. Specifically, the glassPane intercepts user input, expected but no visual cue is visible, which makes me think that the paintComponent() is never called on the glassPane.
Just to be sure I googled and came across another implementation (called DisabledGlassPane) of the "please-wait-glassPane" concept but to no success really. While trying to debug the issue I realised that when I start/activate my glassPane it is invalid by default and does not get validated by itself.
If I specifically call validate() on the JInternalFrame after activating the glassPane, it appears to be valid and visible, based on the properties of the glassPane but I see nothing on the screen (both GlassPane implementations have color and text based features that should be immediately visible to the user).
EDIT:
Below is the relevant piece of the code, extracted out of the bigger scheme of things into a minimalist, self-contained (with the exception of the DisabledGlassPane class mentioned above, omitted for the sake of brevity) example. When I run the DesktopFrame class below, and click the button the calculations start, the cursor changes to waiting mode, however the screen is not grayed out, and the message to the user is not displayed, hence my suspicion of paintComponent is never actually called..
I am primarily wondering if I have made an obvious miss, since I am not that experienced with GUI programming and Swing.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.SwingWorker;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
public class DesktopFrame extends JFrame implements InternalFrameListener{
private JDesktopPane dpane;
private JInternalFrame f;
static DisabledGlassPane gp = new DisabledGlassPane();
public DesktopFrame() {
dpane = new javax.swing.JDesktopPane();
dpane.setPreferredSize(new java.awt.Dimension(1020, 778));
setContentPane(dpane);
addFrame();
pack();
}
public JInternalFrame addFrame(){
f = new JInternalFrame("test");
f.setGlassPane(gp);
f.addInternalFrameListener(this);
f.setLayout(new GridLayout());
f.setPreferredSize(new java.awt.Dimension(400,300));
f.add(new javax.swing.JLabel("something something"));
f.add(new javax.swing.JTextArea(10, 10));
javax.swing.JButton but = new JButton("click me!");
but.setPreferredSize(new java.awt.Dimension(100,50));
but.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
gp.activate("Please wait...");
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
for(float i=-3000; i < 3000; i = i + 0.01f){
double exp = Math.pow(2,i);
double fac = Math.pow(i, 2);
System.out.println(exp/fac);
}
return null;
}
};
worker.execute();
try {
if(worker.get() == null)
gp.deactivate();
} catch (InterruptedException | ExecutionException e1) {
e1.printStackTrace();
}
}
});
f.add(but);
f.setVisible(true);
f.pack();
dpane.add(f);
try {
f.setSelected(true);
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace();
}
dpane.repaint();
return f;
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
DesktopFrame df = new DesktopFrame();
df.setLocationRelativeTo(null);
df.setVisible(true);
df.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
});
}
#Override
public void internalFrameOpened(InternalFrameEvent e) {}
#Override
public void internalFrameClosing(InternalFrameEvent e) {}
#Override
public void internalFrameClosed(InternalFrameEvent e) {}
#Override
public void internalFrameIconified(InternalFrameEvent e) {}
#Override
public void internalFrameDeiconified(InternalFrameEvent e) {}
#Override
public void internalFrameActivated(InternalFrameEvent e) {}
#Override
public void internalFrameDeactivated(InternalFrameEvent e) {}
}
but I would like to both disable the GUI (so no actions are queued) and inform the user that some action is going on and that it's normal.
Check out the Disable Glass Pane for a general solution you might be able to use. The above class intercepts mouse and key events and allows you to display a message while the glass pane is visible.

Is it Possible to Add ActionListener in the JFormattedTextField?

Hello I'm currently working in my java file.
I'd like to add an event on JFormattedTextField when I press the enter key.
This is my code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.MaskFormatter;
import java.awt.*;
import java.text.ParseException;
public class Test extends JFrame implements ActionListener
{
JFormattedTextField phoneField;
Test()
{
setTitle("JFormatted Text");
setLayout(null);
MaskFormatter mask = null;
try {
mask = new MaskFormatter("##########");
} catch (ParseException e) {
e.printStackTrace();
}
phoneField = new JFormattedTextField(mask);
phoneField.setBounds(20, 20, 150, 30);
phoneField.addActionListener(this);
setVisible(true);
setSize(200, 200);
getContentPane().add(phoneField);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new Test();
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()== phoneField)
{
System.out.println("The numbers you enter are "+phoneField.getText());
}
}
}
it works but their the user needs to enter 10 digits.
Add an ActionListener to the field. It is better than using the (low level) KeyListener and will conform to whatever that OS accepts as 'end of entry'.
Don't use KeyListener instead use DocumentListener.
It has the following methods which captures the changes in the JTextField
JTextField textField = new JTextField();
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent arg0) {
// Gives notification that a portion of the document has been removed.
}
#Override
public void insertUpdate(DocumentEvent arg0) {
// Gives notification that there was an insert into the document.
}
#Override
public void changedUpdate(DocumentEvent arg0) {
// Gives notification that an attribute or set of attributes changed.
}
});
You could add a keyListener instead.
phonefield.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
if(evt.getKeyCode() == evt.VK_ENTER){
System.out.println("The numbers you enter are "+phoneField.getText());
}
}
});
If this isn't your problem, you should expand a little and clarify.
EDIT:
As comments and other answers pointed out, you should go for an ActionListener instead. Reasoning can be found below.

Categories