Prevent Sendkeys from other Application. Prevent cheating - java

I programmed with a little java game; the challenge is to type the hole abc in the textbox and it give out the time used.
Now i have already built in some feature to prevent cheating:
like copy paste the hole abc
or only the middle of the abc like bcdefgh...
if you study my code you will see that I only check the first lettre A, L and Z.
A to save the start time
L to prevent cheating and copy paste only the middle of the hole abc
Z to check the hole string wich i put in the TextField. And stop the time.
Heres the Code:
package lvl1;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class test implements KeyListener {
private Date start_time;
private JTextField jtf;
private JLabel lblStatus;
private boolean lpressed;
public static void main(String[] args) {
new test();
}
public test() {
jtf = new JTextField();
JFrame myframe = new JFrame();
jtf.addKeyListener(this);
lblStatus = new JLabel("Zeit:");
myframe.setSize(700, 60);
myframe.setTitle("ABC COOLGAME");
myframe.setLocationRelativeTo(null);
myframe.setDefaultCloseOperation(myframe.EXIT_ON_CLOSE);
myframe.setLayout(new GridLayout(1, 2));
myframe.add(jtf);
myframe.add(lblStatus);
myframe.setVisible(true);
}
#Override
public void keyPressed(KeyEvent arg0) {
if (65 == arg0.getKeyCode()) {
start_time = new Date();
}
if (8 == arg0.getKeyCode()) {
jtf.setText("");
jtf.setBackground(Color.WHITE);
}
if (76 == arg0.getKeyCode()) {
lpressed = true;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
Date date = new Date();
if ((90 == arg0.getKeyCode()) & (jtf.getText().equals("abcdefghijklmnopqrstuvwxyz") & (lpressed == true))) {
lblStatus.setText("Zeit: " + (date.getTime() - start_time.getTime())
+ " Milliseconds");
jtf.setBackground(Color.GREEN);
lpressed = false;
}
}
#Override
public void keyTyped(KeyEvent e) {/* Nothing to do */}
}
Now I send the Jar file to my friend and in only a few minutes i reseved a message with a record of 10 milliseconds. He told me that he send with vba the hole abc over
Sleep 5000 'Here he click the cursor in my textfield
SendKeys "abcdefghijklmnopqrstuvwxyz"
this statement will send automaticly all keys seperatly in comparison similar as I typed this on my keyboard.
Anybody know a method to prevent thes technic of cheating??
the game mustnt be secure for cheat engines other something else, but to prevent the technic above will be amazing.

Related

How to rectify "over-sensitive" JTextField input issue

I've just come over to JAVA from BASIC, so please forgive me for any convention issues with my coding.
I have a mildly infuritating GUI-related issue. I have constructed a matrix-multiplication calculator which does calculations on inputted letters (using MOD 26). I run the program exclusively on Eclipse and have included a picture of the actual program in operation below...
The issue is with the Jtextfield boxes which take the inputted letters:
Actual program running on Eclipse
Basically, I wanted to be able to input a letter in a box, then to have the cursor move to the next box (cycling back to the first box after all the letters are inputted). I used a 'KeyListener' as shown in the code for the first JTextField 'letter box':
A_RUCE = new JTextField(2);
A_RUCE.setFont(new Font("Serif", Font.PLAIN, 18));
A_RUCE.setEditable(true);
cp.add(A_RUCE);
A_RUCE.setText("");
A_RUCE.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
String value=A_RUCE.getText();
if(value.length()==0){
B_RUCE.requestFocus();
}
}
});
The problem is that when I run the program, most of the time, the thing becomes "over sensitive". I try to input a letter and the cursor skips a box. I consider key repeating rate on my computer and such, and have adjusted settings, but this did not help.
All I am seeking is for when a letter is inputted, that the cursor moves to the next box without it 'skipping' over a box. I don't know why that happens, and I cannot figure out an alternative way to fix the issue. I would be very grateful if someone could help with this. Thank you kindly.
I'd be more inclined to use a DocumentListener. You can check the length of the text and then move onto the next field. This is the sort of thing you could do:
import java.awt.Component;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.EventQueue;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
public class FB extends JFrame implements DocumentListener {
private JTextField[] fields = new JTextField[3];
public void insertUpdate(DocumentEvent e) {
int textLen = e.getDocument().getLength();
if (textLen == 1) {
// focus next
int nextToFocus = 0;
Component c = getFocusOwner();
for (int i = 0; i < fields.length; i++) {
if (fields[i] == c) {
nextToFocus = i + 1;
break;
}
}
nextToFocus %= fields.length;
System.out.printf("Next to focus is field %d%n", nextToFocus);
fields[nextToFocus].requestFocus();
}
}
public void removeUpdate(DocumentEvent e) {
} // No-op
public void changedUpdate(DocumentEvent e) {
// No-op
}
private void setGui() {
try {
setLocation(0, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
JPanel fieldsPanel = new JPanel();
for (int i = 0; i < fields.length; i++) {
JTextField tf = new JTextField(1);
tf.getDocument().addDocumentListener(this);
fieldsPanel.add(tf);
fields[i] = tf;
}
setContentPane(fieldsPanel);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
EventQueue.invokeAndWait(() -> {
FB f = new FB();
f.setGui();
f.setSize(200, 200);
f.setVisible(true);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

Change background colour on typing certain value (jNumberField)

I am trying to change the background colour of a number field based on the numbers that are typed in. Just like a number field turns red when you type a letter in it. I want it to also change red when you type numbers below 1 and above 7.
I understand that you can do this with a button, but I want it to change when you're typing.
This is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class applet03 extends JApplet {
private JButton bHoeveelheid = new JButton();
private JNumberField nfAantal = new JNumberField();
private JTextArea taLijst = new JTextArea("");
private JScrollPane taLijstScrollPane = new JScrollPane(taLijst);
public void init() {
Container cp = getContentPane();
cp.setLayout(null);
cp.setBounds(0, 0, 442, 478);
bHoeveelheid.setBounds(224, 56, 59, 33);
bHoeveelheid.setMargin(new Insets(2, 2, 2, 2));
bHoeveelheid.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
bHoeveelheid_ActionPerformed(evt);
}
});
cp.add(bHoeveelheid);
nfAantal.setBounds(304, 56, 99, 36);
nfAantal.setText("Vul getal in");
nfAantal.setHorizontalAlignment(SwingConstants.CENTER);
nfAantal.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
nfAantal_FocusGained(evt);
}
});
nfAantal.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
nfAantal_KeyPressed(evt);
}
});
cp.add(nfAantal);
taLijstScrollPane.setBounds(224, 136, 168, 180);
cp.add(taLijstScrollPane);
}
public void bHoeveelheid_ActionPerformed(ActionEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
public void nfAantal_FocusGained(FocusEvent evt) {
if (nfAantal.getText().equals("Vul getal in")) {
nfAantal.clear();
}
}
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
}
The button part works, but the KeyEvent not.
And when I run this I keep getting these errors:
Exception in thread "AWT-EventQueue-1" java.lang.NumberFormatException: empty String
But when I do this, it kinda works. I still get the same errors but it works. (By the way not optimal, because it only appends it to the text field every second key pressing.):
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
taLijst.append(nfAantal.getText());
} else {
//some other code (not impotant for now)
}
}
So if someone knows why this doesn't work or knows a better way to accomplish this. Then that would be very appreciated!
(By the way I use Java 1.8)
Edit:
I now have (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) in the if statement and that got rid of the errors. (Thanks to #Joe)
But that still doesn't solve my question on how to turn the background red on certain values.
Aditional information about JNumberField:
I think this link has the code that makes up JNumberField and this link contains a download to the .jar file with in there the JNumberField Java file.
Another edit:
I think I found out for myself why it doesn't work with a JNumberfield; in the code it changes the background to white if its value is numeric so only if there is a way to get around this part of the code or change it (which I don't know how to do) my question can be answered for a JNumberField, if this isn't the case then I will use the JFormattedTextField instead.
This is the code that needs to be altered or circumvented:
protected void processKeyEvent(KeyEvent e) {
super.processKeyEvent(e);
if (isNumeric() || getText().equals("-") ||
getText().equals("") || getText().equals("."))
setBackground(Color.white);
else
setBackground(Color.red);
}
I don't know what a JNumberField is. It's not part of the JDK and when I searched with Google, it turned up several different ones.
I also don't understand why you are writing an applet.
Therefore, the below code may not be appropriate since it is a stand-alone Swing application that uses JFormattedTextField and DocumentListener.
Explanations after the code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.NumberFormatter;
public class RedNumbr implements DocumentListener, Runnable {
private JFormattedTextField aantal;
private JFrame frame;
#Override
public void insertUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void removeUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void changedUpdate(DocumentEvent event) {
// Never called for 'JFormattedTextField'
}
#Override
public void run() {
showGui();
}
private JPanel createNumberPanel() {
JPanel numberPanel = new JPanel();
NumberFormat format = NumberFormat.getIntegerInstance();
NumberFormatter formatter = new NumberFormatter(format);
aantal = new JFormattedTextField(formatter);
aantal.setColumns(10);
Document doc = aantal.getDocument();
doc.addDocumentListener(this);
numberPanel.add(aantal);
return numberPanel;
}
private void handleDocumentEvent(DocumentEvent event) {
Document doc = event.getDocument();
int len = doc.getLength();
if (len > 0) {
try {
String text = doc.getText(0, len);
int number = Integer.parseInt(text);
Color fg;
if (number < 1 || number > 7) {
fg = Color.red;
}
else {
fg = UIManager.getColor("TextField.foreground");
}
aantal.setForeground(fg);
}
catch (BadLocationException | NumberFormatException x) {
// Ignore.
}
}
}
private void showGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createNumberPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new RedNumbr());
}
}
Whenever the contents of the JFormattedTextField are changed, the relevant DocumentListener method is invoked. In those methods I check whether the JFormattedTextField contains a number and if it does then I change the foreground color of the JFormattedTextField according to your conditions, i.e. if the number is less than one (1) or greater than 7 (seven).
Note that the NumberFormatter does not prevent entering non-digits because JFormattedTextField handles that when it loses focus. Nonetheless it handles entering positive and negative numbers, which saves you some work. And the point of my answer is simply to demonstrate how to change the foreground color based on the entered text, which I believe answers your question.
EDIT
In order to change the background of the JFormattedTextField, rather than the foreground, you just need to change two lines in my code, above.
Replace
fg = UIManager.getColor("TextField.foreground");
with
fg = UIManager.getColor("TextField.background");
and also replace
aantal.setForeground(fg);
with
aantal.setBackground(fg);
I suppose that the JNumberField is an extension of JTextField and if it is the case it could be the synchronization problem between the main thread and the thread that is triggered by the KeyEvent action. To make sure that the event thread will be carried out you code it with invokeLater.
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
nfAantal.setBackground(Color.RED);
}
});
} else {
//some other code (not impotant for now)
}
}

Java do method while JToggleButton is pressed

Objective
I am trying to achieve code that will call upon a method for the time the JToggleButton in Swing is pressed down. The MainCode.intGenerate method, which returns an List<Integer>, takes in aList<Integer>.
Restrictions
Random_gen_Button is declared as such and is unchangeable due to NetBeans guarding it. I can change it using notepad to open but It is not allowing me to change it for a reason so I shall not.
private JToggleButton RANDOMGENBUTTON;
Code
private void RANDOMGENBUTTONActionPerformed(java.awt.event.ActionEvent evt) {
if(RANDOMGENBUTTON.isSelected()) {
EXITBUTTON.setEnabled(false);
List<Integer> INPUTLIST = new ArrayList<Integer>();
while(RANDOMGENBUTTON.isSelected()) {
INPUTLIST = MainCode.intGenerate(INPUTLIST);
}
}else {
EXITBUTTON.setEnabled(true);
}
}
Possible Solution
I think this should be achievable with another Thread but I am not sure how to do this.
The Error
This code does not work because it freezes the GUI, I cannot press on the JToggle Button again resulting in an infinite loop.
Edit
intGenerate()
public static List<Integer> intGenerate(List<Integer> INLIST) {
Random Rand = new Random();
int RANDOMNUM = Rand.nextInt((9999999 - 1000000) + 1) + 1000000;
if(INLIST.isEmpty()) {
INLIST.add(randomNum);
}else {
while(INLIST.contains(randomNum)==true) {
RANDOMNUM = Rand.nextInt((9999999 - 1000000) + 1) + 1000000;
}
INLIST.add(RANDOMNUM);
}
return INLIST;
Use a java.swing.Timer for the other thread that periodically tells your component to update itself. In the example below, the timer's listener updates the button's text when the button is selected or the button's model says it's pressed.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.Timer;
/**
* #see http://stackoverflow.com/a/38051563/230513
*/
public class Test {
private final Random r = new Random();
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JToggleButton button = new JToggleButton("0000");
f.add(button);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
Timer t = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.isSelected() | button.getModel().isPressed()) {
button.setText(String.valueOf(r.nextInt(9000) + 1000));
}
}
});
t.start();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
As an aside, don't let the GUI editor dictate your design.

Auto-Completing JTextField and Arrow Keys

I'm trying to build a javax.swing.JTextField with javax.swing.JList for auto-completing like Google.
When a write a word, Google show several matches and
when a press the ▼ I can select some match using ▲ and ▼ and
can edit my input with ◀ and ▶ .
When I press Enter key search the content in the box.
When a press Esc the box change to the original input.
My aplication is about the Bible and I want to looking for a particular word when I'm studying the Word. I have seen the Java2sAutoTextField but don't have this particular behavior with the arrow keys.
This needs a custom coded component. Definitely a class that extends JTextField and in that class you have a JPopupMenu that will contain your JList. You will have to position the JPopupMenu right under the text field so that it looks like 1 component.
Your next trick is to filter as you type. I usually do this using Java6 TableRowSorter coupled with a JTable to which I pre-fill it with data. You're gonna need some change listeners on the JTextField and intercept each key typed and fetch your data.
Key pressed
Perform query in DB (or some data storage to get similar entries)
Populate JTable with those entires
Set RowFilter with regex based on JTextField entry to filter through retrieved data
Manage your actions with key listeners
EDIT
I whipped up a sample swing app to show what I stated. This is a copy/paste example and should work right off the bat (need JDK 1.6+). I basically got what you wanted and I put comments in places where I tell you to fill in the blanks.. like for example the Escape key event is consumed and you can do whatever you want with it.
The method initTableModel() just initializes the table model with data. Normally you would want to dynamically populate the table model with data from a database or something. A lot could be tweaked, but this is for example sake ;) So this should be a good enough example for you to modify to your complete your goal. Any more than this and you have to pay me $$$ :)
package test.text.googleclone;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class SearchAutoFillTest {
private JFrame frame = null;
private JTextField searchField = null;
private JPopupMenu popup = null;
private JTable searchTable = null;
private TableRowSorter<DefaultTableModel> rowSorter = null;
private DefaultTableModel searchTableModel = null;
public SearchAutoFillTest() {
searchTableModel = new DefaultTableModel();
initTableModel();
rowSorter = new TableRowSorter<DefaultTableModel>(searchTableModel);
searchTable = new JTable(searchTableModel);
searchTable.setRowSorter(rowSorter);
searchTable.setFillsViewportHeight(true);
searchTable.getColumnModel().setColumnSelectionAllowed(false);
searchTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
searchTable.getTableHeader().setReorderingAllowed(false);
searchTable.setPreferredSize(new Dimension(775, 100));
searchTable.setGridColor(Color.WHITE);
searchField = new JTextField();
searchField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
showPopup(e);
}
});
searchField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
switch(code)
{
case KeyEvent.VK_UP:
{
cycleTableSelectionUp();
break;
}
case KeyEvent.VK_DOWN:
{
cycleTableSelectionDown();
break;
}
case KeyEvent.VK_LEFT:
{
//Do whatever you want here
break;
}
case KeyEvent.VK_RIGHT:
{
//Do whatever you want here
break;
}
}
}
#Override
public void keyPressed(KeyEvent e) {
}
});
KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE");
searchField.getInputMap().put(keyStroke, "ESCAPE");
searchField.getActionMap().put("ESCAPE", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//Do what you wish here with the escape key.
}
});
popup = new JPopupMenu();
popup.add(searchTable);
popup.setVisible(false);
popup.setBorder(BorderFactory.createEmptyBorder());
JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
searchPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
searchPanel.add(searchField, BorderLayout.CENTER);
frame = new JFrame();
frame.setLayout(new BorderLayout(5, 5));
frame.add(searchPanel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 500);
center(frame);
frame.setVisible(true);
}
private final void newFilter() {
RowFilter<DefaultTableModel, Object> rf = null;
try {
rf = RowFilter.regexFilter(getFilterText(), 0);
}
catch(PatternSyntaxException e) {
return;
}
rowSorter.setRowFilter(rf);
}
private final String getFilterText() {
String orig = searchField.getText();
return "("+orig.toLowerCase()+")|("+orig.toUpperCase()+")";
}
private void showPopup(DocumentEvent e) {
if(e.getDocument().getLength() > 0) {
if(!popup.isVisible()) {
Rectangle r = searchField.getBounds();
popup.show(searchField, (r.x-4), (r.y+16));
popup.setVisible(true);
}
newFilter();
searchField.grabFocus();
}
else {
popup.setVisible(false);
}
}
private void cycleTableSelectionUp() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 > 0) {
selModel.setSelectionInterval(index0-1, index0-1);
}
}
private void cycleTableSelectionDown() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 == -1) {
selModel.setSelectionInterval(0, 0);
}
else if(index0 > -1) {
selModel.setSelectionInterval(index0+1, index0+1);
}
}
private void initTableModel() {
String[] columns = new String[] {"A"};
String[][] data = new String[][]
{
new String[] {"a"},
new String[] {"aa"},
new String[] {"aaab"},
new String[] {"aaabb"},
new String[] {"aaabbbz"},
new String[] {"b"},
new String[] {"bb"},
new String[] {"bbb"},
new String[] {"bbbbbbb"},
new String[] {"bbbbbbbeee"},
new String[] {"bbbbbbbeeexxx"},
new String[] {"ccc"},
new String[] {"cccc"},
new String[] {"ccccc"},
new String[] {"cccccaaaa"},
new String[] {"ccccccaaaa"},
};
searchTableModel.setDataVector(data, columns);
}
private void center(Window w) {
int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
int windowWidth = w.getWidth();
int windowHeight = w.getHeight();
if (windowHeight > screenHeight) {
return;
}
if (windowWidth > screenWidth) {
return;
}
int x = (screenWidth - windowWidth) / 2;
int y = (screenHeight - windowHeight) / 2;
w.setLocation(x, y);
}
public static void main(String ... args) {
new SearchAutoFillTest();
}
}
This component is called autocomplete and is included in a so called swing extensions porject.
Just have a look at: http://swingx.java.net/
There is a webstart with demos: http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp
use AutoComplete JTextField placed into JToolBar / MenuBar, notice you must to sort ArrayList before usage,
use undecoratted JDialog instead of JPopup (still have got a few important bugs),
a) create only one JDialog with parent to the JTextField or JMenuBar or JFrame,
b) always to search for getBounds from AutoComplete JTextField before visible JDialog on the screen, this Bounds are for possitioning JDialog correctly on the screen
c) wrap JDialog#setVisible(true) to the invokeLater()
override Escape for JDialog.setVisible(false)
put there close / hide JButton to avoiding overrive rest of important methods on focusLost (this calendar have got excelent workaround on focusLost, mouseClick, etc ...., could it be very easy to replace calendar funcionality with result from Comparator, you have to download codesource)
you can put there (my view) 6 / 9 / max 12 buttons, you can remove JButton Feels by setBackground(Color.white) for example, you cann't, please don't do it something with JDialog and these JButtons, you job will be only to setText("result from Comparator")
in the case that your ArrayList for AutoComplete JTextField was sorted, then you have two choises
a) easiest override bias from AutoComplete funcionality by add fils separate array for setText() for 6 / 9 / max 12 buttons on popup JDialog, if you setBackground(Color.white), then you don't care somehow about to hide JButtons without text
b) another way could be to create own Comparator for searching (the same AutoComplete funcionality) first 6 / 9 / max 12 matches,
for capturing an events from 6 / 9 / max 12 JButtons use putClientProperty or EventHandler or Swing Actions, where you only to test if text isEmpty :-),
maybe Swing Actions could be the best of ways because its events are scallable and you can enabled/disable (if JButtons text isEmpty) output from this Action by default
It sounds like you want a JComboBox (see Swing guide) rather than a JTextField/JList.
Of course, then you have a drop-down button, but there are possible ways to deal with this - see here.
It would be something along these lines:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.*;
public class Component extends JComponent {
private final static String[] terms = {"Jesus",
"Jesus walks on water" //...
};
private static ArrayList<String> recent = new ArrayList<String>();
JTextField jtf;
JList jl;
public Component(){
// set up design
jtf = new JTextField();
jtf.setSize(this.getWidth() - 25, 25);
this.add(jtf);
//...
// add key listeners
}
class Listener implements KeyListener{
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
if (arg0.getKeyCode() == KeyEvent.VK_DOWN){
// set next item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_UP){
// set previous item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
// search
}
else if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
jtf.setText("");
}
else{
// check list for matches
}
}
}
}
The default behavior is that all key events go to the component which has the focus. So what you need to do is identify keys which should really go to the other component and install a KeyListener to both.
In that listener, you can forward the events to the other component.
See this answer how to dispatch an event to a new component. In your case, source must be the other component (the list, if your text field originally received the event and vice versa).

How to act upon hitting "Enter" when on "Cancel" button in JFileChooser?

I have a JFileChooser in a JFrame. I've added an ActionListener to the JFileChooser so that the "Cancel" button works when clicked. I can also tab to the "Cancel" button, but when I then hit the "Enter" key, nothing happens (i.e., the ActionListener isn't called with the event command JFileChooser.CANCEL_SELECTION). What must I do with the JFileChooser so that hitting the "Enter" key when on the "Cancel" button is equivalent to clicking on the "Cancel" button?
Here's a simple example of the (mis)behavior I'm seeing:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
To see the (mis)behavior, execute the program, tab to "Cancel", and then hit the "Enter" key. The program doesn't terminate on my platform -- although it does when I click on the "Cancel" button.
Extending JFileChooser and overriding cancelSelection() also doesn't work (apparently, that function isn't called when the "Enter" key is hit while on the "Cancel" button).
The (mis)behavior occurs on my Fedora 10 x86_64 system with Java 5, 6, and 7.
ADDENDUM: The following adds a KeyEventPostProcessor to the current KeyboardFocusManager and appears to do what I want:
import java.awt.Component;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.out.println(e.paramString());
System.exit(0);
}
});
final KeyboardFocusManager kfm = KeyboardFocusManager
.getCurrentKeyboardFocusManager();
kfm.addKeyEventPostProcessor(new KeyEventPostProcessor() {
#Override
public boolean postProcessKeyEvent(final KeyEvent e) {
if (e.getID() == KeyEvent.KEY_RELEASED
&& e.getKeyCode() == KeyEvent.VK_ENTER) {
final Component comp = e.getComponent();
if (chooser.isAncestorOf(comp)) {
if (!(comp instanceof JButton)) {
chooser.approveSelection();
}
else {
final JButton button = (JButton) comp;
if ("Cancel".equals(button.getText())) {
chooser.cancelSelection();
}
else {
chooser.approveSelection();
}
}
}
}
return false;
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
It seems like a lot of work, however, just to be able to distinguish between hitting the enter key on the "Cancel" button versus anywhere else.
Do you see any problems with it?
DISCOVERED SOLUTION: Setting the GUI Look and Feel to the native one for my system (Linux) does what I want without the need for anything else. This is what I was ignorant of and what I was looking for. The solution is to have the following
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
as the first executable statement of the main() method. One can then dispense with all focus listeners, key event processors, etc.
I've awarded the 100 points to the most helpful respondent.
The program doesn't terminate on my platform.
I see normal operation on Mac OS X 10.5, Ubuntu 10 and Windows 7 using (variously) Java 5 and 6. I replaced your exit() with println() to see the event:
System.out.println(rootDirChooser.getSelectedFile().getName() + e.paramString());
It may help to specify your platform and version; if possible, verify correct installation as well.
I'm not sure I understand your goal; but, as an alternative, consider overriding approveSelection():
private static class MyChooser extends JFileChooser {
#Override
public void approveSelection() {
super.approveSelection();
System.out.println(this.getSelectedFile().getName());
}
}
Addendum:
The goal is to have the action of hitting the "Enter" key while on the "Cancel" button be identical to clicking on the "Cancel" button.
As discussed in Key Bindings, you can change the action associated with VK_ENTER.
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
InputMap map = chooser.getInputMap(JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(enter, "cancelSelection");
If you want the change to occur only while the "Cancel" button has focus, you'll need to do it in a Focus Listener.
Addendum:
I found a solution that uses KeyboadFocusManager, instead. What do you think?
I can see pros & cons each way, so I've outlined both below. Using KeyboadFocusManager finds all buttons, but offers no locale independent way to distinguish among them; the Focus Listener approach can only see the approve button, and it's UI specific. Still, you might combine the approaches for better results. A second opinion wouldn't be out of order.
Addendum:
I've updated the code below to eliminate the need to know the localized name of the "Cancel" button and use key bindings.
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.plaf.metal.MetalFileChooserUI;
public final class FileChooserKeys
implements ActionListener, FocusListener, PropertyChangeListener {
private final JFileChooser chooser = new JFileChooser();
private final MyChooserUI myUI = new MyChooserUI(chooser);
private final KeyStroke enterKey =
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
private void create() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
chooser.addActionListener(this);
myUI.installUI(chooser);
myUI.getApproveButton(chooser).addFocusListener(this);
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(this);
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.paramString());
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("ApproveButton gained focus.");
}
#Override
public void focusLost(FocusEvent e) {
System.out.println("ApproveButton lost focus.");
}
#Override
public void propertyChange(PropertyChangeEvent e) {
Object o = e.getNewValue();
InputMap map = chooser.getInputMap(
JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
if (o instanceof JButton) {
if ("focusOwner".equals(e.getPropertyName())) {
JButton b = (JButton) o;
String s = b.getText();
boolean inApproved = b == myUI.getApproveButton(chooser);
if (!(s == null || "".equals(s) || inApproved)) {
map.put(enterKey, "cancelSelection");
} else {
map.put(enterKey, "approveSelection");
}
}
}
}
private static class MyChooserUI extends MetalFileChooserUI {
public MyChooserUI(JFileChooser b) {
super(b);
}
#Override
protected JButton getApproveButton(JFileChooser fc) {
return super.getApproveButton(fc);
}
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new FileChooserKeys().create();
}
});
}
}

Categories