NullPointerException in Clicking a row in JTable - java

I want to activate a button if I click an empty 8th column in my Jtable. But I'm getting this:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at records$1.valueChanged(records.java:57)
Here's my code:
tb_records.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
public void valueChanged(ListSelectionEvent event) {
int row = tb_records.getSelectedRow();
DefaultTableModel model = (DefaultTableModel)tb_records.getModel();
String hehe = (String) model.getValueAt(row, 7);
if(!hehe.equals("")) {
b_extend.setEnabled(false);
}
else {
b_extend.setEnabled(true);
}
}
});

(not an answer, I'd be talking about simple way)
change ListSelectionMode to SINGLE_...., then only one row can be selected, otherwise you have to loop inside array of selected rows
test if (row > -1) == no row is selected, if passed then you can to
for better help sooner post an SSCCE, short, runnable, compilable, with hardcoded value for JTable

I made few changes to your code, may be help.
.(new ListSelectionListener(){
public void valueChanged(ListSelectionEvent e) {
if (! e.getValueIsAdjusting() ) {
ListSelectionModel d = (ListSelectionModel)e.getSource();
if(d.getLeadSelectionIndex() != -1){
String hehe = (String) model.getValueAt(d.getLeadSelectionIndex(), 7);
b_extend.setEnabled("".equals(hehe));
}
}
}
});

Related

Adding colors to row in nattable based on condition

I have a column 'Lifecycle' in my NAT Table based on which i have to set respective color to each row.
Adding color to row works fine. The problem is when i use the scroll bar to scroll either left or right, the color disappears. I am not aware what i am missing. Kindly help me if you have any idea of how it can be resolved
My code looks like:
IConfigLabelAccumulator cellLabelAccumulator = new IConfigLabelAccumulator() {
#Override
public void accumulateConfigLabels(final LabelStack configLabels, final int columnPosition,
final int rowPosition) {
Object dataValueByPosition = PhysicalDimensionNatTable.this.bodyLayer.getDataValueByPosition(10, rowPosition);
if ((dataValueByPosition != null) && dataValueByPosition.equals("Valid")) {
configLabels.addLabel("VALID");
}
if ((dataValueByPosition != null) && dataValueByPosition.equals("Invalid")) {
configLabels.addLabel("INVALID");
}
if ((dataValueByPosition != null) && dataValueByPosition.equals("Obsolete")) {
configLabels.addLabel("OBSOLETE");
}
}
};
this.bodyLayer.setConfigLabelAccumulator(cellLabelAccumulator);
this.natTable.addConfiguration(new AbstractRegistryConfiguration() {
#Override
public void configureRegistry(final IConfigRegistry configRegistry) {
Style cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_GREEN);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, DisplayMode.NORMAL, "VALID");
cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, DisplayMode.NORMAL,
"INVALID");
cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_YELLOW);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, DisplayMode.NORMAL,
"OBSOLETE");
}
});
The issue that you are facing is that the IConfigLabelAccumulator is registered on the bodyLayer, and I assume that is a stack where the top most layer is the ViewportLayer. bodyLayer.getDataValueByPosition(10, rowPosition); is returning the data value of the column position 10. And the underlying cell changes on scrolling as for example the column with index 11 becomes the column at position 10 if the first column moves out of the visible range. That is the index-position-transformation which is a basic concept in NatTable.
Either you need to perform a transformation calculation e.g. via LayerUtil to get the index, or operate on the DataLayer of the body directly instead of the bodylayer stack. Then you don't need to consider the index-position-transformation. I typically suggest to use the later.
As the index-position-transformation handling is too abstract for several people, another option is to operate on the object on the DataLayer. For this the IConfigLabelAccumulator needs to know the IRowDataProvider to be able to access the row object. And then register it on the DataLayer.
An example would look like the following snippet. Of course it should be transferred to your solution with better class separation.
IRowDataProvider<PersonWithAddress> bodyDataProvider = new ListDataProvider<>(data, accessor);
DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
bodyDataLayer.setConfigLabelAccumulator(new IConfigLabelAccumulator() {
#Override
public void accumulateConfigLabels(LabelStack configLabels, int columnPosition, int rowPosition) {
PersonWithAddress person = bodyDataProvider.getRowObject(rowPosition);
if ("Simpson".equals(person.getLastName())) {
configLabels.addLabel("YELLOW");
}
}
});

Set tooltip for cells in jTable without overriding getToolTipText()

I am making gui with the NetBeans GUI Builder(Swing) and need to set different tooltips for each cells in the header. The problem is that jTable is generated automatically, so I can't override its methods.
Is there any possibility to do it without the overriding getToolTipText()?
One way to do this sort of thing is to add a subclass which extends the MouseMotionAdapter and a method to your code to carry out the task for you. Simply place the following SubClass code below the end of your main Class.
class JTableColumnHeaderToolTips extends MouseMotionAdapter {
TableColumn curCol;
// Create a Map to hold the Header Column
// index value and the tooltip related to
// it.
Map headerColumnTips = new HashMap();
// Method to Set tips into Map.
public void setHeaderColumnToolTip(TableColumn column, String tooltip) {
if (tooltip == null) {
headerColumnTips.remove(column);
}
else {
headerColumnTips.put(column, tooltip);
}
}
// Override the Header's mouseMoved event so as
// to display the appropriate tooltip for whatever
// column the mouse pointer is currently on.
#Override
public void mouseMoved(MouseEvent event) {
JTableHeader header = (JTableHeader) event.getSource();
JTable table = header.getTable();
TableColumnModel colModel = table.getColumnModel();
int colIndex = colModel.getColumnIndexAtX(event.getX());
TableColumn column = null;
if (colIndex >= 0) {
column = colModel.getColumn(colIndex);
}
if (column != curCol) {
header.setToolTipText((String) headerColumnTips.get(column));
curCol = column;
}
}
}
Then add this method setJTableColumnToolTips() somewhere within your main Class:
private void SetJTableHeaderColumnToolTips(JTable table, String[] columnToolTips) {
JTableHeader tableHeader = table.getTableHeader();
// See the JTableColumnHeaderToolTips SubClass.
JTableColumnHeaderToolTips toolTips = new JTableColumnHeaderToolTips();
for (int col = 0; col < table.getColumnCount(); col++) {
TableColumn columnIndex = table.getColumnModel().getColumn(col);
toolTips.setHeaderColumnToolTip(columnIndex, columnToolTips[col]);
}
tableHeader.addMouseMotionListener(toolTips);
}
To use this method you might do it this way:
// Provide the Tooltips you want for
// each column within a String Array.
String[] columnToolTips = {"First Name",
"Last Name",
"The person's address",
"The person's phone number",
"The person's age",
"The person's salary"};
// Set your desired ToolTips to the Header Column cells
setJTableHeaderColumnToolTips(recordsTable, columnToolTips);

How to add MouseListener to a table model

I have a JTable. When a user clicks on a cell another JTable is created that shows the data for the whole row of that cell, in a column format (ie the row is converted to a column).
This happens when the user clicks but its a bit irritating to happen every time so I want to make it only on a double click.
The problem is that the getSelection method of the table only takes a addListSelectionListener method and not a MouseListener. How can I do what I want?
Here is the code:
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
DefaultTableModel newModel = new DefaultTableModel();
String rowName = "Row: " + selectedRow;
newModel.setColumnIdentifiers(new Object[]{rowName});
for (int i = 0; i < table.getModel().getColumnCount(); i++) {
newModel.addRow(new Object[]{table.getModel().getValueAt(selectedRow, i)});
}
JTable newTable = new JTable(newModel) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(140, 240);
}
};
// Apply any custom renderers and editors
JOptionPane.showMessageDialog(frame, new JScrollPane(newTable),
rowName, JOptionPane.PLAIN_MESSAGE);
}
}
});
This happens when the user clicks but its a bit irritating to happen every time so I want to make it only on a double click
You use a MouseListener, not a ListSelectionListener. You would check the Mouse event for a click count of 2.
Read the section from the Swing tutorial on How to Write a MouseLister for more information and working examples.
Also, a double click will start the editor by default so you want to make sure the cell is not editable. So you may need to override the isCellEditable(...) method of the table.

Jtable dynamical fixed columns problems

I created a class that can dynamically to lock and unlock columns .
In my program i create two tables with the same tablemodel.
One is in the Jviewport of the scrollpane, the other in the RowHeaderView.
The problem is when you unlock all the locked columns
and you want to start to lock again, doesn't work. There are no errors but it's like the event doesn't answer.
Steps to produce the problem:
Try the code,
put all the columns in the fixed table,
then unlock with right double click,
then start again to lock, and unlock
Do this procedure and you can see that the mouse event doesnt answer anymore
public class Prova extends JFrame{
private JTable mainTable,fixedTable;
private JScrollPane scrollPane;
private JTableHeader mainTableHeader;
private TableColumnModel originalColumnModel,mainColumnModel,fixedColumnModel;
private TableColumn[] columns;
private int ncols,counter;
public Prova(){
counter = 0;
TableModel mainTableModel = new DefaultTableModel(5, 10);
scrollPane = new JScrollPane();
mainTable = new JTable(mainTableModel);
mainColumnModel = mainTable.getColumnModel();
fixedTable = new JTable();
fixedTable.setAutoCreateColumnsFromModel(false);
fixedTable.setModel(mainTable.getModel() );
ncols = mainTableModel.getColumnCount();
columns = new TableColumn[ncols];
for (int i=0;i<ncols;i++){
columns[i] = mainColumnModel.getColumn(i);
}
mainColumnModel = mainTable.getColumnModel();
fixedColumnModel = fixedTable.getColumnModel();
mainTableHeader = mainTable.getTableHeader();
mainTableHeader.addMouseListener( new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent me){
if (SwingUtilities.isRightMouseButton(me)){
if (ncols - counter>1){
counter ++;
int col = mainTable.columnAtPoint(me.getPoint());
TableColumn column = mainColumnModel.getColumn(col);
mainColumnModel.removeColumn(column);
fixedTable.getColumnModel().addColumn(column);
scrollPane.setRowHeaderView(fixedTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
}
}
}
});
fixedTable.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me){
if (SwingUtilities.isRightMouseButton(me) && me.getClickCount()== 2 ){
while (mainColumnModel.getColumnCount() > 0){
mainColumnModel.removeColumn(mainColumnModel.getColumn(0));
}
while (fixedColumnModel.getColumnCount() > 0){
fixedColumnModel.removeColumn(fixedColumnModel.getColumn(0));
}
for(int i=0;i<ncols;i++){
mainColumnModel.addColumn(columns[i]);
}
scrollPane.setRowHeaderView(null);
}
}
});
scrollPane.setViewportView(mainTable);
add(scrollPane, BorderLayout.CENTER);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Prova().setVisible(true);
}
});
}
}
A few pointers when posting a SSCCE:
for (int i=0;i<ncols;i++){
Don't be afraid to use whitespace in you code to make it more readable be separating the 3 statements of the for statement.
for (int i = 0; i < ncols; i++){
Keep the code simple and directly related to the problem:
TableModel mainTableModel = new EmployeeTableModel(listEmployees);
You question is about "moving columns", not about the data in the table so there is no need for a special TableModel and the Employee class. Just use the DefaultTableModel:
TableModel mainTableModel = new DefaultTableModel(5, 10);
Your current code won't compile because you didn't include the Employee class. By using JDK classes the code is smaller and easier to read.
The problem is when you unlock all the locked columns and you want to start to lock again, doesnt work
Your looping code is wrong. I didn't bother to figure out what was wrong. Instead I made the code simpler:
//for(int i=0;i<(ncols-counter);i++){
while (mainColumnModel.getColumnCount() > 0)
{
mainColumnModel.removeColumn(mainColumnModel.getColumn(0));
}
//for(int i=0;i<counter;i++){
while (fixedColumnModel.getColumnCount() > 0)
{
fixedColumnModel.removeColumn(fixedColumnModel.getColumn(0));
}
Another problem is your fixed table doesn't have a header so you don't know what the columns are. This is fixed by using:
scrollPane.setRowHeaderView(fixedTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
Now that you have a header you need to add the MouseListener to the header, not the scrollpane:
//scrollPane.addMouseListener(new MouseAdapter() {
fixedTable.getTableHeader().addMouseListener(new MouseAdapter() {
Edit:
You have a similar problem to what I fixed above. That is don't keep using variable to track values when you can use the component itself.
if (ncols - counter>1){
You never reset the value of the counter so the if condition won't be true the second time.
As I did above just use the value from the column model:
//if (ncols - counter>1){
if (mainColumnModel.getColumnCount() > 1) {
This is just basic problem solving. Put a display statement in the block of code to see if it executes when you have problems.

How to select a column of a JTable in JDialog by selecting a header

What I've been trying to do with a JDialog are...
To select a column of JTable by clicking the header
To check which column is selected by the user
To get the value of the cells inside the column
According to this post and this page , it would be possible to select a column by clicking the header, by setting a JTableHeader.
However, neither of them seem to be applicable to what I'm trying to do.
First of all, I'm not sure where to put JTableHeader. The examples above seem to have put it for the initialization, but I don't see any appropriate space to do this in my coding.
At least I know that the second example is JPanel. So, in order to have a JTableHeader in JDialog, JTableHeader will need to be set in a completely different position, since initComponents() of JDialog cannot be modified manually by default.
In addition, I cannot find how to select a header (unlike individual cells). I assume that I need to set a JTableHeader beforehand.
Finally, I don't see any method to detect which column is selected. At least I found jTable.getValueAt(int, int) method, but this method seems to be made to get a single cell.
Now I suspect that it might be impossible to do them with JTable and JDialog. I'd appreciate if you'd give any insight.
I add a part of initComponents() so that you'd easily understand it.
private void initComponents() {
//here are irrelevant codes
jTable1 = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
jLabel1.setFont(new java.awt.Font("MS UI Gothic", 3, 18)); // NOI18N
jLabel1.setText("Choose level(s) or unit(s)");
//irrelevant codes
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{"EN6", "EN3", "EN5", "IN1"},
{"EN2", "EN3", null, "IN4"},
{null, null, null, "IN1"},
{null, null, null, "IN2"},
new String [] {
"EN2", "EN3", "EN5", "IN1"
}
) {
Class[] types = new Class [] {
java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
};
public Class getColumnClass(int columnIndex) {
return types [columnIndex];
}
});
//lots of lines, seem to be irrelevant
pack();
}
"[...]it would be possible to select a column by clicking the header, by setting a JTableHeader."
Based on your requirements I don't think you need to provide your own table header but attach a MouseListener to the default one instead. This way and using both rows and columns selection models you can easily achieve your goal.
Snippet
final JTable table = new JTable(tableModel);
table.setColumnSelectionAllowed(true);
table.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// Get the right column based on MouseEvent#getPoint()
int columnIndex = table.columnAtPoint(e.getPoint());
// Set this column as the selected one in the columns selection model
table.getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
// Set all the rows as the selected ones in the rows selection model
table.getSelectionModel().setSelectionInterval(0, table.getRowCount() - 1);
// Print the values in selected column
for (int rowIndex = 0; rowIndex < table.getRowCount(); rowIndex++) {
System.out.println(table.getValueAt(rowIndex, columnIndex));
}
}
});
Note: don't forget to allow columns selection.
See:
MouseEvent#getPoint()
JTable#columnAtPoint(Point p)
JTable#rowAtPoint(Point p)
How to Use Tables: User Selections
You can get the select cell's value using this. But is that right you want?
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if (arg0.getClickCount() == 1) { // 1 : one click, 2 : double click, 3 : right click
int column = table.getSelectedColumn();
int row = table.getSelectedRow();
String str = (String) table.getValueAt(row, column);
int[] rows = table.getSelectedRows();
String str2 = (String) table.getValueAt(rows[0], column);
}
}
});

Categories