JTable:在最后一项下方单击时出现意外行为

JTable : Unexpected behavior when clicking under the last item

请先看图:出现后五行是不正常的。就是在我点击灰色空白区域的时候,他们出现了

我制作了一个列出杂货的程序。

程序启动时,JTable显示整个数据库,然后我让用户select他想看什么。

例如,我select编辑了"Carrefour"生产的所有杂货,列表中共有7项。正常显示。

但是当我点击最后一个项目下的灰色区域时,JTable 出现了下图所示的意外行为(它显示了数据库的其他日期,就像在启动时显示了整个数据库一样).当我调整框架大小时或尝试对不同的列进行排序时,也会发生同样的情况。

我已经研究过了,找不到任何解决这个问题的方法。

点击前

点击后

下面是关于创建 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);
    }
}

编辑 1:

我试过在不使用 JScrollPane 的情况下将 JTable 直接放在 JPanel 上,但没有成功。

我也尝试过在程序启动时不显示整个数据库,但是当我进行第一个查询时,问题是一样的。它要么显示灰色行,要么在我单击随机行时显示上次查询的数据。

我知道问题不是来自我正在使用的查询,因为所需数据已正确显示。

我真的迷路了,无法想象它会从哪里来。

有关信息:我正在使用带有不同 JPanel 的 JFrame。在其中一个上,我添加了 JScrollPane,我在上面放置了 JTable。

编辑 2:

我将整个代码 here 发布给任何想要了解详细信息的人。它包含在一个 class 中,以便于阅读。


完整代码:

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);
    }

}

您的问题似乎是由于在没有删除之前的 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 并通过调用 setModel(...) 来设置 JTable 的模型。这样更干净也更安全。

另请注意我上面尝试获取您的代码并删除与您的问题无关的所有位,包括任何和所有 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();
            }
        });
    }
}