JComboBox how to show the right end of the item? - java

I have the following Java code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class EnumsRightVisible {
public void show() {
JFrame frame = new JFrame("Combo box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[] items = {"aaaaaaaaa__________zzzzzzzzz",
"aaaaaaaaa__________zzzzzzzzz",
"aaaaaaaaa__________zzzzzzzzz"};
JComboBox combo = new JComboBox(items);
combo.setPreferredSize(new Dimension(100,20));
frame.add(combo, BorderLayout.CENTER);
frame.setLocation(600, 100);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
EnumsRightVisible enumsRightVisible = new EnumsRightVisible();
enumsRightVisible.show();
}
}
Running it you can see that the visible text is left oriented.
Please note that this code does not solve my problem (it aligns the text to the right, but only when the combo box is expanded):
((JLabel)comboBox.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);
How can I display the right end of the text in the same window (...__zzzzzz)?
Thanks in advance!

Use a custom renderer that uses FontMetrics to measure the String's width and does the ellipsis (...) manually. More info here: http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer

Method 1
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class ComboBoxDemo extends JFrame {
public ComboBoxDemo() {
JComboBox comboBox = new JComboBox();
((JLabel)comboBox.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);
comboBox.addItem("Apple");
comboBox.addItem("Orange");
comboBox.addItem("Mango");
getContentPane().add(comboBox, "North");
setSize(200, 100);
this.setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new ComboBoxDemo().setVisible(true);
}
}
Method 2 (Oviously, First is better)
import java.awt.Component;
import java.awt.ComponentOrientation;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class ComboBoxDemo extends JFrame {
public ComboBoxDemo() {
JComboBox comboBox = new JComboBox();
setListCellRendererOf(comboBox);
comboBox.addItem("Apple");
comboBox.addItem("Orange");
comboBox.addItem("Mango");
getContentPane().add(comboBox, "North");
setSize(200, 100);
this.setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void setListCellRendererOf(JComboBox comboBox) {
comboBox.setRenderer(new ListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component component = new DefaultListCellRenderer()
.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
component.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
return component;
}
});
}
public static void main(String[] args) {
new ComboBoxDemo().setVisible(true);
}
}

Related

JCheckBox inside JTableCell appear and disappear on click

I have a table in which a column needs to be a 'checkbox-column". And I wrote the code like this.
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class Test0 {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test0 test = new Test0();
test.launch();
}
});
}
private void launch() {
JFrame frame = new JFrame();
Object[][] data = {{Boolean.TRUE}};
String[] columnName = {"Checkbox here!"};
#SuppressWarnings("serial")
JTable table = new JTable(new DefaultTableModel(data,columnName) {
#Override
public Class<?> getColumnClass(int columnIndex){
return Boolean.class;
}
});
JCheckBox checkBox = new JCheckBox("HI");
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(checkBox));
JScrollPane tableScrollPane = new JScrollPane(table);
frame.add(tableScrollPane);
frame.pack();
frame.setVisible(true);
}
}
When I run this, the checkbox with a "HI" label was not there as I want to be.
Instead, a normal checkbox appeared and when I clicked that, my checkbox appeared and disappeared quickly.
I don't understand what caused that. Please help me. Thank you.

Cell rendering with FX in JTable

Given a renderer implemented in JavaFX that renders something onto a Canvas. It works well.
This renderer needs to be usable in Swing applications and it works fine thanks to JFXPanel component in most of the use cases, except for JTable. If the user wants render table cell values with the given renderer, the application starts to fail in many different ways.
Here's a sample application:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
public class TableRenderer {
private JFrame frame;
private JFrame createFrame(String title, JComponent component, int width, int height) {
final Dimension dimension = new Dimension(width, height);
JFrame frame = new JFrame(Util.getActiveScreenDevice().getDefaultConfiguration());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(dimension);
frame.setSize(dimension);
frame.add(component);
frame.setTitle(title);
Util.center(frame);
frame.pack();
return frame;
}
private void show() {
try {
init();
} catch (IOException e) {
e.printStackTrace();
}
frame.setVisible(true);
}
private void init() throws IOException {
JTable table = new JTable(new TableModel());
table.setRowHeight(200);
table.setDefaultRenderer(Object.class, new CellRenderer());
JScrollPane p = new JScrollPane(table);
table.setFillsViewportHeight(true);
frame = createFrame("Renderer Demo - JTable", p, 420, 220);
}
public static void main(String[] args) {
TableRenderer app = new TableRenderer();
SwingUtilities.invokeLater(app::show);
}
#SuppressWarnings("serial")
private static class TableModel extends AbstractTableModel {
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return "this is cell at ("+columnIndex+"; "+rowIndex+")";
}
#Override
public int getRowCount() {
return 3;
}
#Override
public int getColumnCount() {
return 3;
}
};
private static class CellRenderer implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Rectangle cellRect = table.getCellRect(row, column, true);
Renderer renderer = new Renderer(cellRect.getSize(), value);
renderer.setSize(cellRect.getSize());
renderer.setPreferredSize(cellRect.getSize());
renderer.setBackground(java.awt.Color.BLACK);
return renderer;
}
}
#SuppressWarnings("serial")
private static class Renderer extends JFXPanel {
public Renderer(Dimension cellRect, Object value) {
super();
Group root = new Group();
Scene scene = new Scene(root);
Canvas canvas = new Canvas(cellRect.getWidth(), cellRect.getHeight());
canvas.getGraphicsContext2D().setFill(Color.RED);
canvas.getGraphicsContext2D().fillText(value.toString(), 10, 10);
canvas.getGraphicsContext2D().fillOval(10, 10, 10, 10);
root.getChildren().add(canvas);
setScene(scene);
}
}
}
In this case nothing appears in the cells and the application freezes.
The same thing works just fine if displayed in JPanel
import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
public class PanelRenderer {
private JFrame frame;
private JFrame createFrame(String title, JComponent component, int width, int height) {
final Dimension dimension = new Dimension(width, height);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(dimension);
frame.setSize(dimension);
frame.add(component);
frame.setTitle(title);
Util.center(frame);
frame.pack();
return frame;
}
private void show() {
try {
init();
} catch (IOException e) {
e.printStackTrace();
}
frame.setVisible(true);
}
private void init() throws IOException {
JPanel p = new JPanel();
p.add(new Renderer(new Dimension(200, 200), "Demo"));
frame = createFrame("Renderer Demo - JPanel", p, 200, 200);
}
public static void main(String[] args) {
PanelRenderer app = new PanelRenderer();
SwingUtilities.invokeLater(app::show);
}
#SuppressWarnings("serial")
private static class Renderer extends JFXPanel {
public Renderer(Dimension cellRect, Object value) {
super();
Group root = new Group();
Scene scene = new Scene(root);
Canvas canvas = new Canvas(cellRect.getWidth(), cellRect.getHeight());
canvas.getGraphicsContext2D().setFill(Color.RED);
canvas.getGraphicsContext2D().fillText(value.toString(), 10, 10);
canvas.getGraphicsContext2D().fillOval(10, 10, 10, 10);
root.getChildren().add(canvas);
setScene(scene);
}
}
}
I've tried to add the renderer in a JPanel and return that as a cell renderer component, no change.
I've tried to synchronize FXThread and EDT, it is a hell and nothing happens.
I've tried to render an image, create a Component, overwrite the paintComponent to draw image, and synchronize the threads. That seems to work on Windows, but on OSX still fails.
I'm doing something wrong, or I should accept that this usecase is from the devil and no way to make it work?

How to hide Swing accelerators by a text pane?

I have a Swing application with multiple panes. Some of the panes are text ones (JTextPane), some are dialog-like (with buttons and sliders) and some are graphical (custom painted ). I have a few actions defined in the main menu with simple accelerators like K, P or O.
I would like those accelerators to be processed by the menu actions only if the currently focused pane is not processing them. Specifically, I do not want them to be processed by the menu when the user is just typing in a text pane.
I am creating actions and menu items using:
action = new javax.swing.AbstractAction
new MenuItem(action)
I am registering accelerators with:
action.putValue(javax.swing.Action.ACCELERATOR_KEY, keyStroke)
Is it possible to "eat" (suppress) the key press event for the keys which are processed in the text panes so that they are not passed to the main menu for the global processing?
If not, are there some alternatives to do something similar, like to register the accelerators I know should not be processed when in a text pane for some panes only?
I am adding a code based on an answer to make the question clearer (and to make developing alternate solutions easier):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here I want no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here I want accelerators working"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is the example. In text area no key bindings working. In text field work all key bindings. Also all the menu items are accessible (enabled) from the menu.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
menu.add(new PrintAction("O", KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)));
menu.add(new PrintAction("K", KeyStroke.getKeyStroke(KeyEvent.VK_K, 0)));
menu.add(new PrintAction("P", KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)));
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
area.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
setItemStatus(menu, true);
}
#Override
public void focusGained(FocusEvent e) {
setItemStatus(menu, false);
}
});
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static void setItemStatus(JMenu aMenu, boolean aStatus) {
for (Component item : aMenu.getMenuComponents()) {
((JMenuItem) item).getAction().setEnabled(aStatus);
}
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is a solution using KeyBindinds, as suggested by camickr. It is shorter than the one provided by Sergiy Medvynskyy, and I find it more straightforward, but it has a drawback the shortcut is not displayed in the menu, which is a result of the shortcut not being defined in the action itself.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O");
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators") {
{
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0), "command_O");
getActionMap().put("command_O", oAction);
}
}, BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr) {
super("Print: " + aPrintStr);
str = aPrintStr;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
It is possible to use KeyEventDispatcher to filter key events.
(Credit: I have adapted the code from answer to Application wide keyboard shortcut)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
final JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
// pass only KEY_TYPED for letters with no modifiers in the editing area, suppress KEY_PRESSED, KEY_RELEASED
return area.isFocusOwner() && keyStroke.getModifiers()==0 && e.getID()!=KeyEvent.KEY_TYPED && Character.isLetter(e.getKeyChar());
}
});
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

different font for combo box in Java

I would make a little rft text editor in Java and I would have that the different kind of fonts are show in my combo box in that font. The reason is because the user can see that font.
I know that you can use a combo box item for C#. But I didn't know for Java.
Can anyone help me?
Edit:
Sounds like you need to implement a custom renderer for your combo box.
See the java tutorial here: http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer
i.e. Something like this (assuming the Objects in your combo box are Fonts):
class CustomRenderer implements ListCellRenderer
{
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = new JLabel();
label.setFont(((Font) value).deriveFont(12f));
label.setText(((Font) value).getFontName());
return label;
}
}
Custom Combo box for font selection in java
Here is code :
package stack;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class CustomComboBox {
JComboBox fontComboBox;
JFrame frame;
String fontName[];
Integer array[];
public CustomComboBox() {
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
fontName = ge.getAvailableFontFamilyNames();
array = new Integer[fontName.length];
for(int i=1;i<=fontName.length;i++) {
array[i-1] = i;
}
fontComboBox = new JComboBox(array);
ComboBoxRenderar renderar = new ComboBoxRenderar();
fontComboBox.setRenderer(renderar);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(fontComboBox);
frame.pack();
frame.setVisible(true);
}
public class ComboBoxRenderar extends JLabel implements ListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
int offset = ((Integer)value).intValue() - 1 ;
String name = fontName[offset];
setText(name);
setFont(new Font(name,Font.PLAIN,20));
return this;
}
}
public static void main(String args[]) {
new CustomComboBox();
}
}
and preview of the code see the Image
:

SwingX AutoCompleteDecorator : no suitable methode found for decorate

I am trying to test SwingX for the first time,For this, I read the doc : http://www.jdocs.com/swingx/1.0/org/jdesktop/swingx/autocomplete/AutoCompleteDecorator.html
I'd like to make a suggestion on a JTextField like this:
List items = [...];
JTextField textField = [...];
AutoCompleteDecorator.decorate(textField, items);
so I create a project on netbeans, this is my code:
package test_swingx;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
/**
*
* #author marwen
*/
public class Test_swingx extends JFrame {
public Test_swingx(String title) throws HeadlessException {
this.setTitle(title);
JPanel pan=new JPanel();
JTextField jtf=new JTextField();
jtf.setColumns(20);
List items = new ArrayList();
items.add("hello");
items.add("marwen");
items.add("allooo");
AutoCompleteDecorator.decorate(jtf, items);
pan.add(jtf);
this.setContentPane(pan);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setBounds(280, 150, 500, 200);
}
public static void main(String[] args) {
Test_swingx tsx=new Test_swingx("helloo swingx");
}
}
I get this error :
no suitable methode found for decorate....
I'm following well the syntax , I do not understand where the error come?
ANY HELPS ?
Your method decorate call, is resolve to the first method below which is incorrect. Second method decorate expected JList instead of list.
public static void decorate(JComboBox comboBox, ObjectToStringConverter stringConverter)
public static void decorate(JList list, JTextComponent textComponent)
However, if you still want to use List, you should use this method,
public static void decorate(JTextComponent textComponent, List<?> items, boolean strictMatching)
I've changed the error part in your question with this.
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
public class Test_swingx extends JFrame
{
public Test_swingx(String p_title)
{
this.setTitle(p_title);
JPanel pan = new JPanel();
JTextComponent jtf = new JTextField();
((JTextField) jtf).setColumns(20);
List items = new ArrayList();
items.add("hello");
items.add("marwen");
items.add("allooo");
AutoCompleteDecorator.decorate(jtf, items, false);
pan.add(jtf);
this.setContentPane(pan);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setBounds(280, 150, 500, 200);
}
public static void main(String[] args)
{
Test_swingx tsx = new Test_swingx("helloo swingx");
tsx.setVisible(true);
}
}

Categories

Resources