I'm trying to set a button in enabled(false) when I create it, and when I select any row on the Jtable, that button goes enabled(true).
Logic is pretty simple here, but for some reason, it doesn't quite work, the button never gets into enabled(true).
JButton btnIniciarReparacin = new JButton("INICIAR REPARACI\u00D3N");
btnIniciarReparacin.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tiempoStart = (int) (System.currentTimeMillis() / 1000L);
btnIniciarReparacin.setEnabled(false);
}
});
btnIniciarReparacin.setFont(new Font("SansSerif", Font.BOLD, 13));
btnIniciarReparacin.setBackground(new Color(231, 111, 81));
btnIniciarReparacin.setBounds(129, 625, 254, 50);
frame.getContentPane().add(btnIniciarReparacin);
int row = table.getSelectedRow();
//Comprobamos si hemos cogido algo de la tabla y si los botones están encendidos
if (table.isRowSelected(row)) {
btnIniciarReparacin.setEnabled(true);
} else {
btnIniciarReparacin.setEnabled(false);
}
Swing GUI's work by your adding listeners to events and then responding to state changes within the listener.
You appear to be checking the row selection state in code where you create your components, and that will never work since it only checks the state once, and before the user has had a chance to make a selection. Instead, you need to use a listener on your JTable, more specifically a ListSelectionListener that you add to the JTable's selection model that you get via table.getSelectionModel().addListSelectionListener(...)
Also note that this:
int row = table.getSelectedRow();
if (table.isRowSelected(row)) {
btnIniciarReparacin.setEnabled(true);
} else {
btnIniciarReparacin.setEnabled(false);
}
can be shortened to:
int row = table.getSelectedRow();
btnIniciarReparacin.setEnabled(table.isRowSelected(row));
e.g. something like:
table.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
public void valueChanged(ListSelectionEvent event) {
int row = table.getSelectedRow();
btnIniciarReparacin.setEnabled(table.isRowSelected(row));
}
});
For example, if the button deletes a row:
import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class Test01 extends JPanel {
private static final String[] COLUMNS = {"One", "Two", "Three", "Four"};
private DefaultTableModel tableModel = new DefaultTableModel(COLUMNS, 0);
private JTable table = new JTable(tableModel);
private JButton deleteRowButton = new JButton("Delete Row");
public Test01() {
int tableRows = 20;
for (int i = 0; i < tableRows; i++) {
Integer[] row = new Integer[COLUMNS.length];
for (int j = 0; j < row.length; j++) {
row[j] = (int) (100 * Math.random());
}
tableModel.addRow(row);
}
table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
int row = table.getSelectedRow();
deleteRowButton.setEnabled(table.isRowSelected(row));
}
});
deleteRowButton.addActionListener(e -> {
int row = table.getSelectedRow();
tableModel.removeRow(row);
});
deleteRowButton.setEnabled(false);
JPanel bottomPanel = new JPanel();
bottomPanel.add(deleteRowButton);
setLayout(new BorderLayout());
add(new JScrollPane(table));
add(bottomPanel, BorderLayout.PAGE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
Test01 mainPanel = new Test01();
JFrame frame = new JFrame("Test01");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
Related
I've looked everywhere but can't seem to figure this out. I just want to pull out a cell's value from my JTable when a user clicks on it.
However at the moment I am getting -1 so I suppose double clicking results in no row being detected. Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLException;
import javax.swing.*;
import javax.swing.table.TableColumn;
public class CardLayoutExample {
private static JScrollPane scrollPane;
public static void main(String[] arguments) throws SQLException {
// main window
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame window = new JFrame("CardLayout Example");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1500,800);
window.getContentPane().setLayout(new BorderLayout());
final CardLayout cardLayout = new CardLayout();
final JPanel cardPanel = new JPanel(cardLayout);
JPanel card3 = new JPanel();
cardPanel.add(card3,"All Patients");
String AllPatients="select * from tblPtDetails";
JTable tablePatientDt = new JTable(Bquery.buildTableModel(Bquery.resultQuery(AllPatients)));
tablePatientDt.setEnabled(false);
tablePatientDt.setPreferredScrollableViewportSize(new Dimension(1200, 400));
tablePatientDt.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
tablePatientDt.setRowHeight(30);
tablePatientDt.setAutoCreateRowSorter(true);
card3.add(tablePatientDt);
card3.add(new JScrollPane(tablePatientDt), BorderLayout.CENTER);
for (int i = 0; i < (tablePatientDt.getColumnCount()); i++) {
TableColumn columnPatients = null;
columnPatients = tablePatientDt.getColumnModel().getColumn(i);
columnPatients.setPreferredWidth(70); //sport column is bigger
}
tablePatientDt.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int row = tablePatientDt.getSelectedRow();
int column = tablePatientDt.getSelectedColumn();
//Object val= tablePatientDt.getModel().getValueAt(row, column);
//tablePatientDt.getModel().getValueAt(row, column);
//return tablePatientDt.getModel().getValueAt(row, column);
System.out.println(row);
JFrame newFrame = new JFrame();
newFrame.setTitle("Detail Screen");
newFrame.setVisible(true);
}
}
});
Your main problem is here:
tablePatientDt.setEnabled(false);
Because the table is not enabled, no cell or row can ever be selected, and so the selected row will always be -1. Solution: get rid of that line. Instead, if you don't want a cell to be editable on double click, override the JTable or its model and override the isCellEditable method:
e.g.,
// create your JTable model here:
DefaultTableModel model = ......
JTable tablePatientDt = new JTable(model){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
Other issues: don't add the JTable to more than one component as you're doing. That spells great risk for trouble since Swing components can be added to only one component at a time.
A side recommendation: in your future questions post only small compilable and runnable programs. Your code above cannot run since it has database dependencies that we don't have access to, and is also incomplete. In order to find your problem, I had to take your code and create a small runnable program with it, an mcve (please read the link):
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLException;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class CardLayoutExample {
private static JScrollPane scrollPane;
public static void main(String[] arguments) throws SQLException {
// main window
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame window = new JFrame("CardLayout Example");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// !! window.setSize(1500, 800);
window.getContentPane().setLayout(new BorderLayout());
final CardLayout cardLayout = new CardLayout();
final JPanel cardPanel = new JPanel(cardLayout);
JPanel card3 = new JPanel();
cardPanel.add(card3, "All Patients");
String AllPatients = "select * from tblPtDetails";
//!!
String[][] data = {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}};
String[] columnNames = {"One", "Two", "Three"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
// !! JTable tablePatientDt = new JTable(Bquery.buildTableModel(Bquery.resultQuery(AllPatients)));
JTable tablePatientDt = new JTable(model){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
// !! tablePatientDt.setEnabled(false);
tablePatientDt.setPreferredScrollableViewportSize(new Dimension(1200, 400));
tablePatientDt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tablePatientDt.setRowHeight(30);
tablePatientDt.setAutoCreateRowSorter(true);
// !! card3.add(tablePatientDt);
card3.add(new JScrollPane(tablePatientDt), BorderLayout.CENTER);
for (int i = 0; i < (tablePatientDt.getColumnCount()); i++) {
TableColumn columnPatients = null;
columnPatients = tablePatientDt.getColumnModel().getColumn(i);
columnPatients.setPreferredWidth(70); // sport column is bigger
}
tablePatientDt.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int row = tablePatientDt.getSelectedRow();
int column = tablePatientDt.getSelectedColumn();
// Object val= tablePatientDt.getModel().getValueAt(row,
// column);
// tablePatientDt.getModel().getValueAt(row, column);
// return tablePatientDt.getModel().getValueAt(row, column);
System.out.println(row);
JFrame newFrame = new JFrame();
newFrame.setTitle("Detail Screen");
newFrame.setVisible(true);
}
}
});
//!!
window.add(cardPanel);
window.pack();
window.setVisible(true);
}
}
But really this effort should be yours not mine, since we're all volunteers, and you're the one asking for volunteer help in solving a problem. So in the future we ask that you create your own mcve to go with your questions.
Also that detail window shouldn't be a JFrame but rather a JDialog.
I need to remove the rows that are selected after a button is pressed.
That's is my code: I have a column that is a checkbox, then a check if it is checked and add the corresponding line to the list.
DefaultTableModel model = (DefaultTableModel) jTableLayouts.getModel();
// gets the number of rows that were selected
Public ArrayList<Integer> selectedLines = new ArrayList<Integer>();
for (int j = 0; j <= jTableLayouts.getModel().getRowCount(); j++) {
if ((Boolean) jTableLayouts.getModel().getValueAt(j,2)){ //checkbox
selectedLines.add(jTableLayouts.getSelectedRow());
}
model.removeRow(selectedLines.get(j));
}
With this code I can remove one by one. Any ideas how I can remove all the lines after a press the button?
EDIT: I only need to remove the rows that are marked as true in the checkbox. Example: the rows 0,1,4,5 are marked as true, after that I will add these lines in a list, and then just remove the lines that are on the list at same time after the button is pressed.
As #MadProgrammer already commented, you can do this from a button by having the ActionListener perform the deletes and add the deleted rows to the list you want.
In this snippet when pressing the button, the checked rows on the left are deleted and added to the table on the right. Check the createDeleteButton method for how this is done.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class TestTableDeleteRows extends JPanel {
private JTable tblLeft;
private JTable tblRight;
public TestTableDeleteRows() {
initialize();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
private void initialize() {
setLayout(new BorderLayout());
add(createHeaderPane(),BorderLayout.NORTH);
add(createTablePane(),BorderLayout.CENTER);
add(createDeleteButton(),BorderLayout.SOUTH);
}
private JPanel createHeaderPane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS));
p.add(new JScrollPane(new JLabel("Source",SwingConstants.CENTER)));
p.add(new JScrollPane(new JLabel("Deleted",SwingConstants.CENTER)));
return p;
}
private JPanel createTablePane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
tblLeft = createTable(stdRows);
tblRight = createTable(new Vector<Vector<Object>>());
p.add(new JScrollPane(tblLeft));
p.add(new JScrollPane(tblRight));
return p;
}
private static final int COL_CHECK=0;
private static final int COL_TEXT=1;
private static final Vector<Vector<Object>> stdRows;
private static final Vector<Object> cols;
static {
stdRows = new Vector<Vector<Object>>();
for(int i=0;i!=100;++i)
stdRows.add(new Vector<Object>(Arrays.asList(new Object[]{Boolean.FALSE,"This is text line number "+(i+1)})));
cols = new Vector<>(Arrays.asList(new Object[]{"Check me","Silly text"}));
}
private static JTable createTable(Vector<Vector<Object>> rows) {
JTable t = new JTable(rows,cols) {
#Override
public Class<?> getColumnClass(int column) {
if(getRowCount()>0)
return getValueAt(0, column).getClass();
return super.getColumnClass(column);
}
};
t.getColumnModel().getColumn(COL_CHECK).setPreferredWidth(50);
t.getColumnModel().getColumn(COL_TEXT).setPreferredWidth(200);
return t;
}
private JButton createDeleteButton() {
JButton b = new JButton("Delete checked rows");
b.addActionListener(new ActionListener() {
#SuppressWarnings("unchecked")
#Override
public void actionPerformed(ActionEvent e) {
Vector<Vector<Object>> removedRows = new Vector<>();
DefaultTableModel modelLeft = (DefaultTableModel) tblLeft.getModel();
for(int r=0;r!=modelLeft.getRowCount();++r)
if((Boolean) modelLeft.getValueAt(r,COL_CHECK)) {
removedRows.add((Vector<Object>) modelLeft.getDataVector().get(r));
modelLeft.removeRow(r--);
}
DefaultTableModel modelRight = (DefaultTableModel) tblRight.getModel();
for(Vector<Object> row : removedRows)
modelRight.addRow(row);
}
});
return b;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Delete checked rows in JTable from button");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new TestTableDeleteRows());
f.pack();
f.setVisible(true);
}
});
}
}
Result:
I have text fields and a JTable on a Frame. When user clicks on the JTable row or moves key up and down, textfields filled up with these selected row values so that user can update the row. So the problem is when I select the row and then pressed the delete button the table refreshes but the textfields still show the deleted row values.So at this moment I dont want to reset the fields. I want to show the row values which comes before the deleted row in the text field
For example there are two rows
id name
1 hello
2 bello
user selected the row which has ID 2 and delete it. now the values on the textfield should be hello not bellow
You can use a ListSelectionListener on your JTable which sets the text of the JTextField elements based on the current selection in your JTable. When the delete button is pressed, you can have the ActionListener remove the selected row from the JTable and force the next selection in the model via setRowSelectionInterval. Below is a simple example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.*;
public class JTableDelete extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTable table;
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JTableDelete frame = new JTableDelete();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public JTableDelete() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
table = new JTable();
table.setModel(new DefaultTableModel(new Object[][] { { "Red" }, { "Green" }, { "Blue" }, { "Violet" }, { "Orange" }, },
new String[] { "Colors" }));
ListSelectionModel cellSelectionModel = table.getSelectionModel();
cellSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
int selectedRow = table.getSelectedRow();
int selectedColumn = table.getSelectedColumn();
if (selectedRow != -1 && selectedColumn != -1)
textField.setText((String) table.getValueAt(selectedRow, selectedColumn));
else
textField.setText("");
}
});
contentPane.add(table, BorderLayout.CENTER);
JButton btnDelete = new JButton("Delete");
btnDelete.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
int rowCount = table.getRowCount() - 1; // -1 because counting starts at 0
if (row != -1) {
((DefaultTableModel) table.getModel()).removeRow(row);
rowCount--; // 1 less row now
if (row < table.getRowCount()) // next selection
table.setRowSelectionInterval(row, row);
else if (rowCount != -1) // end selection
table.setRowSelectionInterval(rowCount, rowCount);
}
}
});
contentPane.add(btnDelete, BorderLayout.SOUTH);
textField = new JTextField();
textField.setEnabled(false);
contentPane.add(textField, BorderLayout.NORTH);
textField.setColumns(10);
pack();
}
}
In the example, I'm seeking to add a table to my GUI and then dynamically add rows to it (to show the progress). What I don't understand is why all the rows are appearing at once. I mean, the the table's changing, isn't it? Can someone please give me an explanation?
import java.awt.Component;
public class Main {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
GUI gui = new GUI();
gui.setVisible(true);
DefaultTableModel model = new DefaultTableModel(
new String[] { "Column 1", "Column 2" }, 0);
JTable table = new JTable(model);
gui.add(table);
gui.validate();
for (int i = 0; i < 10; i++) {
System.out.println("Row " + i);
model
.addRow(new String[] { "Row", String.valueOf(i) });
// model.fireTableDataChanged();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 100);
setLocationRelativeTo(null);
JPanel cp = new JPanel();
cp.setBorder(new EmptyBorder(10, 10, 10, 10));
setContentPane(cp);
}
}
Reiterating Kleopatra : Don't Sleep the EDT
You can instead use a javax.swing.Timer as seen in this answer
EDIT
I didn't want to mess with your code too much (just because it looks weird to me) but I changed it somewhat to add the Timer
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class Main {
static JTable table;
static GUI gui;
static Processor p = null;
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
gui = new GUI();
p = new Processor() {
#Override
public void execute() {
final JTable table = new JTable(p.getTableModel());
final JScrollPane scrollPane = new JScrollPane(table);
gui.getContentPane().add(scrollPane, BorderLayout.CENTER);
gui.setLocationRelativeTo(null);
gui.setVisible(true);
Timer timer = new Timer(100, new ActionListener(){
public void actionPerformed(ActionEvent e) {
p.processRow();
table.scrollRectToVisible(table.getCellRect(table.getRowCount() - 1, 0, true));
}
});
timer.start();
}
};
p.execute();
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 400);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
interface Callback {
void execute();
}
abstract class Processor implements Callback {
private final String[] cols = {"COL", "COL", "COL", "COL", "COL"};
private DefaultTableModel tableModel;
int numRows;
int numCols;
int a, b, c, d, e;
Processor() {
a = 1; b = 2; c = 3; d = 4; e = 4;
numRows = 1000;
tableModel = new DefaultTableModel(cols, numCols);
}
public DefaultTableModel getTableModel() {
return tableModel;
}
public void processRow() {
tableModel.addRow(new Object[]{a, b, c, d, e});
a++; b++; c++; d++; e++;
}
}
As pointed out by kleopatra and peeskillet, my initial example suffered from a stupid mistake. It's worth noting that peeskillet and I were following different approaches, though. In my example, the columns meant to represent connection attempts (more or less) that can take an unknown amount of time and that can actually fail (in that case, and only in that case, the next column would come into play and so on). Therefore, it wouldn't have made sense for me to add the rows at once (which was probably what made my example look weird to peeskillet). I've solved the task using a SwingWorker. As pointed out by kleopatra, there was a another mistake, which is now fixed. Here's my code:
package SwingWorkerExampleCopy;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;
public class SwingWorkerExampleCopy {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
GUI gui = new GUI();
DefaultTableModel tableModel = new DefaultTableModel();
// Use a SwingWorker
Worker worker = new Worker(tableModel);
worker.execute();
JTable table = new JTable(tableModel);
table.setEnabled(false);
// table.setTableHeader(null);
JScrollPane scrollPane = new JScrollPane(table);
gui.getContentPane()
.add(scrollPane, BorderLayout.CENTER);
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 400);
setLocationRelativeTo(null);
setVisible(true);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
class Worker extends SwingWorker<DefaultTableModel, Object[]> {
private final static int numRows = 10;
private final static int numCols = 10;
private DefaultTableModel model;
Worker(DefaultTableModel model) {
this.model = model;
model.setColumnCount(numCols);
}
#Override
protected DefaultTableModel doInBackground() throws Exception {
// Add row
for (int row = 0; row < numRows; row++) {
// Build columns
for (int col = 0; col < numCols; col++) {
if (col == 0) {
publish(new Object[] { new String("Row " + row), row,
col });
} else {
// Simulate a slow source
Thread
.sleep(new Random().nextInt((250 - 50) + 1) + 50);
Boolean isSuccessful = false;
// Simulate a return value
if (new Random().nextBoolean()) {
isSuccessful = true;
}
publish(new Object[] {
new String((isSuccessful == true ? "x" : "o")), row,
col });
if (isSuccessful == true) {
break;
}
}
}
}
return model;
}
#Override
protected void process(List<Object[]> chunks) {
for (Object[] chunk : chunks) {
// chunk[0]: cell value
// chunk[1]: number
// chunk[2]: column
if ((int) chunk[2] == 0) {
Object[] row = new Object[numCols];
row[0] = (Object) chunk[0];
model.addRow(row);
} else {
model.setValueAt((Object) chunk[0], (int) chunk[1],
(int) chunk[2]);
}
}
}
}
Because while your code is running, no other events (such as repaint events) can execute - you're blocking the event thread until you're done.
You may be able to call repaint directly, but the UI will still be unresponsive to input while your code is running. You'd be better off running the loop in a separate worker thread, and using invokeLater or invokeAndWait to perform the updates to the UI when needed.
I created the following example source and am wondering what I need to do to update my JPanel with a JLabel that has the information located from the row clicked in the JTable.
I also wanted to note that this is just a bare example as I've improved the sample code quite a bit thanks to a few SO members here. So I'm posting this bare example as a way to learn
SwingTesting (main)
public class SwingTesting {
private final JFrame frame;
private final TablePane tablePane;
private final JSplitPane splitPane;
private final JPanel infoPanel;
private final JLabel infoLabel;
public SwingTesting() {
tablePane = new TablePane();
infoPanel = new JPanel();
frame = new JFrame();
infoLabel = new JLabel(); //this is the panel i want to add the label to
infoPanel.add(infoLabel);
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tablePane, infoPanel);
frame.add(splitPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SwingTesting();
}
});
}
}
TablePane
public class TablePane extends JPanel {
private final JTable table;
private final TableModel tableModel;
private final ListSelectionModel listSelectionModel;
public TablePane() {
table = new JTable();
tableModel = createTableModel();
table.setModel(tableModel);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table.add(table.getTableHeader(), BorderLayout.PAGE_START);
table.setFillsViewportHeight(true);
listSelectionModel = table.getSelectionModel();
table.setSelectionModel(listSelectionModel);
listSelectionModel.addListSelectionListener(new SharedListSelectionHandler());
table.setSelectionModel(listSelectionModel);
this.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.gridwidth = 3;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.ipadx = 2;
gbc.ipady = 2;
gbc.weightx = 1;
gbc.weighty = 1;
this.add(new JScrollPane(table), gbc);
}
private TableModel createTableModel() {
DefaultTableModel model = new DefaultTableModel(
new Object[] {"Car", "Color", "Year"}, 0
){
#Override public boolean isCellEditable(int row, int column) {
return false;
}
};
addTableData(model);
return model;
}
private void addTableData(DefaultTableModel model) {
model.addRow(new Object[] {"Nissan", "Black", "2007"});
model.addRow(new Object[] {"Toyota", "Blue", "2012"});
model.addRow(new Object[] {"Chevrolet", "Red", "2009"});
model.addRow(new Object[] {"Scion", "Silver", "2005"});
model.addRow(new Object[] {"Cadilac", "Grey", "2001"});
}
class SharedListSelectionHandler implements ListSelectionListener {
//When selection changes i want to add a label to the panel
//currently it just prints out the info from the selected row
#Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
String contents = "";
if(lsm.isSelectionEmpty()) {
System.out.println("<none>");
} else {
int minIndex = lsm.getMinSelectionIndex();
int maxIndex = lsm.getMaxSelectionIndex();
for(int i = minIndex; i <= maxIndex; i++) {
if(lsm.isSelectedIndex(i)) {
for(int j = 0; j < table.getColumnCount(); j++) {
contents += table.getValueAt(i, j) + " ";
}
}
}
System.out.println(contents);
}
}
}
}
So I'm wondering how to access that JPanel from the ListSelectionListener. Should I just pass the panel to the TablePane class? Or is there a more proper way to do this?
Also, my ListSelectionListener prints out the row information twice for some reason, did I mess up the loop?
EDIT
public class TablePane extends JPanel {
private final JTable table;
private final TableModel tableModel;
private final ListSelectionModel listSelectionModel;
private final displayPanel;
public TablePane() {
//removed code for reading purposes
}
//IDE says issue with thinking displayPanel may have already been initialized
public TablePane(JPanel panel) {
//this();
//displayPanel = panel;
}
//ListSelectionListener uses panel.add(jlabel)
}
Is it as simple as taking final off?
You can pass the JLabel object to the TablePane object (in TablePane's constructor or by providing a custom setLabel() method). Then you can use StringBuilder to create the text that needs to go on the label, and call setText() on the label with the constent of the StringBuilder object (via its toString() method).
I believe you are printing everytihn twice because the valueChanged method is called twice: once on the notification for the deselection of the current row, then again on the notification on the selection of the new row.