Обычная версия
Java форум JavaTalks
форум программистов

Поиск   Пользователи   Группы   Регистрация 
 Профиль   Личные сообщения 

 Вход 

Помогите пожалуйста с TableModelListener
Список форумов
 ->  Swing, AWT & SWT


На страницу 1, 2  След. 
Начать новую тему 
Предыдущая тема :: Следующая тема  
Автор Сообщение
ДимончеГ : 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


 
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Java and all Java-related trademarks and logos are trademarks or registered trademarks of Oracle Corporation in the United States and other countries.
Это сайт не относится к фирме Oracle Corporation и не поддерживается ею.

© 2006-2010 www.javatalks.ru: форум java программистов
Используется скрипт phpBB © 2001, 2010 phpBB Group

Хостинг от bizname.ru