JTable update columns header height after multiple header insertion - java

What should be invoked /fired when I added new column to the table but its header label has more lines (using html and br element) than in the already presents headers so the headers will resize accordingly?
Before adding
After adding
This does not happen if when first painting the table a column already has that number of rows (when the label is <html>Card<br>name</html>).
I fire fireTableStructureChanged() in TableModel when new record is added (so new columns are added).

Starting from #mKorbel's example, the following button alters the appearance as shown. The method setColumnIdentifiers() of DefaultTableModel invokes fireTableStructureChanged() on your behalf. If you extend AbstractTableModel, you should do this from within your TableModel.
Code:
private DefaultTableModel model = new DefaultTableModel(data, columnNames) {…}
…
frame.add(new JToggleButton(new AbstractAction("Toggle") {
#Override
public void actionPerformed(ActionEvent e) {
JToggleButton b = (JToggleButton) e.getSource();
if (b.isSelected()) {
columnNames[0] = "<html>String<br>of pearls</html>";
} else {
columnNames[0] = "String";
}
model.setColumnIdentifiers(columnNames);
}
}), BorderLayout.SOUTH);

Related

how to make JTable cell non editable but should be able to select and copy the value in current cell

I am trying to make JTable cells non-editable but if i do so Iam unable to select a single cell value instead when i try to copy the entire row is getting selected
I want to copy only the selected cell value instead of entire row.Is there a way to do it?
public class EmployeeWin extends JFrame {
DefaultTableModel model = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column){
return false;
}
};
Container cont = this.getContentPane();
JTable tab = new JTable(model);
private TableRowSorter<TableModel> rowSorter = new TableRowSorter<>(model);
private final JTextField searchFilter = new JTextField();
public EmpDataWin(List<EmployeeDTO> pEmployeeDTO) {
initialize(pEmployeeDTO);
}
public void initialize(List<EmployeeDTO> pEmployeeDTOList) {
JPanel panelParent = new JPanel(new BorderLayout());
// Add Header
model.addColumn("Employee Name");
model.addColumn("Department");
model.addColumn("Details");
// Add data row to table
for (EmployeeDTO aEmployeeDTO : pEmployeeDTOList) {
model.addRow(new Object[] { aEmployeeDTO.getEmployee_Name(), aEmployeeDTO.getDepartment(),
aEmployeeDTO.getDetails()});
}
tab.setRowSorter(rowSorter);
tab.setAutoCreateRowSorter(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JLabel(UIConstants.SEARCH), BorderLayout.WEST);
JTextField searchFilter = SearchFilter.createRowFilter(tab);
panel.add(searchFilter, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
tab.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane sp = new JScrollPane(tab,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
panelParent.add(panel,BorderLayout.NORTH);
panelParent.add(sp,BorderLayout.CENTER);
panelParent.setBorder(BorderFactory.createEmptyBorder(10 , 10, 10, 10));
cont.add(panelParent);
this.pack();
}
public static void main(String[] args) {
EmployeeDAO dao = new EmployeeDAO();
List<EmployeeDTO> dto = dao.getemployeeData();
JFrame frame = new EmployeeDataWin(dto);
}
}
when i try to copy the entire row is getting selected I want to copy only the selected cell value instead of entire row
The default Action for the Ctrl+C key is to copy the entire row. If you only want the data of the currently selected cell then you need to replace the default Action with a custom Action.
The logic would be something like:
Action copyCell = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
JTable table = (JTable)e.getSource();
int row = table.getSelectedRow();
int column = table.getSelectedColumn();
Object value = table.getValueAt(row, column);
// copy the data to the clipboard
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection testData = new StringSelection( value.toString() );
c.setContents(testData, testData);
}
};
table.getActionMap().put("copy", copyCell);
The above code will create the custom Action and replace it in the ActionMap of the JTable. See Key Bindings. The program provided in the link shows all the default Actions and the keyword for each Action.

Refresh table's row (Not row's value) on frame?

Sorry for being so amateur, I created a 'button' on a frame so that when we click the button for the first time, A ROW will be inserted on the frame. But ALL I WANT is that when I click the button THE SECOND TIME, the ROW IS REFRESHED (Not creating a new row!), I know that '.addRow(new Object[] { "", "", ""});' is the cause , because the object is created every time I click the button, so how could I possibly modify the code? Thanks for your attention.
*My weak brain said that if only I can empty 'model' object (or destroying the object, something like that), then I would find the solution, but how I could possibly empty/destroy that 'model' object?
import javax.swing.*;
import java.awt.event.*;
import javax.swing.table.DefaultTableModel;
public class MyTable extends JFrame {
private JTable table;
private DefaultTableModel model;
private JScrollPane scroll;
private JButton createRow;
private String headers[] = {"a", "b", "c"};
public MyTable() {
createRow = new JButton("Create Row");
model = new DefaultTableModel();
model.setColumnIdentifiers(headers);
table = new JTable();
table.setModel(model);
scroll = new JScrollPane(table);
add(createRow, java.awt.BorderLayout.NORTH);
add(scroll, java.awt.BorderLayout.CENTER);
createRowOn();
}
// while button is pressed then create A ROW
public void createRowOn() {
createRow.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == createRow) {
model.addRow(new Object[]{"", "", ""});
}
}
});
}
public static void main(String args[]) {
MyTable t = new MyTable();
t.setVisible(true);
t.setSize(300, 300);
}
}
Sorry for being so amateur
please read Oracle tutorial How to use Tables, especially part Creating Table Model
I created a 'button' on frame so that when we click the button for the
first time, A ROW will be inserted on frame. But all i want that when
i click the button on THE SECOND TIME , the ROW IS REFRESHED (Not
creating a new row !) , i suspect 'new Object[] { "", "", ""}' is the
cause , because the object is created everytime i click the button, so
how could i possibly modify the code ?
not clear from question (nothing is added to JTable) if you want to:
add a new row (model.addRow)
remove all rows (setDataVector/setRowCount)
reset value in JTables view (setValueAt)
but everything is described in Oracle tutorial, rest in the DefaultTableModel

JTable selection listener

I have a code which displays Table in applets & consists of two columns:-
image icon
description
Here's my code:
import javax.swing.table.*;
public class TableIcon extends JFrame
{
public TableIcon()
{
ImageIcon aboutIcon = new ImageIcon("about16.gif");
ImageIcon addIcon = new ImageIcon("add16.gif");
ImageIcon copyIcon = new ImageIcon("copy16.gif");
String[] columnNames = {"Picture", "Description"};
Object[][] data =
{
{aboutIcon, "About"},
{addIcon, "Add"},
{copyIcon, "Copy"},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable( model )
{
// Returning the Class of each column will allow different
// renderers to be used based on Class
public Class getColumnClass(int column)
{
return getValueAt(0, column).getClass();
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
getContentPane().add( scrollPane );
}
public static void main(String[] args)
{
TableIcon frame = new TableIcon();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible(true);
}
}
Now what i want to know is how can I implement selection listener or mouse listener event on my table , such that it should select a particular image from my table and display on text area or text field(my table contains path of image file)?
Can I add text field on table & table on frame? Please feel free to ask queries if required.
In my code I have a table where I set single selection mode; in my case, listener described in How to Write a List Selection Listener (with a for loop from getMinSelectionIndex to getMaxSelectionIndex) is not useful because releasing mouse button I'm sure I have just one row selected.
So I've solved as follows:
....
int iSelectedIndex =-1;
....
JTable jtable = new JTable(tableModel); // tableModel defined elsewhere
jtable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
ListSelectionModel selectionModel = jtable.getSelectionModel();
selectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
handleSelectionEvent(e);
}
});
....
protected void handleSelectionEvent(ListSelectionEvent e) {
if (e.getValueIsAdjusting())
return;
// e.getSource() returns an object like this
// javax.swing.DefaultListSelectionModel 1052752867 ={11}
// where 11 is the index of selected element when mouse button is released
String strSource= e.getSource().toString();
int start = strSource.indexOf("{")+1,
stop = strSource.length()-1;
iSelectedIndex = Integer.parseInt(strSource.substring(start, stop));
}
I think this solution, that does not require a for loop between start and stop to check which element is selectes, is more suitable when table is in single selection mode
How about this?
protected void handleSelectionEvent(ListSelectionEvent e) {
if (e.getValueIsAdjusting())
return;
final DefaultListSelectionModel target = (DefaultListSelectionModel)e.getSource();
iSelectedIndex = target.getAnchorSelectionIndex();
}
Read the section from the Swing tutorial on How to Write a List Selection Listener.
You can't add a text field to the table, but you can add a textfield and a table to the same frame.

Java: JTable Listener in AbstractTableModel seems to not work

I have been reading about the TableModelListener (http://www.cs.auckland.ac.nz/compsci230s1c/lectures/xinfeng/swingmodelview.pdf) for a while now and I am trying to implement a Listener for a JTable which uses the AbstractTableModel.
To explain the different parts of my program my class. My main class extends JFrame and implements TableModelListener so that is why I have this tableChanged method.
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE)
System.out.println("It is updated");
if (e.getType() == TableModelEvent.DELETE)
System.out.println("It is deleted");
}
My Class SwitchTableModel which extends AbstractTableModel - Which is not the constructor - creates a table which displays some values which are taken from some other arrays. Part of the implementation is here Display the next row of a List in a JTable .
I use the constructor to call the SwitchTableModel class and create the JTable and the JFrame.
I have also added this row in to get when a value is updated.
public Object getValueAt(int rowIndex, int columnIndex) {
fireTableCellUpdated(rowIndex, columnIndex); ...
The thing that I would like to be able to edit my JTable and then save its data, but although it seems that I could edit it, when I write smth for example in a empty field and press enter, it doesn't keep the data. The same happens when I try to change smth in a non-empty field.
Actually, with this code, it continues printing "It is edited" for the whole time that the JFrame stays open.
Any idea what I might be doing wrong?
***** EDIT *****
My constructor is like this:
final SwitchTableModel model = new SwitchTableModel(user_decide);
JTable table = new JTable(model);
JFrame frame = new JFrame ("Results");
table.getModel().addTableModelListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add (toolbar, BorderLayout.PAGE_START);
frame.getContentPane().add (
new JScrollPane(
table,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED),
BorderLayout.CENTER);
//frame.add(checkPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}

Interacting with JTable which is rapidly updated with new rows

Brief description of a problem.
Assume we have JTable and user interacting with it in some way. TableModel of this table is constantly changing. How to ensure that when user tries to get some info from the table by referencing some constant column and currently selected row (by its rowIndex he got from JTable), he will not get into situation when TableModel is changed and his rowIndex obtained from JTable is no longer corresponding to same value in TableModel.
Following is initial question which explains problem in more detail:
Consider following situation:
There is JTable which shows user info about currently running requests in some system
When new request enters system, new row is being added to the table
user can interact with table by right-clicking on a row (single row selection model is used in table) and choosing option from the menu (like: abort, postpone, retry, etc.)
there is separate class which implements ActionListener interface (listens to the table) and handles all user interactions
When user does some action on the table this class checks currently selected row and assigns some values for user's action (basically it takes index of selected row and then calls tableModel.getValueAt(indexOfSelectedRow, someValuableDataColumnIndex))
Now consider scenario when system is under stress test and requests are being submitted constantly with big frequency. This, in my case, leads to a bug, when sometimes class which handles user's actions gets wrong info from table model (action was called on one row, but action is done for another, usually next one). I believe this happens because during some inits in action handling class table model is changed because of new request accepted.
Question is, how to fix this. I am thinking about two approaches:
use something like invokeAndWait() for initialization in my user actions' handling class (don't like this idea, because imo it will lead to other unpredictable bugs)
creating separate listener class which will listen to user selections in the table and store data from selected row as soon as it was selected separately from TableModel. This way actions handling class will take data not from table model which is being changed, but from selected row, which is constant during the described scenario. (not sure this idea will work)
Please, comment on my ideas, and suggest yours.
I am sorry for absence of any code here, but original code will take way too much space, and model example isn't something what can be done easily here.
I don't think inserting rows in a table changes the selection, so as long as you are updating the TableModel on the EDT, the selected row is still same when the user shows the popup and chooses and action from the popup.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class TestJTableInsert {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final DefaultTableModel model = new DefaultTableModel(0, 1);
new Timer(500, new ActionListener() {
private final Random random = new Random();
private int data = 1;
#Override
public void actionPerformed(ActionEvent e) {
model.insertRow(random.nextInt(model.getRowCount() + 1),
new Object[] { data++ });
}
}).start();
final JTable table = new JTable(model);
JPopupMenu popup = new JPopupMenu();
popup.add(new AbstractAction("Which row is this?") {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(table,
"This is row " + table.getValueAt(table.getSelectedRow(), 0));
}
});
table.setComponentPopupMenu(popup);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
model example isn't something what can be done easily here.
Here's a starter to demonstrate that the selection is kept constant (in the sense that it always points to the same "real" row:
final DefaultTableModel model = new DefaultTableModel(0, 1);
for (int i = 0; i < 50; i++) {
model.addRow(new Object[] {i});
};
final JXTable table = new JXTable(model);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setRowSelectionInterval(25, 25);
Action l = new AbstractAction("random insert") {
Random random = new Random();
#Override
public void actionPerformed(ActionEvent e) {
int row = random.nextInt(model.getRowCount());
model.insertRow(row, new Object[] {"inserted at: " + row});
table.scrollRowToVisible(table.getSelectedRow());
}
};
new Timer(100, l).start();

Categories

Resources