JTable - usuwanie wierszy

0

Napisałem program, który umożliwia dodanie wiersza w tabeli lub usunięcie wybranych. Ale pojawiają się 2 problemy. Dodaję 4 wiersze. Zaznaczam 2, 3 i 4 - klikam "Delete" i usuwa - ale kiedy próbuję zaznaczyć pozostały 1 wiersz wybija exception. Poza tym - tworząc np. 4 wiersze - w każdym wpisuję kolejno 1, 2, 3, 4 w JComboBoxie (w JTextFieldzie też tak działa) - i zaznaczam wiersz 2, usuwam i teraz w miejscu, w którym przed chwilą był wiersz nr 2 powinien być wiersz o nr 3. Ale pozostaje 2 - mimo, że to nie ten wiersz, bo w JTextFieldzie wartość się zmieniła - pod warunkiem, że nie jest właśnie zaznaczony. ALE ! - klikając na nagłówek tabeli (a nazwami kolumn) - 2ka zmienia się już prawidłowo na 3. Mimo to, kiedy próbuje po usunięciu zakodować utratę focusa (2 zakomentowane linie) to już się na 3 nie zmienia i zostaje 2ka, która powinna być usunięta. Ale kiedy kliknie się nie na nagłówek tabeli, ale np. na inną komórkę, to 2-ka też nie zamienia się w 3. O co chodzi ?


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

class TableDialog extends JDialog
{
	private static final long serialVersionUID = 1L;
	private DefaultTableModel model;
	private JComboBox combo = null;
	private JPanel buttons = null;
	private JPanel panel = null;
	private JScrollPane scroll = null;
	private JTable table = null;
	private JTextField cell = null;

	private TableDialog(JFrame owner, String title)
	{
		super(owner, title, false);
		
		setContentPane(getPanel());
		pack();
		
		setResizable(false);
		setVisible(true);
	}
	
	private JPanel getPanel()
	{
		if(panel == null)
		{
			panel = new JPanel(new BorderLayout());
			panel.add(getTable(0), BorderLayout.NORTH);
			panel.add(getButtons(), BorderLayout.SOUTH);
		}
		
		return panel;
	}
	
	private JScrollPane getTable(int rowcount)
	{
		if(scroll == null)
		{
			model = new DefaultTableModel(new String[]{"COL1", "COL2"}, rowcount);
			table = new JTable(model);
			table.setRowSelectionAllowed(true);
			
			cell = new JTextField("0");
			cell.setBorder(new LineBorder(Color.black));
			
			combo = new JComboBox(new Object[]{"ELEMENT"});
			combo.setEditable(true);
			
			TableColumnModel columnModel = table.getColumnModel();
			TableColumn col = null;
			
			DefaultCellEditor cellEditor = new DefaultCellEditor(combo);
			cellEditor.setClickCountToStart(0);
			col = columnModel.getColumn(0);
			col.setCellEditor(cellEditor);
			
			cellEditor = new DefaultCellEditor(cell);
			cellEditor.setClickCountToStart(0);
			columnModel.getColumn(0).setPreferredWidth(20);
			col = columnModel.getColumn(1);
			col.setCellEditor(cellEditor);
			
			scroll = new JScrollPane(table);
			scroll.setPreferredSize(new Dimension(300, 100));
		}
		
		return scroll;
	}
	
	private JPanel getButtons()
	{
		if(buttons == null)
		{
			JButton add = new JButton("Add");
			add.setFont(new Font(add.getFont().getFontName(), Font.BOLD, add.getFont().getSize()));
			add.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					addRow();
				}
			});
			
			JButton delete = new JButton("Delete");
			delete.setFont(new Font(delete.getFont().getFontName(), Font.BOLD, delete.getFont().getSize()));
			delete.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					removeSelectedRows();
				}
			});
			
			buttons = new JPanel(new GridLayout());
			buttons.add(add);
			buttons.add(delete);
		}
		
		return buttons;
	}
	
	private void addRow()
	{
		Object[] newRow = new Object[model.getColumnCount()];
		
		for(int col = 0; col < model.getColumnCount(); col++)
			newRow[col] = "";
		
		model.addRow(newRow);
	}
	
	private void removeSelectedRows()
	{
		int[] selectedRows = table.getSelectedRows();
		
		for(int i = 0; i < selectedRows.length ; i++) 
			model.removeRow(table.getSelectedRow());
		
//		variablesTable.clearSelection();
//		variablesTable.getCellEditor().stopCellEditing();
	}
	
	public static void showTablePane(JFrame owner, String title)
	{
		new TableDialog(owner, title);
	}
}

public class Table extends JFrame
{
	private static final long serialVersionUID = 1L;

	public static void main(String[] args)
	{
		TableDialog.showTablePane(null, "Window");
	}
}

0

Przy usuwaniu przetwarzaj indeksy od końca. Każde usunięcie wiersza powoduje zmianę indeksów wierszy po nim.

int[] selectedRows = table.getSelectedRows();

//nie da się posortować int[] odwrotnie, dlatego nalezy przekopiowac do Integer[]	
Integer[] rows = new Integer[selectedRows.length];
for (int i = 0; i < selectedRows.length; i++) {
	rows[i] = selectedRows[i];
}

// sortowanie odwrotne
Arrays.sort(rows,  new Comparator<Integer>(){
	public int compare(Integer i1, Integer i2) {
		return i2 - i1;
	}});
   
for(int i = 0; i < rows.length ; i++)
	model.removeRow(rows[i]);
0

Próbowałeś to w ogóle testować ? :]

Nie ma znaczenia kolejność, bo nie podaję indeksów, które zapamiętałem wcześniej, tylko te, które na bieżąco sczytuję z każdego napotkanego selectedRowa (indeksowanie przez table.getSelectedRow())

for(int i = 0; i < selectedRows.length ; i++)
                        model.removeRow(table.getSelectedRow());

A poza tym usuwa poprawnie, ale nie pozwala potem zaznaczyć wiersza, który nie został usunięty (bo nie miał być).

Nie za bardzo rozumiem też komentarz

//nie da się posortować int[] odwrotnie, dlatego nalezy przekopiowac do Integer[]

Przykład sprzeczny :):

int[] selectedRows = table.getSelectedRows();
int[] sortedRows = new int[selectedRows.length];
		
for(int j = 0; j < sortedRows.length; j++)
	sortedRows[j] = selectedRows[sortedRows.length - j - 1];

Tak, czy inaczej przetestowałem twój kod i to niczego nie zmienia.

0

ta funkcja powinna wyglądać tak:

private void removeSelectedRows() {
	table.editingStopped(null);
	while (table.getSelectedRowCount() > 0) {
		model.removeRow(table.getSelectedRow());
	}
}

jak chcesz dynamicznie sprawdzać zaznaczone wiersze.
najważniejsze jednak jest to:

table.editingStopped(null);

aby kończyło edycje przed próbą usunięcia

0

table.editingStopped(null);

HA ! O to właśnie chodziło. Nie o table.getCellEditor().stopCellEditing(). Dzięki. Z tym whilem też prawda, bo po co przeszukiwać do końca, skoro nie ma już zaznaczonych wierszy.

0
Czort napisał(a)
int[] selectedRows = table.getSelectedRows();
int[] sortedRows = new int[selectedRows.length];
		
for(int j = 0; j < sortedRows.length; j++)
	sortedRows[j] = selectedRows[sortedRows.length - j - 1];

Tak, czy inaczej przetestowałem twój kod i to niczego nie zmienia.

Ale czy w dokumentacji jest cokolwiek na temat kolejności?
Ja niczego takiego nie widzę.
getSelectedRows() może więc zwrócić np. {5,1,3}, a powinieneś usuwać tak: 5,3,1.

Ale rzeczywiście powinno być ok jeżeli za każdym razem wykonujesz getSelectedRow(). Zmyliło mnie getSelectedRows() na początku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1