Особенности работы с представлением данных и манипуляциями со столбцами в объекте JTable
Данная задача решалась при разработке матрицы планирования эксперимента (МПЭ), которая яв-ляется основным объектом системы исследования свойств порошковых материалов с помощью сим-плекс планов. Вся идеология системы основана на теории планирования эксперимента и математиче-ской статистики. Исходя и этого, МПЭ имеет ряд свойств и методов. В частности она состоит из обяза-тельной части и не обязательной. В обязательную часть входит рис.1:
- номер опыта;
- относительные (Z1…Z3) и абсолютные (X1,X2,X3) концентрации компонентов смеси;
- значение функции отклика (Y1) в соответствующих точка, которые получены в результате про-ведения эксперимента;
- значение коэффициентов полинома, которые получаются расчетным путем в зависимости от выбранной модели (b1,b2…,g12,g13….).
Рисунок 1МПЭ - обязательная часть
Отсутствие любого компонента обязательной части ведет к потери функциональности МПЭ. На основании данных представленных в МПЭ строятся контурные кривые отклика на симплекс - диаграм-ме. Однако на практике наличие одного отклика не всегда позволяет в полной мере выполнить анализ тех или иных свойств смесей. Самый простой выход – создание аналогичной МПЭ, с теми же концен-трациями, но для другого отклика. Под откликом в данном контексте понимаются некоторые исследуе-мые электрофизические и прочностные характеристики смеси. Однако как показывает тестирование разрабатываемой системы при планировании эксперимента, данный подход не удобен для практическо-го использования. Кроме того, при данном подходе не рационально используются ресурсы ЭВМ, так как создание подобных объектов требует дополнительного выделения памяти. В свою очередь наличие од-ного отклика в МПЭ затрудняет анализ полученных данных, используя критерий Харрингтона (функция желательности). Поэтому возникла задача создать возможность добавления и соответственно удаления в МПЭ дополнительных откликов, а также анализа полученных данных с помощью критерия Харрингто-на.
Следовательно, добавляемые отклики и критерий Харрингтона, можно отнести к необязательной части МПЭ, так как их отсутствие не сказывается на функциональных возможностях МПЭ, а присутст-вие только расширяет их.
Разобьем данную задачу на два этапа, первый этап связан с созданием МПЭ и добавлением столб-цов в нее, а второй соответственно удалением столбцов из нее.
Добавление столбцов
Сам объект МПЭ отображается на экране посредством объекта JinternalFrame в который занесен объект JscrolPane с собственно таблицей, объект JTable. Вопросы создания указанных объектов являют-ся довольно тривиальными, более интересным, с точки зрения дальнейшего использования является способ "наполнения" и создания объекта JTable, так как он в данном случае является основным.
Код создания объекта выглядит следующим образом:
…………………………
Vector col = new Vector();
col.addElement("№ опыта");
col.addElement("Координаты");
col.addElement("Z1");
col.addElement("Z2");
col.addElement("Z3");
col.addElement("X1");
col.addElement("X2");
col.addElement("X3");
col.addElement("Отклик-Y1");
col.addElement("Знач.-Y1");
col.addElement("Коэф.-Y1");
col.addElement("Знач.Коэф.-Y1");
dtm = new DefaultTableModel(col,0){
public boolean isCellEditable(int row, int column) {
return true;}
};
jt = new JTable(dtm);
jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
jsp = new JScrollPane(jt);
………………………………..
Что из этого кода следует? Во – первых, для хранения данных используется DefaultTableModel, столбцы заносятся в модель данных с помощью вектора. Мною был рассмотрен вариант создания таб-лицы, используя, конструктор JTable(TableModel, TableColumnModel). Фрагмент кода альтернативного создания, используя модель столбцов:
…………………
dtcm = new DefaultTableColumnModel();
TableColumn tc1 = new TableColumn();
tc1.setHeaderValue("№ опыта");
tc1.setWidth(20);
dtcm.addColumn(tc1);
TableColumn tc2 = new TableColumn();
tc2.setHeaderValue("Коордтинаты");
tc2.setWidth(20);
dtcm.addColumn(tc2);
……………
А для модели данных в этом случае используется конструктор :
dtm = new DefaultTableModel(){};
В этом случае, как видно, код создания столбца увеличивается с одной строчки до четырех, по умолчанию создается модель данных с 0-ым количеством столбцов и строк.
Также особое внимание необходимо уделить именованию столбцов, так как в дальнейшем это бу-дет важным фактором при манипуляциях с ними. Для удобства, я принял решение, что название столб-ца характеризующего отклик должно состоять из двух частей, это связано с тем, что, по сути, при до-бавлении отклика в таблицу добавляется четыре столбца: обозначение отклика, значение отклика; ко-эффициенты полинома для данного отклика; значение коэффициентов полинома. Поэтому старшая часть названия должна указывать на тип столбца (Отклик, Знач., Коэф. ЗначКоэф.), а младшая индекс отклика (Y1,Y2….Yn). Поэтому в классе МПЭ создается переменная – индекс и методы setIdx() и getIdx() для работы с ней. Кроме того, в таблицу еще необходимо добавлять два столбца, которые буду отвечать за критерий Харрингтона, особенность их добавления заключается в том, что они добавляются, когда МПЭ имеет один отклик, и при последующих добавлениях откликов, должны располагаться после всех столбцов.
Фрагмент кода, метода добавления столбцов представлен ниже, в зависимости от количества столбцов в таблице, в нее добавляются или 6-ть столбцов, в которые входит наряду с параметрами от-клика еще и функция желательности.
int IDx = arPlanCreate.getIdx();
IDx++;
if (dtm.ColumnCount()= =12) {
dtm.addColumn("Отклик-Y"+ IDx);
dtm.addColumn("Знач.-Y"+ IDx);
dtm.addColumn("Коэф.-Y"+ IDx);
dtm.addColumn("Знач.Коэф-Y"+ IDx);
dtm.addColumn("Желательность");
dtm.addColumn("Знач.Жел.");
feelOt(12);
arPlanCreate.revalidate();
arPlanCreate.repaint();
}
Или 4-е столбца, но в этом случае необходимо обеспечить размещение столбцов характеризующих функцию желательности в самом конце. Дело в том, что как только столбец добавлен в модель данных, он сразу получает свой порядковый номер, и если предыдущие столбцы не удалялись, то этот номер ос-тается неизменным, следовательно, порядок вывода на экран может не совпадать с порядком следова-ния столбцов в модели данных. Поэтому для изменения порядка следования столбцов на экране, кото-рый не совпадает с моделью данных таблицы, используется метод setChangeColumn():
else{
int colCol = dtm.getColumnCount();
dtm.addColumn("Отклик-Y"+ IDx);
dtm.addColumn("Знач.-Y"+ IDx);
dtm.addColumn("Коэф.-Y"+ IDx);
dtm.addColumn("Знач.Коэф-Y"+ IDx);
feelOt(colCol++);
int newCol = dtm.getColumnCount();
setChangeColumn();
arPlanCreate.revalidate();
arPlanCreate.repaint();
}
arPlanCreate.setIdx(IDx);
Метод feelOt() позволяет заполнять соответствующие столбцы обозначением отклика и коэффици-ентов.
private void setChangeColumn(){
tcm = arPlanCreate.jt.getColumnModel();
for(int i = 0; i < dtm.getColumnCount();i++){
TableColumn tc = tcm.getColumn(i);
if(tc.getHeaderValue().toString().indexOf("Жел")>-1; ){
tcm.moveColumn(i,dtm.getColumnCount()-1);
tcm.moveColumn(i,dtm.getColumnCount()-1);
break;
}
}
}
Удаление столбцов
При удалении столбцов необходимо проверить три условия. Первое условие связано с проверкой выделения столбца и не представляет большого интереса. Второе условие проверя-ет общее количество столбцов в МПЭ, так как, было написано выше, она в результате удаления может потерять свое функциональное назначение. Особенность удаления заключается в том, что столбцы, ха-рактеризующие критерий Харрингтона, должны удалятся в последнюю очередь и в МПЭ необходимо оставить набор столбцов хотя бы одного отклика. Поэтому массивы объектов для формирования векто-ра данных должны иметь на шесть столбцов меньше. Кроме того, в связи с тем, что порядок следования столбцов в модели данных и столбцов различен, необходимо сопоставить имена столбцов в модели столбцов с их номерами в модели данных. Код представлен ниже.
if(arPlanCreate.jt.getColumnCount()==18 ){
col=0;
// Инициализация массива объектов с учетом удаления шести столбцов
Object [] colNamD =new Object [tcm.getColumnCount()-6];
Object [][] rowDatD = new Object [dtm.getRowCount()][tcm.getColumnCount()-6];
// Определение индекса отклика
int c = arPlanCreate.jt.getSelectedColumn() ;
tc = (TableColumn)tcm.getColumn(c);
nam =tc.getHeaderValue().toString();
if(nam.indexOf("Y")>-1;){
for(int i = 0; i<nam.length;(); i++){
if('Y'==(nam.charAt(i))){
nam = nam.substring(i);
break;
}
}
// Выявление столбцов с соответствующим индексом и "желательностью"
for (int i = 0;i<tcm.getColumnCount;();i++){
tc=tcm.getColumn(i);
if (((tc.getHeaderValue().toString()).indexOf(nam)==(-1))&&
((tc.getHeaderValue().toString()).indexOf("Жел")==(-1))){
//сопоставление имени столбца в модели столбцов с именем в модели данных и формирование
//новых массивов для модели данных
for(int k =0; k < dtm.getColumnCount();k++){
if((tc.getHeaderValue().toString()) == dtm.getColumnName(k)){
for (int j = 0; j < dtm.getRowCount();j++){
colNamD[col] = dtm.getColumnName(k);
rowDatD[j][col]=dtm.getValueAt(j,k);
}
col++;
}
}
}
}
}
// переопределение вектора данных для модели данных таблицы
dtm.setDataVector(rowDatD,colNamD);
arPlanCreate.revalidate();
arPlanCreate.repaint();
}
Аналогичным образом происходит удаление одного отклика. Разница заключается в размере мас-сива для модели данных, и в том, что после удаления необходимо методом setChangeColumn(); перемес-тить в модели столбцов критерий желательности в самый конец.
int c = arPlanCreate.jt.getSelectedColumn() ;
Object [] colNam =new Object [tcm.getColumnCount()-4];
Object [][] rowDat = new Object [dtm.getRowCount()][tcm.getColumnCount()-4];
TableColumnModel tcm = arPlanCreate.jt.getColumnModel();
tc = (TableColumn)tcm.getColumn(c);
nam =tc.getHeaderValue().toString();
if(nam.indexOf("Y")>-1;){
for(int i = 0; i<nam.length;(); i++){
if('Y'==(nam.charAt(i))){
nam = nam.substring(i);
break;
}
}
col= 0;
for(int i=0; i < tcm.getColumnCount();i++){
tc = tcm.getColumn(i);
if((tc.getHeaderValue().toString()).indexOf(nam)==(-1)){
for(int k =0; k < dtm.getColumnCount();k++){
if((tc.getHeaderValue().toString()) == dtm.getColumnName(k)){
for (int j = 0; j < dtm.getRowCount();j++){
colNam[col] = dtm.getColumnName(k);
rowDat[j][col]=dtm.getValueAt(j,k);
}
col++;
}
}
}
}
dtm.setDataVector(rowDat,colNam);
setChangeColumn();
Рисунок 2 МПЭ - после манипуляций со столбцами
Выводы
- Все манипуляции со столбцами, имеются в виду, вопросы, связанные с их удалением и пе-ремещением необходимо решать, используя модель данных конкретной таблицы. Так как в противном случае, может возникнуть несогласованность данных, связанная с разным по-рядком следования столбцов в модели столбцов и модели данных.
- Для изменения отображения столбцов на экране (удаления и перемещения) удобнее всего пользоваться моделью столбцов таблицы объект TableColumnModel. Но в этом случае не коим образом нельзя манипулировать данными самой таблицы. Так как в этом случае, даже если применить метод объекта TableColumnModel - removeColumn(), столбец не удаляется из модели данных, а просто не выводится на экран.
Окончил технологический факультет ДГТУ (1993).
доцент кафедры «Информатика» ДГТУ,
кандидат технических наук (1996).
ДГТУ г.Ростов-на-Дону
Январь 2005г.