Как вставить новую строку в JTable, используя пользовательскую модель таблицы?

Я работаю над небольшим проектом, который включает JTable, который требует от пользователя нажатия кнопки и добавления строки в таблицу (я назвал кнопку addrow). Я использовал пользовательскую модель таблицы (Mytablemodel), которая расширяет модель таблицы по умолчанию. Моя таблица сначала состоит из пяти строк и 4 столбцов, после чего пользователь может нажать кнопку addrow, чтобы добавить больше строк.

Все в моем коде работает нормально, кроме кнопки addrow, которая ничего не делает. Я буду признателен за любую помощь.

public class AddingNewRows extends JFrame {
JTable mytable;
JButton addrow;
String[] columns={"Admission number","Name","School","Year"};
TableColumn tc;
int defaultrows=5;
int rows=new Mytablemodel().getRowCount(),columnscount=new Mytablemodel().getColumnCount();
List data=new ArrayList();
Mytablemodel mytbm;
//
public AddingNewRows(){
super("adding rows");
for(int initialrows=0; initialrows<5; initialrows++){
   String[] items={"1","2","3","4"};
 data.add(items);
}
mytbm=new Mytablemodel();
mytable=new JTable(mytbm);

JScrollPane scroll=new JScrollPane(mytable);
addrow=new JButton("ADD ROW");
//
JPanel buttonpanel=new JPanel();
buttonpanel.setLayout(new BoxLayout(buttonpanel,BoxLayout.X_AXIS));
buttonpanel.setAlignmentX(Component.RIGHT_ALIGNMENT);
buttonpanel.add(addrow);

//
add(scroll,BorderLayout.CENTER);
add(buttonpanel,BorderLayout.SOUTH);

addrow.addActionListener(new Myactions());

}
public class Mytablemodel extends DefaultTableModel{

@Override
public String getColumnName(int column) {
    return columns[column];
}
@Override
public Object getValueAt(int row, int col){
 return ((String[])data.get(row))[col]; 
}
@Override
public boolean isCellEditable(int row, int col){
  return true;
}
@Override
public void setValueAt(Object value,int row, int col){
  ((Object[])data.get(row))[col]=value;
  fireTableCellUpdated(row,col);

}
@Override
public Class getColumnClass(int column){
  return getValueAt(0,column).getClass();
}  
@Override
public int getColumnCount(){
  return columns.length;
}

@Override
public int getRowCount(){
  return increaserows; 
}

@Override
public void addRow(Object[] mynewdata){
  int rownum=data.size();
  System.out.println(rownum);
  data.add(madata);
fireTableRowsInserted(rownum,rownum);
}

}
//
private class Myactions implements ActionListener{

@Override
public void actionPerformed(ActionEvent event){
 if(event.getSource()==addrow){ 
   Object[]newdata={"","","",""};
    mytbm.addRow(newdata);  
 } 
} 
}
public static void main(String[] args) {

 AddingNewRows frame=new AddingNewRows();
 frame.setVisible(true);
    frame.setSize(400,400);
    frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);

}

}

person Edijae Crusar    schedule 06.01.2015    source источник
comment
Слова, набранные строчными буквами, трудно читать, как будто пытаешься слушать, что кто-то бормочет. Пожалуйста, используйте заглавную букву в начале предложения, для слова I и имен собственных, таких как ArrayList или Oracle.   -  person Andrew Thompson    schedule 06.01.2015
comment
Mytablemodel extends AbstractTableModel{ Сделайте себе одолжение и вместо этого продлите DefaultTableModel. Он делает такие вещи для вас. Но для более быстрой помощи опубликуйте MCVE (минимальный полный проверяемый пример) или SSCCE (краткий, автономный, правильный пример).   -  person Andrew Thompson    schedule 06.01.2015
comment
@AndrewThompson все данные, введенные в таблицу, позже сохраняются в базе данных с помощью другой кнопки, и это работает нормально. вот почему я использовал пользовательскую модель таблицы, так как я не думаю, что смогу использовать DefaultTableModel для сохранения данных в базе данных. кроме того, у меня возникли проблемы с пониманием метода fireTableRowsInserted(int,int). сами параметры и где или когда вызывать метод   -  person Edijae Crusar    schedule 06.01.2015
comment
Хорошо, опубликуйте MCVE.. Жестко закодируйте некоторые данные для замены БД.   -  person Andrew Thompson    schedule 06.01.2015
comment
@ Эндрю Томпсон. я думал, что мой код уже MCVE. кроме того, как вы можете видеть, все мои строки содержат пустые строки, поскольку цикл for заполняет массив объектов пустыми строками. поэтому они действуют как данные, которые заменяют БД   -  person Edijae Crusar    schedule 06.01.2015
comment
Я думал, что мой код уже MCVE. Вы ошиблись. Он не полный, поэтому его нельзя компилировать, не говоря уже о запуске. Таким образом, это также не поддающийся проверке пример. Таким образом, MCVE соответствует только первому критерию.   -  person Andrew Thompson    schedule 06.01.2015
comment
@gikarasojokinene «Я не думаю, что смогу использовать DefaultTableModel для сохранения данных в базе данных». Почему вы так думаете? Модель просто хранит данные. В вашей модели нет специального кода для базы данных. Все, что есть у вашей модели, это метод getValueAt(...), который также можно найти в ЛЮБОЙ TableModel. `У МЕНЯ ПРОБЛЕМЫ ПОНИМАНИЯ метода fireTableRowsInserted(int,int)`, а DefaultTableModel уже делает это за вас, поэтому вам не нужно ничего делать. Таким образом, снова нет необходимости создавать пользовательскую TableModel на основе функциональности вашей текущей модели.   -  person camickr    schedule 06.01.2015
comment
@camickr я обновил свой вопрос и использовал DefaultTableModel, но моя кнопка добавления ничего не делает. пожалуйста, посмотрите мой отредактированный вопрос и скажите мне, где я ошибаюсь   -  person Edijae Crusar    schedule 08.01.2015
comment
@AndrewThompson Я воспользовался вашим советом и расширил DefaultTableModel, но моя кнопка добавления ничего не делает при нажатии. посмотри мой отредактированный вопрос и скажи мне, где я не прав   -  person Edijae Crusar    schedule 08.01.2015
comment
Этот код здесь не скомпилируется. Пожалуйста, ознакомьтесь с тем, что такое MCVE/SSCCE.   -  person Andrew Thompson    schedule 08.01.2015
comment
Вам не хватает смысла использовать DefaultTableModel. Он уже реализует метод addRow(...). Вам не нужно создавать свои собственные. Он также реализует такие методы, как getColumnNames(), getValueAt(), setValueAt() и т. д., поэтому нет необходимости реализовывать эти методы. Просто используйте функциональность по умолчанию и переопределите метод только в том случае, если вам нужно изменить поведение по умолчанию.   -  person camickr    schedule 08.01.2015
comment
@AndrewThompson, наконец, я понял. смотри мой ответ ниже   -  person Edijae Crusar    schedule 09.01.2015
comment
@camickr последовал твоему совету и все сделал правильно. смотри мой ответ ниже   -  person Edijae Crusar    schedule 09.01.2015


Ответы (2)


Некоторые примечания о вашем коде:

  • Вы никогда не должны вызывать какой-либо из методов fireXxx() явно извне. Они предназначены для внутреннего вызова AbstractTableModel подклассами, когда это необходимо. Примечание: ИМХО, это должны быть protected, а не public, чтобы избежать их неправильного использования. Но почему-то их обнародовали.

  • Ваша кнопка addrow, похоже, создает новую модель таблицы, которая не привязана ни к какому JTable, поэтому в этом нет смысла. Ваша табличная модель должна предоставлять метод addRow(...) для добавления в нее новой строки. Скорее всего, вам придется увеличивать двумерный массив, который является базовой структурой данных табличной модели, каждый раз, когда добавляется строка.

  • Как уже предложил @AndrewThompson, DefaultTableModel кажется, хорошо подходит для того, что делает ваша модель таблицы.

  • Проверьте инициализацию свойств rows и columnscount. Мне это кажется неправильным.

С другой стороны, вы говорите в комментарии:

У меня проблемы с пониманием метода fireTableRowsInserted(int,int). сами параметры и где или когда вызывать метод

Этот метод следует вызывать внутри addRow(...), который я предложил вам создать во втором пункте. Этот метод должен увеличить структуру данных и уведомить TableModelListeners о вставке новых строк. Параметрами являются первый и последний индексы соответственно. Как правило, когда вы добавляете новую одиночную строку в конец модели таблицы, тогда и первый, и последний индексы совпадают, а новый размер — 1 базовой структуры данных. Конечно, можно вставить несколько строк и не обязательно в конец модели таблицы, так что вам придется придумать соответствующие индексы. См. пример, показанный здесь, в котором в качестве структуры данных используется List пользовательских объектов.

person dic19    schedule 06.01.2015
comment
19 когда вы говорите о первом и последнем индексах, что именно вы имеете в виду? например, у меня есть 5 строк, когда я хочу добавить 6-ю строку, я скажу fireTableRowsUpdated(6,6)? - person Edijae Crusar; 06.01.2015
comment
В этом случае вы должны вызвать fireTableRowsInserted(5,5), потому что индексы в Java начинают отсчет с 0 (индекс 5 - это 6-я строка). Примечание. Я уведомил строки вставлены (не обновлены), потому что вы действительно хотите добавить новую строку. @gikarasojokinene - person dic19; 06.01.2015
comment
поэтому первый индекс обозначает вставляемую строку, а второй индекс представляет столбцы, которые должны быть в строке. я прав? - person Edijae Crusar; 06.01.2015
comment
Нет, оба индекса представляют собой первую и последнюю строки соответственно (вы можете добавить более одной строки). Например, допустим, у вас есть 5 строк, и вы добавляете 3 строки. Предполагая, что вы добавляете все новые строки в конец структуры данных, вам нужно вызвать fireTableRowsInserted(5, 7), потому что первая добавленная строка будет 6-й (индекс == 5), а последняя - 8-й (индекс == 7). Всегда читайте API для получения более подробной информации. @gikarasojokinene - person dic19; 06.01.2015
comment
это один момент правильно. не обращайте внимания на инициализацию свойств rows и columnscount. я не использую их для указания методов getColumnCount и getRowCount() - person Edijae Crusar; 06.01.2015
comment
я обновил свой вопрос и использовал DefaultTableModel, но моя кнопка addrow ничего не делает. пожалуйста, посмотрите мой отредактированный вопрос и скажите мне, где я ошибаюсь - person Edijae Crusar; 08.01.2015
comment
я наконец понял. смотри мой ответ ниже - person Edijae Crusar; 09.01.2015

Согласно вашему вопросу, вы хотите добавлять новые строки каждый раз, когда пользователь нажимает кнопку addrow. Достигните своей цели, используя DefaultTableModel без создания собственного или переопределения метода addrow. в моем примере ниже параметры в конструкторе DefaultTableModel представляют начальные строки (5) и столбцы (4), которые будут иметь таблица, где после выполнения пользователь может добавить больше строк, нажав кнопку addrow.

public class AddingNewRows extends JFrame {
 DefaultTableModel def;
JTable mytable;
JButton addrow;
//
public AddingNewRows(){
super("adding rows");

def=new DefaultTableModel(5,4);
mytable=new JTable(def);

JScrollPane scroll=new JScrollPane(mytable);
addrow=new JButton("ADD ROW");
//
JPanel buttonpanel=new JPanel();
buttonpanel.setLayout(new BoxLayout(buttonpanel,BoxLayout.X_AXIS));
buttonpanel.add(addrow);

//
add(scroll,BorderLayout.CENTER);
add(buttonpanel,BorderLayout.SOUTH);

addrow.addActionListener(new Myactions());

}

private class Myactions implements ActionListener{

@Override
public void actionPerformed(ActionEvent event){
if(event.getSource()==addrow){ 
Object[]newdata={"","","",""};
def.addRow(newdata);
} 
} 
}
public static void main(String[] args) {
AddingNewRows frame=new AddingNewRows();
frame.setVisible(true);
frame.setSize(400,400);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);

}

}
person Edijae Crusar    schedule 09.01.2015