2015-09-26 3 views
1

Пожалуйста, сначала посмотрите на изображение: это не нормально, что появляются пять последних строк. Это когда я щелкнул по серой пустой области, в которой они появились.JTable: непредвиденное поведение при нажатии последнего элемента

Я создал программу, в которой перечислены продукты.

При запуске программы JTable отображает всю базу данных, а затем я позволяю пользователю выбирать то, что он хочет видеть.

Здесь, например, я выбрал все продукты, сделанные в «Carrefour», и в списке всего 7 элементов. Он отображается нормально.

Но когда я перехожу в серой области под последним элементом, JTable имеет неожиданное поведение на изображении ниже (он показывает другую дату базы данных, как если бы вся база данных отображалась, как при запуске) , То же самое происходит, когда я изменяю размер кадра или пытаюсь настроить разные столбцы.

Я сделал свое исследование и не могу найти решение этой проблемы.

ПЕРЕД НАЖИМАЯ

JTableBeforeClicking

ПОСЛЕ НАЖИМАЯ

JTable Problem

Вот часть кода о создании JTable:

private void tableCreation(String query) { 
    // Random database queries I don't display for the sake of clarity 

     excel = new JTable(rowData, columnNames); 
     excel.setAutoCreateRowSorter(true); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    tablePanel.removeAll(); 
    this.getContentPane().add(new JScrollPane(tablePanel.add(excel)), BorderLayout.CENTER); 
    this.revalidate(); 
} 

А вот часть кода относительно исследования и, следовательно, модифицирование в JTable:

class SearchListener implements ActionListener{ 
    @Override 
    public void actionPerformed(ActionEvent e) { 

    // Random query construction with the e.getText() method 

    if (!column.equals("prix") && !column.equals("num_id")){ 
      query = "select * from products where " + column + " like '%" + searchText.getText().toUpperCase().trim() + "%'"; 
     }else{ 
      query = "select * from products where " + column + " = '" + searchText.getText().toUpperCase().trim() + "'"; 
     } 

    }else{ 
     query = "select * from products"; 
    } 
     tableCreation(query); 
    } 
} 

EDIT 1:

Я пытался поставить JTable непосредственно на JPanel без использования JScrollPane, это не сработало.

Я также пытался не отображать всю базу данных при запуске программы, но когда я делаю первый запрос, проблема такая же. Он либо отображает серые строки, либо отображает данные из последнего запроса, когда я нажимаю случайную строку.

Я знаю, что проблема не связана с запросом, который я использую, потому что нужные данные отображаются правильно.

Я действительно потерялся и не мог себе представить, откуда это могло произойти.

Для справки: Я использую JFrame с разными JPanel на нем. На одном из них я добавил JScrollPane, на котором я разместил свой JTable.

EDIT 2:

я разместил весь код here для тех, кто хочет, чтобы детали. Он содержится только в одном классе, поэтому его легко читать.


Всего код:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.GridBagConstraints; 
import java.awt.GridLayout; 
import java.awt.Toolkit; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.sql.ResultSet; 
import java.sql.ResultSetMetaData; 
import java.sql.SQLException; 
import java.sql.Statement; 

import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JSplitPane; 
import javax.swing.JTable; 
import javax.swing.JTextField; 


public class FrameFC extends JFrame{ 

    public static void main(String[] args) { 
     FrameFC fr = new FrameFC(); 
    } 

    /*Main Frame Creation*/ 

    private JSplitPane split; 
    private Font f = new Font("Arial", Font.PLAIN, 15); 
    private JScrollPane scroll = new JScrollPane(); 

    /*Panel Creation*/ 
    private JPanel mainPanel = new JPanel(); 

    private JPanel westPanel = new JPanel(); 
    private JPanel eastPanel = new JPanel(); 

    private JPanel addPanel = new JPanel(); 
    private JPanel searchPanel = new JPanel(); 
    private JPanel removePanel = new JPanel(); 

    private int screenHeight = (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight()); 
    private int screenWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()); 

    private JButton buttonAdd = new JButton("Ajouter"), 
        buttonSearch = new JButton("Rechercher"), 
        buttonRemove = new JButton("Supprimer"); 

    private JTextField nomP = new JTextField(), 
         cat = new JTextField(), 
         mag = new JTextField(), 
         prix = new JTextField(), 
         dateAchat = new JTextField(), 
         codemag = new JTextField(), 
         removeText = new JTextField(); 

    private JTextField searchText = new JTextField(); 

    private String[] tabCat = {"ID", "Nom Produit", "Categorie", "Magasin", "Prix", "Date (JJ/MM/AAAA)", "Code Magasin"}; 

    private JComboBox combo = new JComboBox(tabCat); 

    /*Table Creation*/ 
    private JPanel tablePanel = new JPanel(); 
    private JTable excel = new JTable(); 
    private String query = "select * from products order by num_id"; 

    public FrameFC(){ 
     this.setTitle("Gestionnaire de produits"); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setExtendedState(JFrame.MAXIMIZED_BOTH); 
     this.setLayout(new BorderLayout()); 

     panelCreation(); 
     tableCreation(query); 

     this.setVisible(true); 
    } 

    class AjouterListener implements ActionListener{ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      // TODO Auto-generated method stub 
      if (nomP.getText().equals("") || 
        cat.getText().equals("") || 
        mag.getText().equals("") || 
        prix.getText().equals("") || 
        dateAchat.getText().equals("")){ 

      }else{ 
       String nomps, cats, mags, prixs, dates; 
       nomps = nomP.getText(); 
       cats = cat.getText(); 
       mags = mag.getText(); 
       prixs = prix.getText(); 
       dates = dateAchat.getText(); 

       query = "insert into products " 
         + "(nom_produit, cat, mag, prix, date_achat, code_magasin)" 
         + " values (" 
         + "'" + nomps + "', '" + cats 
         + "', '" + mags + "', " + prixs 
         + ", '" + dates + "', '" + codemag.getText() + "');"; 

       Statement state; 
       ResultSet res; 
       try { 
        state = ConnectPostGRESql.getInstance("postgres").createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); 
        res = state.executeQuery(query); 
       } catch (SQLException e1) { 
        System.out.println(nomps + " ajouté avec succès."); 
       } 

       query = "select * from products"; 
       tableCreation(query); 
       nomP.setText(""); 
       cat.setText(""); 
       prix.setText(""); 

      } 
     } 
    } 

    class SearchListener implements ActionListener{ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      // TODO Auto-generated method stub 
      String column; 

      if (!searchText.getText().equals("")){ 

      switch (String.valueOf(combo.getSelectedItem())) 
      { 
      case "ID": 
       column = "num_id"; 
       break; 
      case "Nom Produit": 
       column = "nom_produit"; 
       break; 
      case "Categorie": 
       column = "cat"; 
       break; 
      case "Magasin": 
       column = "mag"; 
       break; 
      case "Prix": 
       column = "prix"; 
       break; 
      case "Code Magasin": 
       column = "code_magasin"; 
       break; 
      default: 
       column = "date_achat"; 
       break; 
      } 
      if (!column.equals("prix") && !column.equals("num_id")){ 
       query = "select * from products where " + column + " like '%" + searchText.getText().toUpperCase().trim() + "%'"; 
      }else{ 
       query = "select * from products where " + column + " = '" + searchText.getText().toUpperCase().trim() + "'"; 
      } 

     }else{ 
      query = "select * from products"; 
     } 
      tableCreation(query); 
     } 
    } 

    class RemoveListener implements ActionListener{ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      // TODO Auto-generated method stub 
      if (!removeText.getText().equals("")){ 
       Statement state; 
       ResultSet res; 
       try { 
        state = ConnectPostGRESql.getInstance("postgres").createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); 
        res = state.executeQuery("delete from products where num_id = " + removeText.getText()); 
       } catch (SQLException e1) { 
        System.out.println("Entrée supprimée avec succès."); 
       } 
      } 
      tableCreation("select * from products"); 

     } 
    } 

    private void tableCreation(String query) { 
     // TODO Auto-generated method stub 
     try { 
      Statement state = ConnectPostGRESql.getInstance("postgres").createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); 
      ResultSet res = state.executeQuery(query); 

      ResultSetMetaData meta = res.getMetaData(); 

      Object[] columnNames = new Object[meta.getColumnCount()]; 

      for (int i = 1; i<=meta.getColumnCount();i++){ 
       columnNames[i-1] = meta.getColumnName(i); 
      } 

      res.last(); 

      Object[][] rowData = new Object[res.getRow()][meta.getColumnCount()]; 

      res.beforeFirst(); 

      int j = 1; 

      while (res.next()){ 
       for (int i = 1; i <= meta.getColumnCount(); i++){ 
        if (i == 1){ 
         int nombredez = 4 - String.valueOf(res.getInt(i)).length(); 
         String nombredezString = ""; 
         for (int n = 0; n < nombredez;n++){ 
          nombredezString += "0"; 
         } 
         rowData[j-1][i-1] = nombredezString + String.valueOf(res.getObject(i)); 
        } 
        else{ 
         rowData[j-1][i-1] = res.getObject(i); 
        } 
       } 
       j++; 
      } 

      res.close(); 
      state.close(); 

      excel = new JTable(rowData, columnNames); 
      excel.setAutoCreateRowSorter(true); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     tablePanel.removeAll(); 
     this.getContentPane().add(new JScrollPane(tablePanel.add(excel)), BorderLayout.CENTER); 
     this.revalidate(); 
    } 

    private void panelCreation() { 
     // TODO Auto-generated method stub 

     /*Panel Add (West)*/ 
     addPanel.setLayout(new GridLayout(7,2)); 

     addPanel.add(new JLabel("Entrez le nom du produit :")); 
     addPanel.add(nomP); 
     addPanel.add(new JLabel("Entrez la catégorie :")); 
     addPanel.add(cat); 
     addPanel.add(new JLabel("Entrez le magasin :")); 
     addPanel.add(mag); 
     addPanel.add(new JLabel("Entrez le prix :")); 
     addPanel.add(prix); 
     addPanel.add(new JLabel("Entrez la date :")); 
     addPanel.add(dateAchat); 
     addPanel.add(new JLabel("Entrez le code magasin")); 
     addPanel.add(codemag); 
     addPanel.add(new JLabel()); 

     buttonAdd.addActionListener(new AjouterListener()); 
     addPanel.add(buttonAdd); 

     addPanel.setBorder(BorderFactory.createTitledBorder("Ajouter")); 
     addPanel.setPreferredSize(new Dimension(949, 360)); 

     /*Panel Search (North-East)*/ 
     searchPanel.setLayout(new GridLayout(2,2)); 

     searchPanel.add(combo); 
     searchPanel.add(searchText); 
     searchPanel.add(new JLabel()); 

     buttonSearch.addActionListener(new SearchListener()); 
     searchPanel.add(buttonSearch); 

     searchPanel.setBorder(BorderFactory.createTitledBorder("Rechercher")); 
     searchPanel.setPreferredSize(new Dimension(949, 180)); 

     /*Panel Remove (South-East)*/ 
     removePanel.setLayout(new GridLayout(2,2)); 

     removePanel.add(new JLabel("Entrez le numero d'identifiant : ")); 
     removePanel.add(removeText); 
     removePanel.add(new JLabel()); 

     buttonRemove.addActionListener(new RemoveListener()); 
     removePanel.add(buttonRemove); 

     removePanel.setBorder(BorderFactory.createTitledBorder("Supprimer")); 
     removePanel.setPreferredSize(new Dimension(949, 180)); 

     /*MainPanel on Frame*/ 
     westPanel.setBorder(BorderFactory.createLineBorder(Color.black, 2)); 
     westPanel.add(addPanel); 

     eastPanel.setLayout(new BorderLayout()); 
     eastPanel.setBorder(BorderFactory.createLineBorder(Color.black, 2)); 

     eastPanel.add(searchPanel, BorderLayout.NORTH); 
     eastPanel.add(removePanel, BorderLayout.SOUTH); 

     mainPanel.setLayout(new BorderLayout()); 

     mainPanel.add(westPanel, BorderLayout.WEST); 
     mainPanel.add(eastPanel, BorderLayout.EAST); 

     this.getContentPane().add(new JScrollPane(mainPanel), BorderLayout.NORTH); 
    } 

} 
+0

"JTable имеет неожиданное поведение" - и что неожиданное поведение является ...? –

+0

@JonSkeet Я отредактировал его, но в двух словах при нажатии под ним отображаются данные при запуске программы при отображении всей базы данных. Я добавил фотографию к моему объяснению. –

+1

Хорошо, какая диагностика вы использовали до сих пор, чтобы понять, что происходит? Вы поставили точки останова в коде, чтобы посмотреть, какой запрос выполняется? Вы должны уметь существенно сузить этот вопрос и предоставить короткую, но полную * программу, демонстрирующую проблему. (См. Http://stackoverflow.com/help/mcve) –

ответ

2

Ваша проблема, как представляется, быть вызвано добавлением нового JScrollPane с JTable, не удаляя предыдущую JScrollPane.

Например, попробуйте запустить код ниже

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.util.Random; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 

@SuppressWarnings("serial") 
public class FrameFC extends JFrame { 

    public static void main(String[] args) { 
     new FrameFC(); 
    } 

    private Random random = new Random();  
    private JPanel northPanel = new JPanel(); 

    private JTable excel = new JTable(); 
    private JScrollPane currentScrollPane = null; 

    public FrameFC() { 
     this.setTitle("Gestionnaire de produits"); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     northPanel.add(new JButton(new AbstractAction("Change Table") { 

      @Override 
      public void actionPerformed(ActionEvent evt) { 
       tableCreation(); 
      } 
     })); 

     add(northPanel, BorderLayout.PAGE_START); 
     tableCreation(); 
     pack(); 
     setLocationRelativeTo(null); 

     this.setVisible(true); 
    } 

    private void tableCreation() { 
     String[] columnNames = {"A", "B", "C"}; 

     int rowCount = random.nextInt(10) +3; 
     Object[][] rowData = new Object[rowCount][columnNames.length]; 
     for (int i = 0; i < rowData.length; i++) { 
      for (int j = 0; j < rowData[i].length; j++) { 
       rowData[i][j] = "" + random.nextInt(100) + 50; 
      } 
     } 

     excel = new JTable(rowData, columnNames); 
     excel.setAutoCreateRowSorter(true); 

     if (currentScrollPane != null) { 
      // remove(currentScrollPane); // ******* here ****** 
     } 
     currentScrollPane = new JScrollPane(excel); 

     add(currentScrollPane); 
     this.revalidate(); 
     repaint(); 
    } 

} 

и без этой линии прокомментировал:

// remove(currentScrollPane); // ******* here ****** 

Если это не стоит на месте, вы можете увидеть побочные эффекты от нераспределенной JScrollPane.

Лучшее решение, как я уже упоминал в своих комментариях: не заменяйте компоненты, а вместо этого меняйте модель в JTable. Создайте модель DefaultTableModel с нужными данными и настройте модель JTable, вызвав на ней setModel(...). Это намного чище и безопаснее.

Обратите также внимание на мои попытки сделать код и удалить все биты, не связанные с вашей проблемой, включая любой и весь код SQL, а также компоненты и слушатели, не связанные с проблемой. Пожалуйста, подумайте об этом самостоятельно в своих попытках отладки и ваших вопросов на этом сайте.

например,

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.util.Random; 
import javax.swing.*; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableModel; 

@SuppressWarnings("serial") 
public class PanelFC extends JPanel { 
    private static final String[] COLUMN_NAMES = {"A", "B", "C"}; 
    private Random random = new Random();  
    private JPanel northPanel = new JPanel();  
    private JTable excel = new JTable(modelCreation()); 

    public PanelFC() { 
     northPanel.add(new JButton(new CreateModelAction("Create Model"))); 

     setLayout(new BorderLayout()); 

     add(northPanel, BorderLayout.PAGE_START); 
     add(new JScrollPane(excel), BorderLayout.CENTER); 
    } 

    private TableModel modelCreation() { 
     // your code will take some parameter, and using database query 
     // result, create the table model 
     // Also, all database code should be called in a background thread 
     int rowCount = random.nextInt(10) +3; 
     Object[][] rowData = new Object[rowCount][COLUMN_NAMES.length]; 
     for (int i = 0; i < rowData.length; i++) { 
      for (int j = 0; j < rowData[i].length; j++) { 
       rowData[i][j] = "" + random.nextInt(100) + 50; 
      } 
     }   
     DefaultTableModel model = new DefaultTableModel(rowData, COLUMN_NAMES); 
     return model; 
    } 

    private class CreateModelAction extends AbstractAction { 
     public CreateModelAction(String name) { 
      super(name); 
      int mnemonic = (int) name.charAt(0); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      excel.setModel(modelCreation()); 
     } 
    } 

    private static void createAndShowGui() { 
     PanelFC mainPanel = new PanelFC(); 

     JFrame frame = new JFrame("PanelFC"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGui(); 
      } 
     }); 
    } 
} 
+0

Ничего себе, если вы знаете, как долго я искал решение этой проблемы. Я очень благодарен HoverCraft. Большое вам спасибо, он отлично работает. –

+0

@YassinHH: Добро пожаловать - см. Править. Лучшее решение: создать таблицуModel из данных базы данных. Также в соответствии с комментариями вы должны стремиться помещать данные базы данных в фоновый поток. Кроме того, перечитайте ссылку [mcve]. Я создал свой MCVE здесь, чтобы решить эту проблему, но в будущем бремя усилий по созданию и публикации этих вопросов должно быть на вопросе афер, а не на решателя вопросов добровольца. –

+0

Я прочитал его и был готов отредактировать вопрос после воссоздания всей проблемы, конечно ... Спасибо за совет и еще раз спасибо за помощь :) –

Смежные вопросы