|
Java форум JavaTalks форум программистов
|
|
|
|
| Предыдущая тема :: Следующая тема |
| Автор |
Сообщение |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 11:33 |
|
|
Моя проблемма заключается в следующем: не могу прикрутить TableModelListener ни к модели, ни к таблице, которая эту модель использует. Вообще никуда не могу прикрутить т.к. куда б не ставил модель не реагирует на слушателя.
В программе из базы вынимаются все значения таблиц и из них получается модель таблицы.Далее эта модель представляется как JTable и добавляется в JTabbedPane.
Так вот, вопрос к знатокам: Как мне правильно сделать так, чтобы таблицы с данными начали реагировать на их изменение ? Помогите пожалуйста, я новенький и уже 3-й день бьюсь с этим...
Код класса, создающего саму таблицу:
| Код: |
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Properties;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
class TableCreater
{
public static JTable table;
static private Connection conn;
public static JTable TableCreateMethod (String query)
{
try
{
conn = getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
AbstractTableCreater model = new AbstractTableCreater();
model.setDataSource(rs);
table = new JTable(model);
table.setAutoCreateRowSorter(true);
conn.close();
}
catch (IOException e)
{e.printStackTrace();}
catch (SQLException ex)
{
for (Throwable t : ex)
t.printStackTrace();
}
catch (ClassNotFoundException e)
{e.printStackTrace();}
return table;
}
public static Connection getConnection() throws SQLException, IOException
{
Properties props = new Properties();
FileInputStream in = new FileInputStream("database.properties");
props.load(in);
in.close();
String drivers = props.getProperty("jdbc.drivers");
if (drivers != null) System.setProperty("jdbc.drivers", drivers);
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
return DriverManager.getConnection(url, username, password);
}
}
class AbstractTableCreater extends AbstractTableModel
{
private ArrayList<String> columnNames = new ArrayList<String>();
private ArrayList<Class> columnTypes = new ArrayList<Class>();
private ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>();
public int getRowCount() {
synchronized (data) {
return data.size();
}
}
public int getColumnCount() {
return columnNames.size();
}
public Object getValueAt(int row, int col) {
synchronized (data) {
return data.get(row).get(col);
}
}
public String getColumnName(int col) {
return columnNames.get(col);
}
public Class getColumnClass(int col) {
return columnTypes.get(col);
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object obj, int row, int col) {
synchronized (data) {
data.get(row).set(col, obj);
}
}
/**
* Core of the model. Initializes column names, types, data from ResultSet.
*
* @param rs ResultSet from which all information for model is token.
* @throws SQLException
* @throws ClassNotFoundException
*/
public void setDataSource(ResultSet rs) throws SQLException, ClassNotFoundException
{
ResultSetMetaData rsmd = rs.getMetaData();
columnNames.clear();
columnTypes.clear();
data.clear();
int columnCount = rsmd.getColumnCount();
for (int i = 0; i < columnCount; i++) {
columnNames.add(rsmd.getColumnName(i + 1));
Class type = Class.forName(rsmd.getColumnClassName(i + 1));
columnTypes.add(type);
}
fireTableStructureChanged();
while (rs.next()) {
ArrayList rowData = new ArrayList();
for (int i = 0; i < columnCount; i++) {
if (columnTypes.get(i) == String.class)
rowData.add(rs.getString(i + 1));
else
rowData.add(rs.getObject(i + 1));
}
synchronized (data) {
data.add(rowData);
this.fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
}
}
}
|
Код главной формы:
| Код: |
import java.awt.EventQueue;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class MainGUIClass {
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run ()
{
JFrame frame = new ProgramMainFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class ProgramMainFrame extends JFrame
{
private static final int DEFAULT_WIDTH = 800;
private static final int DEFAULT_HEIGHT = 600;
private JTabbedPane tabbedPane;
public static JTable table;
static private Connection conn;
public ProgramMainFrame()
{
setTitle("11Учет деталей [version 1.1]");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
try
{UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");}
catch (Exception e) {e.printStackTrace();}
tabbedPane = new JTabbedPane();
add(tabbedPane, "Center");
// we set the components to null and delay their loading until the tab is shown
// for the first time
tabbedPane.addTab("Микросхемы", null);
tabbedPane.addTab("Транзисторы", null);
tabbedPane.addTab("Все детали", null);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
tabbedPane.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent event)
{
// check if this tab still has a null component
if (tabbedPane.getSelectedComponent() == null)
{
// set the component to the image icon
int n = tabbedPane.getSelectedIndex();
loadTab(n);
}
}
});
loadTab(0);
}
/**
Загружает вкладку когда на нее переходят.
@param n индекс загружаемой вкладки
*/
private void loadTab(int n)
{
if (n==0)
{
JTable tabPan1 = TableCreater.TableCreateMethod("select * from MICROCHIPS");
tabbedPane.setComponentAt(n, new JScrollPane(tabPan1));
}
if (n==1)
{
JTable tabPan2 = TableCreater.TableCreateMethod("select * from TRANSISTORS");
tabbedPane.setComponentAt(n, new JScrollPane(tabPan2));
}
if (n==2)
{
JTable tabPan3 = TableCreater.TableCreateMethod("SELECT * FROM MICROCHIPS union SELECT * FROM TRANSISTORS");
tabbedPane.setComponentAt(n, new JScrollPane(tabPan3));
}
}
public static Connection getConnection() throws SQLException, IOException
{
Properties props = new Properties();
FileInputStream in = new FileInputStream("database.properties");
props.load(in);
in.close();
String drivers = props.getProperty("jdbc.drivers");
if (drivers != null) System.setProperty("jdbc.drivers", drivers);
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
return DriverManager.getConnection(url, username, password);
}
}
|
, null
Последний раз редактировалось: ДимончеГ (Янв 29, 2012 11:31), всего редактировалось 1 раз |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 13:49 |
|
|
| ДимончеГ писал(а): |
Моя проблемма заключается в следующем: не могу прикрутить TableModelListener ни к модели, ни к таблице, которая эту модель использует. Вообще никуда не могу прикрутить т.к. куда б не ставил модель не реагирует на слушателя.
В программе из базы вынимаются все значения таблиц и из них получается модель таблицы.Далее эта модель представляется как JTable и добавляется в JTabbedPane.
Так вот, вопрос к знатокам: Как мне правильно сделать так, чтобы таблицы с данными начали реагировать на их изменение ? Помогите пожалуйста, я новенький и уже 3-й день бьюсь с этим... |
1. Зачем класс TableCreater наследуется от JTable?
2. Покажите, где именно и как вы добавляли слушатель модели. _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 15:42 |
|
|
Я посчитал, что так нужно, вы правы, можно и без него. Я только начинаю писать реальный продукт, поэтому простите за такие ляпы.
Я и вот так делал:
| Код: |
public static JTable TableCreateMethod (String query)
{
try
{
conn = getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
AbstractTableCreater model = new AbstractTableCreater();
model.setDataSource(rs);
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent arg0)
{
System.out.println("--------------------------");
}
});
table = new JTable(model);
table.setAutoCreateRowSorter(true);
conn.close();
}
catch (IOException e)
{e.printStackTrace();}
catch (SQLException ex)
{
for (Throwable t : ex)
t.printStackTrace();
}
catch (ClassNotFoundException e)
{e.printStackTrace();}
return table;
} |
и добавлял имплемент в начало класса TableCreater и потом писал как в примере работы с "Listening for Data Changes" на сайте оракла
| Код: |
| table.getModel().addTableModelListener(this); |
и в классе ProgramMainFrame то же самое делал (в начале класса имплиментил и добавлял непосредственно к таблице)
| Код: |
class ProgramMainFrame extends JFrame implements TableModelListener
{
//----
public void tableChanged(TableModelEvent e)
{
System.out.println ("хоть что нибудь выведи");
}
public ProgramMainFrame()
{
// к примеру тут так
JTable tabPan1 = TableCreater.TableCreateMethod("select * from MICROCHIPS");
tabPan1.getModel().addTableModelListener(this);
//...
}
|
и добавлял к самому JTable в конструкторе. Вобщем везьде и по всякому пытался вставить.
Последний раз редактировалось: ДимончеГ (Янв 28, 2012 16:30), всего редактировалось 2 раз(а) |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 15:46 |
|
|
| и в самом классе расширяющем AbstractTableModel имплиментил интерфейс со слушателем и даже создавал отдельный класс слушатель... ничего не выходит у меня, в лучшем случае выводится таблица, но никаких слушателей она не видит, а в худших случаях даже таблица переставала выводиться... |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 16:06 |
|
|
| ДимончеГ писал(а): |
Я посчитал, что так нужно, вы правы, можно и без него. Я только начинаю писать реальный продукт, поэтому простите за такие ляпы.
Я и вот так делал:
| Код: |
public CopyOfTableCreaterSec (String query)
{
try
{
conn = getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
model = new AbstractTableCreaterSec();
model.setDataSource(rs);
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent arg0)
{
System.out.println("--------------------------");
}
});
table = new JTable();
table.setModel(model);
table.setAutoCreateRowSorter(true);
conn.close();
}
catch (IOException e)
{e.printStackTrace();}
catch (SQLException ex)
{
for (Throwable t : ex)
t.printStackTrace();
}
catch (ClassNotFoundException e)
{e.printStackTrace();}
} |
и добавлял имплемент в начало класса TableCreater и потом писал как в примере работы с "Listening for Data Changes" на сайте оракла
| Код: |
| table.getModel().addTableModelListener(this); |
и в классе ProgramMainFramet то же самое делал (в начале класса имплиментил и добавлял непосредственно к таблице)
| Код: |
class ProgramMainFramet extends JFrame implements TableModelListener
{
//----
public void tableChanged(TableModelEvent e)
{
System.out.println ("хоть что нибудь выведи");
}
public ProgramMainFramet()
{
// к примеру тут так
tabPan1 = new CopyOfTableCreaterSec("select * from MICROCHIPS");
add(new JScrollPane(tabPan1));
tabPan1.getModel().addTableModelListener(this);
}
|
и добавлял к самому JTable в конструкторе
| Код: |
public ProgramMainFramet()
{
tabPan1 = new CopyOfTableCreaterSec("select * from MICROCHIPS");
add(new JScrollPane(tabPan1));
tabPan1.getModel().addTableModelListener(new TableModelListener()
{
public void tableChanged(TableModelEvent e)
{
System.out.println ("хоть что нибудь выведи");
}
});
|
вобщем везьде и по всякому пытался вставить. |
| ДимончеГ писал(а): |
| и в самом классе расширяющем AbstractTableModel имплиментил интерфейс со слушателем и даже создавал отдельный класс слушатель... ничего не выходит у меня, в лучшем случае выводится таблица, но никаких слушателей она не видит, а в худших случаях даже таблица переставала выводиться... |
Я ничего не понял. Что это за класс "CopyOfTableCreaterSec"? В первых примерах кода его не было. Почему вы показываете одни классы, а спрашиваете про другие? _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 16:32 |
|
|
| Прошу прощения, я в начале показал код чистой версии без слушателей, а потом примеры подключения слушателя начал кидать из другой версии программы. Вот вроде исправил всё в том сообщении. |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 16:56 |
|
|
| ДимончеГ писал(а): |
| Код: |
public static JTable TableCreateMethod (String query)
{
try
{
<...>
model.setDataSource(rs);
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent arg0)
{
System.out.println("--------------------------");
}
});
<...>
}
<...>
} |
|
Попробуйте поменять местами: сперва добавляйте слушателя, а потом ДатаСорс. Есть шанс, что ваша таблица просто ничего не делала, поэтому вы и не получали никаких событий. _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 17:19 |
|
|
Вот сделал вот так :
| Код: |
static int a = 0;
public static JTable TableCreateMethod (String query)
{
try
{
//...
AbstractTableCreater model = new AbstractTableCreater();
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent arg0)
{
System.out.println(a++);
}
});
model.setDataSource(rs);
table = new JTable(model);
table.setAutoCreateRowSorter(true);
conn.close();
//...
} |
после запуска программы, в консоле выводится список событий, каждый из которых отображает количество занесения записи в model.
У меня в ResultSet находится 2764 записи и такое же число вывелось последним. А после после попыток изменения содержимого ячейки никаких событий не происходит. |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 17:37 |
|
|
| ДимончеГ писал(а): |
Вот сделал вот так :
| Код: |
static int a = 0;
public static JTable TableCreateMethod (String query)
{
try
{
//...
AbstractTableCreater model = new AbstractTableCreater();
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent arg0)
{
System.out.println(a++);
}
});
model.setDataSource(rs);
table = new JTable(model);
table.setAutoCreateRowSorter(true);
conn.close();
//...
} |
после запуска программы, в консоле выводится список событий, каждый из которых отображает количество занесения записи в model.
У меня в ResultSet находится 2764 записи и такое же число вывелось последним. А после после попыток изменения содержимого ячейки никаких событий не происходит. |
Вы чего хотите добиться? Узнать, когда кто-то что-то руками в таблицу написал? Так слушатель модели тут совершенно ни при чём. В модели таблицы есть метод "public void setValueAt(Object aValue, int rowIndex, int columnIndex)", переопределяйте его.
UPD: Попробуйте запустить во этот код и поредактировать ячейки:
| Код: |
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Test {
public static void main(String[] args) {
JTable table = new JTable(new DefaultTableModel() {
@Override
public int getColumnCount() {
return 3;
}
@Override
public int getRowCount() {
return 3;
}
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
@Override
public void setValueAt(Object aValue, int row, int column) {
System.out.println(row + " x " + column + ": " + aValue);
}
});
JOptionPane.showMessageDialog(null, new JScrollPane(table));
}
} |
_________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 17:51 |
|
|
Я хочу сделать обновление данных в базе если ктото изменяет значение ячейки. Разве для этого не нужен слушатель ? Я же исспользовал setValueAt(Object obj, int row, int col) вот так в модели:
| Код: |
public void setValueAt(Object obj, int row, int col) {
synchronized (data) {
data.get(row).set(col, obj);
}
}
|
как он может реагировать на изменение ячеек ? |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 18:06 |
|
|
| ДимончеГ писал(а): |
| Я хочу сделать обновление данных в базе если ктото изменяет значение ячейки. Разве для этого не нужен слушатель ? |
Нет.
| ДимончеГ писал(а): |
Я же исспользовал setValueAt(Object obj, int row, int col) вот так в модели:
| Код: |
public void setValueAt(Object obj, int row, int col) {
synchronized (data) {
data.get(row).set(col, obj);
}
}
|
|
Ну так у вас значения ячеек остаются изменёнными после окончания редактирования?
| ДимончеГ писал(а): |
| как он может реагировать на изменение ячеек ? |
Вот так и может. Так же, как таблица у модели спрашивает, можно ячейку редактировать или нет. _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 18:52 |
|
|
Спасибо огромное. Действительно помогло, но пожалуйста объясните как оно работает и почему не стоило применять TableModelListener ?
И еще скажите пожалуйста как отловить изменённую ячейку чтобы потом получить её значение и запросом обновить базу ? |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 19:21 |
|
|
| ДимончеГ писал(а): |
| Спасибо огромное. Действительно помогло, но пожалуйста объясните как оно работает и почему не стоило применять TableModelListener ? |
Потому что через TableModelListener'ы модель оповещает всех интересующихся об изменениях. Но когда вы руками печатаете что-нибудь в ячейке таблицы - модель не меняется, меняется сама таблица; и она оповещает об этом свою модель, с помощью метода "setValueAt". А дальше модель думает, что делать с новыми данными - измениться и оповестить всех, или забить и ничего не делать.
С помощью листенеров, например, сама таблица слушает модель, чтобы узнать, когда ей нужно перерисовать себя. Вот если вы посторонними способами (не через внешнее представление таблицы) изменили модель, добавили строки, или удалили их, или изменили их содержимое, то вам нужно чтобы модель оповестила всех об этом. Для этого можно использовать методы "fire***" из класса AbstractTableModel. Вы это делаете, но только очень по варварски. Не думаю что стоит сообщать о каждой вставленной строке, особенно если у вас их больше 2K. Вы вставьте все строки, а потом уже жгите событие. Или вставляйте в отдельном потоке и жгите событие каждые 10-20 строк. Но точно не после каждой.
| ДимончеГ писал(а): |
| И еще скажите пожалуйста как отловить изменённую ячейку чтобы потом получить её значение и запросом обновить базу ? |
Ну так, ёшки матрёшки, вероятно методом "setValueAt", не? _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
ДимончеГ : 18 Новичок
|
Янв 28, 2012 19:40 |
|
|
я понял что вы имеете ввиду, но мне не нужно сообщать об обновлении талбицы. Мне нужно было лишь узнать как как можно отловить изменение таблицы руками и я очень вам благодарен за помощь.
А второй вопрос заключался в том, как мне именно получить значение в ячейке после её изменения для того чтобы через setValueAt обновить базу? (я уже попробовал тот код что вы предложили и понял что отлавливать действие с таблицей нужно с помощью setValueAt ) |
|
|
|
 |
Vantuz-Subhuman : 660 Постоянный посетитель Откуда: издиснейленда
|
Янв 28, 2012 20:29 |
|
|
| ДимончеГ писал(а): |
| я понял что вы имеете ввиду, но мне не нужно сообщать об обновлении талбицы. |
1. Это вам пока не нужно. А когда станет нужно, опять пойдёте спрашивать? Поэтому слушайте и мотайте.
2. Что ж вы тогда сообщаете, раз вам не нужно? В методе "setDataSource". _________________ «One should never underestimate the predictability of stupidity»,
«Never attribute to malice that which can be adequately explained by stupidity» |
|
|
|
 |
|
|
Страница 1 из 2 На страницу 1, 2 След. |
Список форумов
-> Swing, AWT & SWT |
|
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете голосовать в опросах
|
|