JTable - compound editor focus - java

I have a custom editor composed of several components. Something like:
class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
JTextArea textArea;
JButton button;
JPanel panel;
MyCellEditor() {
textArea = new JTextArea();
button = new JButton();
panel = new JPanel(new BorderLayout());
panel.add(textArea, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
textArea.setText((String) value);
return panel;
}
public Object getCellEditorValue() {
return textArea.getText();
}
}
I want the inner textArea to grab focus when editing starts. It works just fine when I click the cell, but not when I navigate the table with keyboard and start typing in this cell.
How can I fix this?

I had the same problem some time ago and took me ages to find a solution. Tried a lot with focuslistener and stuff, but nothing really seemed to work the way I wanted it to until I found this useful article by Santhosh Kumar.
Its well written and should fix your problem.

Related

JPopupMenu gets closed as soon as the mouse enters in an embedded JCheckboxMenuItem

I wrote the following code to have a JPopupMenu that allows multiple selection of different items.
The problem is that, as soon as the mouse enters one of the displayed JCheckboxMenuItems, the JPopupMenu gets closed. This issue doesn't occur if I replace JCheckboxMenuItem with, for example, JLabel but, for sure, JLabel doesn't work for my purpose.
Any idea of what could trigger this issue? Any idea of how this problem can be resolved in a better way? I apologize for the newbie question but I'm not a java developer. Thanks in advance for any help.
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedborder(),"Select Layers");
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
for (MyAction layer : layers) {
JCheckBoxMenuItem box = new JCheckBoxMenuItem(layer);
box.setIcon(new SquareIcon(myColor));
panel.add(box);
}
JPopup popup = new JidePopup();
popup.add(panel)
JButton button = new JButton("Layers");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
popup.show(button,0,button.getHeight())
}
});
Thats in the nature of JPopupMenus. They disappear when the invoker component loses the focus. But I found a little trick here.
Create your own class and extend it from JPopupMenu. Then override the setVisible method that it will only forward true to the super class and create an own method that will setVisible of the super class to false.
public class StayOpenPopup extends JPopupMenu{
public void setVisible(boolean visible){
if(visible == true)
super.setVisible(visible);
}
public void disappear() {
super.setVisible(false);
}
}
Then use it like this in your code
[...]
StayOpenPopup popup = new StayOpenPopup();
popup.add(panel);
[...]
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(popup.isVisible())
popup.disappear();
else popup.show(button,0,button.getHeight());
}
});
Now one click on button will show it. And it will stay visible until next click on Button.

Adding JButton in a column in JTable (JAVA)

I am currently reading an excel sheet (.xls) and placing it in a JTable. The excel sheet consists of 3 columns. I am successfully able to read it. However, when reading the excel sheet, I want to add an extra fourth column in the JTable that includes JButtons (One button for each row). When JButton is clicked in a row, I want to take the content of the third column and perform some action.
I am currently using the code from here.
What is the best way to add JButtons in a JTable column?
You can create a class extending JButton. Then add property to that class.(field with getter and setter) when you adding data to the table, add JButton instance for each row using your custom JButton class and set value in the third column using setter method. So you can use that value in processing in the click event. Hope it helps :)
You can add your button this way.
class MyRenderer implements TableCellRenderer {
JButton button = new JButton();
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
button.setText(value.toString());
return button;
}
and to add action listener do this
class mybutttoneditor extends AbstractCellEditor implements TableCellEditor,
ActionListener {
JTable table;
JButton button = new JButton();
public mybutttoneditor(JTable table) {
this.table = table;
button.setFont(new Font("Serif", Font.BOLD, 14));
button.setForeground(Color.blue);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
final int row = table.getEditingRow();
String column3data=table.getValueAt(row, 2);
//do what you want with the data here
//hopefully this helps and if so accept the answer
}
//other abstract methods are here
}
}
DefaultTableModel md=(DefaultTableModel)mytable.getModel();
//do this while reading your excel sheet
Object row[]={"dataone","datatwo","data3","Open Button"};
md.addRow(row);
TableColumnModel colModel = mytable.getColumnModel();
colModel.getColumn(3).setCellRenderer(new MyRenderer());
colModel.getColumn(3).setCellEditor(new mybutttoneditor(mytable));

Adding JPanel to JList

I want to add a custom objects that extend JPanel into a JList. Everything is fine, but I can not interact with them. For example, I can not type in the JTextField which is added on panel. I Use DefaultListModel<ListItem = new DefaultListModel<ListItem>(); Plase help.
This is custom Object
public class ListItem extends JPanel{
private static final long serialVersionUID = 1L;
private JTextField textField;
public ListItem() {
setLayout(new MigLayout("", "[grow][grow]", "[30px:n:30px][30px:n:30px][30px:n:30px]"));
JLabel lblNewLabel = new JLabel("New label");
add(lblNewLabel, "cell 0 0,alignx trailing");
textField = new JTextField();
add(textField, "cell 1 0,growx");
}
This is the renderer
public class ListItemRenderer implements ListCellRenderer<Object>{
#Override
public Component getListCellRendererComponent(JList<? extends Object> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component component = (Component) value;
if(isSelected)
component.setBackground(Color.RED);
return component;
}
This is how I create List
list = new JList<ListItem>(addedItems);
And
ListItem temp = new ListItem();
addedItems.addElement(temp);
list.setCellRenderer(new ListItemRenderer());
I want to add a custom objects that extend JPanel into a JList. Everything is fine, but I can not interact with them. For example, I can not type in the JTextField which is added on panel.
That is because a Jlist does not hold or show components but rather only rendering of components. If you want a list like object that holds components that can be edited, that the user can interact with, then either create your own -- using a JPanel that uses GridLayout and holds a grid of your components, or use a JTable that has at least two columns, one (the "label") that's not editable, and the other (the "text field") that is.

How to refresh JTree UI

I have a JTree that shows files and folders of a directory. Also there is a button that disables some of the nodes in the JTree (using DefaultTreeCellRenderer).
The item gets disabled when I press the button, but JTree does not show it as a disabled item. Until I click somewhere, or in on if the items of the tree, then it also shows the disabled look of the item.
I know there is a reload() method for DefaultTreeModel. But I use a customised model. So this method doesnt work. Here is the model that I use to list files and folders: FileSystemModel
And this is my code:
public class FileViewer {
JFrame frame;
JPanel panel;
JTree tree;
File root;
public ArrayList<String> disabledNodes = new ArrayList<String>();
public FileViewer(){
frame = new JFrame("File Viewer");
panel = new JPanel(new BorderLayout());
root = new File("D:\\Documents\\A X");
FileSystemModel model = new FileSystemModel(root);
tree = new JTree();
tree.setModel(model);
panel.add(tree, BorderLayout.CENTER);
JButton press = new JButton("Press");
panel.add(press, BorderLayout.SOUTH);
press.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
disabledNodes.add("folder1");
}
});
tree.setCellRenderer(new CustomDefaultTreeCellRenderer());
frame.add(panel);
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new FileViewer();
}
class CustomDefaultTreeCellRenderer extends DefaultTreeCellRenderer{
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus){
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
File node = (File)value;
String name = node.getName();
for(String element : disabledNodes){
if(name.equals(element)){
this.setEnabled(false);
}
}
return this;
}
}
}
However, in the ActionListener of the button, I added tree.updateUI(); and it perfectly worked. But somehow I have heard updating UI is a bad practice since it will make other problems later. So is using updateUI correct here? or there is a better way to make the UI updated with clicks and user interactions?
Note, I will not add or remove any file from the tree, I just have to enable/disable nodes.
UPDATE: I just notice there is a repaint() option that does similar function for me. But still, Is it the right way of refreshing the JTree?
repaint() is the correct API to use in this situation.

MouseEvents for a JTabbedPane Tab component are not bleeding through

I have a JTabbedPane with a custom tab component. That component contains a JLabel (To display the tab title) and a JButton (A close button). When I change the text in the JLabel the JLabel stops receiving mouse events and I can no longer select that tab when I click directly on the label instead if I click around the label then I can select the tab. Any ideas?
A snippet of the code:
class ShellPanelTabComponent extends JPanel implements ActionListener{
private ShellPanel panel;
private JLabel label;
public ShellPanelTabComponent(final ShellPanel panel){
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.panel = panel;
setOpaque(false);
label = new JLabel(panel.getTitle());
label.setFocusable(false);
add(label);
label.setBorder(BorderFactory.createEmptyBorder(2,0,0,5));
//now the button
CloseButton closeButton = new CloseButton(panel);
add(closeButton);
closeButton.addActionListener(this);
}
public void actionPerformed(ActionEvent ae) {
panel.getShell().removeShellPanel(panel);
}
/**
* #return the label
*/
public JLabel getLabel() {
return label;
}
}
I don't recall seeing such a problem in the TabComponentsDemo, discussed in How to Use Tabbed Panes. You might compare your code with that example as a reference.
Addendum: Re-factoring ButtonTabComponent to include getLabel(), this version of runTest() in TabComponentsDemo adds a button that evinces the desired behavior. In particular, each time the button is pressed, the tabs are redrawn to display the enlarged title.
Update: Modify correct tab component after pane.remove().
public void runTest() {
pane.removeAll();
for (int i = 0; i < tabNumber; i++) {
final int titleIndex = i;
String title = "Tab " + titleIndex;
final JButton button = new JButton("Relabel tab");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int index = pane.indexOfComponent(button);
ButtonTabComponent btc = (ButtonTabComponent)
pane.getTabComponentAt(index);
JLabel label = btc.getLabel();
pane.setTitleAt(index, label.getText() + titleIndex);
label.invalidate();
pane.repaint();
}
});
pane.add(title, button);
initTabComponent(i);
}
tabComponentsItem.setSelected(true);
pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
scrollLayoutItem.setSelected(false);
this.setPreferredSize(new Dimension(500, 200));
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
I seem to remember a question like this recently although I can't find the posting. I believe the problem is that the "custom component" receives the mouse event so it is not passed on to the tabbed pane. The solution suggested was to use the dispatchEvent(...) method to redispatch the mouse event to the proper tab.
The problem is related to the one that I posted here after I did more digging: Workaround for setToolTipText consuming mouse events?

Categories