Java - Allow using backspace in an editable JComboBox with Substance L&F - java

I am using Substance L&F and I have set a JComboBox to editable so that i can select the value that i want from its popup, or type a new value in its Editor.
Typing a new value works fine, but if i want to delete a miss-typed letter from the Combo editor, and i click Backspace to do that it selects the letters in the editor instead of erasing them. Here is a screenshot :
I want the Combo editor to work like a JTextField when typing keyboard letters or Backspace or Delete in it, so is there a way to do that ? Or what is causing this?

See below for the importance of an SSCCE not everything that goes wrong is a bug, most of the times it something wrong in your actual code, which without an SSCCE we are non the wiser.
Seems to work fine for me:
On start up:
After selecting JComboBox and pressing Backspace:
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JComboBox jc = new JComboBox(new String[]{"Hello", "Bye", "World", "Cruel"});
jc.setEditable(true);
frame.add(jc);
frame.pack();
frame.setVisible(true);
}
});
}
public static void main(String[] args) {
new Test();
}
}
UPDATE
As per your comment:
I did not think it would work fine ! ... It is a problem in Substance;
the L&F i am using.
See below for details on the Bug:
Substance: Editable JComboBox does not support backspace key
As stated:
This behavior is by design. This is a "feel" part of Substance that
adds auto-completion on editable comboboxes.
Alternatively see my answer here for more L&Fs and/or a way to make your own
UPDATE 2:
Thanks to #Brad (for deciphering the bug log I linked from Substance :P) to fix this simply do:
UIManager.put( LafWidget.COMBO_BOX_NO_AUTOCOMPLETION, Boolean.TRUE );

UIManager.put(LafWidget.COMBO_BOX_NO_AUTOCOMPLETION, Boolean.TRUE);
This work for me!

Related

Java Swing: display Text selectable

I wont to display some text with Java Swing. It should also be possible to select it with the mouse in order to copy it. If I use a JLable it is not possible to select the text. If I use a JTextField or JTextArea it is possible to select and copy the text, but then the user can modify the text. Sure I can disable them so that it is not longer possible to change the text, but then again it is also not possible to select and copy the text ether.
Is there some way to achieve what I am searching for?
Use setEditable(false) on a JTextField. Oddly, then, the mouse pointer is an arrow, but you can still select the text.
This worked for me:
import javax.swing.*;
public class TestTextField extends JFrame {
private JTextField txt;
public TestTextField() {
txt = new JTextField("test");
this.add(txt);
txt.setEditable(false);
this.setSize(200, 100);
}
public static void main(String[] asArgs) {
new TestTextField().show();
}
}

Setting TableCellRenderer adds an empty value atop of value list of `JComboBox`

SCCEE here:
import java.awt.EventQueue;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
public class TC extends JFrame{
public TC(){
begin();
}
private void begin(){
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("nothing.");
String[] options = {"One", "Two", "Three"};
JComboBox<String> combo = new JComboBox<>(options);
JTable table = new JTable(new Object[2][2], new String[]{"One", "Two"});
TableColumn col0 = table.getColumnModel().getColumn(0);
col0.setCellEditor(new DefaultCellEditor(combo));
class MyRender extends DefaultTableCellRenderer {
public MyRender() {
}
#Override
public void setValue(Object value) {
if (value instanceof JComboBox) {
setText(((JComboBox) value).getSelectedItem().toString());
}
}
}
MyRender renderer = new MyRender();
col0.setCellRenderer(renderer);
JScrollPane sp = new JScrollPane(table);
getContentPane().add(sp);
pack();
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
#Override
public void run() {
TC tc = new TC();
}
});
}
}
My problem is: setting the TableCellRenderer makes the combo choose an empty option atop of all other values, without anyone telling it to do so. The empty entry comes from nowhere.
How can I make the combo select the "One" entry at first moment, instead of " "? Something I missed when implementing the custom renderer?? I followed here:
Oracle tutorial of How to Use Tables - Swing - Java SE
Also, the combo is not shown until I click it. I don't think it's the proper way to show it. I tried to follow another example here:
Show a JComboBox with custom editor and renderer, example from java2s.com
but I remain confused.
How can I make the combo select the "One" entry at first moment,
This is the default behaviour. The data from the TableModel is used to select the item in the combo box when the editor is invoked.
The section from the Swing tutorial on Using a ComboBox as an Editor contains a working example showing how to do this.
the combo is not shown until I click it
This is the way it is designed. The renderer displays the data normally. The editor is not displayed until the user starts editing the cell.
If you want to give the user an indication that a combo box will be used as the editor then you need to use a custom renderer. Your attempted implementation is incorrect because you would never have a JCombobox as data in the table model.
Check out: How to make a JComboBox table editor have the design of an ordinary JComboBox? for a couple of different implementations of a possible renderer:
my example shows what using a real combo box would be like (I don't like it) and
the accepted answer shows a better renderer. You might want to change the example to have a panel as the renderer with a BorderLayout. Then you add a label to the LINE_START and the icon to the LINE_END so the icon so it more resembles a combo box with the down arrow on the right.
Edit:
but in your link, the combobox is showing the first option
No it isn't. Test the code again. Click on the 2nd or 3rd row to invoke the editor to see which item is selected.
To clarify what I said earlier. The item in the combo box is selected based on the data in the TableModel. Since your TableModel is empty there is no item to select.
Put some data in the TableModel. The example from the Swing tutorial and the two examples in the link I provided you all have data in the TableModel which is why they work.
Thank you Rob Carmick. I won't cross-posting again.
I have found the problem. In the default renderer I put one line of code like this:
class MyComboBoxRenderer extends JComboBox implements TableCellRenderer {
public MyComboBoxRenderer(JComboBox<String> combo) {
super(combo.getModel());
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
// setSelectedItem(value); // where lies the problem, will always be null.
return this;
}
}
When the combo is loaded, the value is always null, and I let the combo select it, so the empty line appears. Comment it and all's fine.
In CodeRanch I post this and system takes it as spam, I don't know why. Although I found my solution myself, I accept you answer for helping.
Thanks again.

how to use text fields in java

I just have a very basic question about how to use textfields in Java. It's very simple, but the tutorials and other questions I've been looking for haven't been helpful, and I'm hoping that someone can explain things a little more clearly for me.
Right now I have the following code that I just sort of slapped together for the sake of example:
import javax.swing*;
public class testText {
public static void main(String[] args){
JFrame frame = new JFrame();
JTextField text = new JTextField();
frame.add(text);
frame.setVisible(true);
System.out.println(text.getText());
}
}
All I'm trying to do, is print what the user types into the text field in the console. But nothing happens when I type into the text field.
Now,based on the research I've done, I think the problem is that I'm not using an actionListener. The thing is, I really don't understand how those work, and I'm hoping someone can clarify for me.
I've been using this tutorial to try and figure things out, and particularly the TextDemo example they have near the top. I'm still kind of at a loss though, and I can't seem to find any way to use the actionlistener interface without breaking the program. If someone could either just explain simply and directly how to use the actionlistener to pull a string from a text field and then use it, or else point me to somewhere else where I can FIND a simple straightforward explanation, I would immensely appreciate it. I've been beating my head against this for five hours now with absolutely nothing to show for it, so I apologize for asking such a basic question but I'm at a loss.
An action listener will be called when an enter key is pressed while typing in the field. From the JTextfield Javadoc :
How the text field consumes VK_ENTER events depends on whether the
text field has any action listeners. If so, then VK_ENTER results in
the listeners getting an ActionEvent, and the VK_ENTER event is
consumed.
Here is your example modified to work with an action listener :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class testText {
public static void main(String[] args){
JFrame frame = new JFrame();
final JTextField text = new JTextField();
frame.add(text);
frame.setVisible(true);
text.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(text.getText());
}
});
}
}
And here is an object oriented complete example not relying only on a static main method.

Different windows with the same code?

This is the "main" class (doesn't contain the main method)
import javax.swing.*;
import java.awt.*;
//import java.lang.Object;
//import java.awt.event.ActionListener;
//import java.awt.event.;
public class Program {
public JFrame frame;
public JPanel header;
public JPanel text;
public JPanel body;
public JTextField input;
public JButton agregar;
public List listA;
public List listB;
public Program(String title) {
frame = new JFrame(title);
frame.setSize(500,600);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
header = new JPanel();
header.setBackground(new Color(255,204,50));
header.setBounds(0,0,500,100);
text = new JPanel();
text.setBackground(new Color(255,204,100));
text.setBounds(0,100,500,50);
text.setLayout(null);
//Inicializando la "entrada"
input = new JTextField(20);
input.setBounds(50,13,300,25);
text.add(input);
agregar = new JButton();
agregar.setBounds(360,12,80,25);
agregar.setText("Agregar");
text.add(agregar);
//Listo
body = new JPanel();
body.setBackground(new Color(255,204,150));
body.setBounds(0,150,500,450);
//Lo que está dentro del body
listA = new List(20);
body.add(listA);
listB = new List(20);
body.add(listB);
//Listo
//Añadir todos los paneles al frame principal
frame.add(header);
frame.add(text);
frame.add(body);
}
}
And this is the MAIN class (This one contains the main method):
public class Main {
public static void main(String[] args) {
new Program("Ordenamiento Recursivo");
}
}
Each time I run the application, the UI components are presented differently, please see attached screen shot.
Well, thanks to everyone who responded the post, I finished the program and I'm very happy with the final result, here it is:
In case anyone wants to take a look at the code, here it is: Link
Problems:
You're call setVisible(true) on your JFrame before adding components and this will lead to unreliable drawing of your program's graphics and is why you are seeing different results. Don't do this, but rather call it after you've added all to the top-level Window.
As the others are saying, read up and learn to use the layout managers.
Different windows with the same code?
I think that is very simple and possible by implements CardLayout
I'd suggest don't opening a new Top-Level Container, only if is there really important reason then use JDialog or JOptionPane
Be sure to construct the GUI on the EDT. Not doing so can cause unpredictable results.
Call pack() after the components are added using layouts and then call setVisible(true).
You will need a layout manager for your form so setting the layout manager to null is not the thing to do.
Work in progress here ... https://gist.github.com/2510570
Couple of changes. Not quite finished yet, but check out the following
Have Program extend a JFrame.
Have set a layout manager.
Update
Finally I knocked this up in IntelliJ's form designer.
https://gist.github.com/2512197
Where you want to attach behaviour to the buttons search through the code for the comments that ask you to add code. Although I did this in the InteliJ Ultimate (this one that costs money) I think that no-cost free to download Community Edition UI designer also paints Swings GUIs. Very quick and easy. Netbeans also has a good GUI painter.
The Swing Tutorial on oracle.com is worth reviewing also.

How do I assign Enter as the trigger key of all JButtons in my Java application?

I'm writing a Java Swing application using the Metal look-and-feel. Every time there is a JButton in my application the user uses the Tab key to move the focus to the button and then hits the Enter key. Nothing happens! If he hits the Space key the button events are fired. How do I assign the Enter key to trigger the same events as the Space key? Thank you for your help.
I found the following:
http://tips4java.wordpress.com/2008/10/25/enter-key-and-button/
Where Rob Camick writes that when using JDK5 and later you simply add...
UIManager.put("Button.defaultButtonFollowsFocus", Boolean.TRUE);
...to the application to solve the problem. This did the trick for me! And I can't imagine anything simpler. However, when using older versions of Java you will have to do something like Richard and Peter describe in their answers to this question.
Here is complete example. Richard was close, but you also need to map pressed ENTER to action, not just released. To make it work for ALL buttons, I have put this mapping to default input map for buttons. Add imports, and it should be runnable.
public class Main implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Main());
}
#Override
public void run() {
setupEnterActionForAllButtons();
JFrame frame = new JFrame("Button test");
frame.getContentPane().add(createButton(), BorderLayout.NORTH);
frame.getContentPane().add(createButton(), BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private void setupEnterActionForAllButtons() {
InputMap im = (InputMap) UIManager.getDefaults().get("Button.focusInputMap");
Object pressedAction = im.get(KeyStroke.getKeyStroke("pressed SPACE"));
Object releasedAction = im.get(KeyStroke.getKeyStroke("released SPACE"));
im.put(KeyStroke.getKeyStroke("pressed ENTER"), pressedAction);
im.put(KeyStroke.getKeyStroke("released ENTER"), releasedAction);
}
private JButton createButton() {
JButton b = new JButton("press enter");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Pressed");
}
});
return b;
}
}
Actually, this is a look and feel issue. It is (and should be) up to the look and feel as to which key triggers the focused button.
The "default button" work-around works since the L&F you're using uses enter for the default button.
Peter's workaround explicitly changes the L&F default "focus action" key - which is somewhat more convincing if you ask me.
I would add that I don't think many users would want to tab to the button then hit enter (most won't even notice the focus indicator) - they want the default action to be the "right" one and work wherever they press enter. This can only be done with input maps as Richard suggests.
I would certainly suggest getting a very clear picture of what your users actually want and expect (preferably with reference to other apps they use) before changing anything globally.
You do it by assigning an input / action map for the Enter key. Something like the following:
// save the command mapping for space
Object spaceMap = button.getInputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true));
// add a mapping from enter to the same command.
button.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true),spaceMap);
You can also set the "default button" to the button most recently focussed.
I did this on an application, and all methods of doing this are a nightmare to maintain and debug. The fact is, this is clearly not what the designers of Swing intended to happen.
Extension to above answers to do same with radio , checkboxes.
Called this before creating components
void setupEnterAction(String componentName){
String keyName = componentName + ".focusInputMap";
InputMap im = (InputMap) UIManager.getDefaults().get(keyName);
Object pressedAction = im.get(KeyStroke.getKeyStroke("pressed SPACE"));
Object releasedAction = im.get(KeyStroke.getKeyStroke("released SPACE"));
im.put(KeyStroke.getKeyStroke("pressed ENTER"), pressedAction);
im.put(KeyStroke.getKeyStroke("released ENTER"), releasedAction);
}
public void setEnterEvent(){
setupEnterAction("Button");
setupEnterAction("RadioButton");
setupEnterAction("CheckBox");
}

Categories