【问题标题】:JTable inside a JScrollPane not showing up properlyJScrollPane 中的 JTable 未正确显示
【发布时间】:2014-03-07 09:29:28
【问题描述】:

我正在开发一段我一直在修补的代码的 GUI。我被困在程序的这一部分,我希望用户选择的数据文件以预览方式显示在JTable 中(即用户不应该能够编辑表格上的数据)。

单击“实验参数”选项卡中的按钮(参见下面的屏幕截图),我创建并运行一个“PreviewAction”,它创建一个新选项卡,并用必要的组件填充它。以下是DataPreviewAction 的代码。 编辑:我还发布了一个self-contained, minimal version,它模仿了实际项目中的条件,并表现出相同的行为。

import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

private JPanel panel1;
private JTabbedPane tabs;
private JButton runButton;

public MyFrame() {
    tabs = new JTabbedPane();
    panel1 = new JPanel();
    runButton = new JButton("go!");
    runButton.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            runButtonActionPerformed(evt);
        }
    });
    panel1.add(runButton);
    tabs.addTab("first tab", panel1);
    this.add(tabs);
    pack();
}

public static void main(String args[]) {
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager
                .getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    }

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {

        public void run() {
            MyFrame frame = new MyFrame();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
    /*
     * Normally there is more stuff happening here but this much will do for
     * the sake of example
     */
    List<String[]> data = new LinkedList<String[]>();
    for (int i = 1; i < 1000; i++)
        data.add(new String[] { "entry1", "value1", "value2", "value3" });

    SwingUtilities.invokeLater(new DataPreviewAction(data, tabs));
}

public class DataPreviewAction implements Runnable {

    private JTabbedPane contentHolder;
    private List<String[]> data;

    public DataPreviewAction(List<String[]> data, JTabbedPane comp) {
        this.contentHolder = comp;
        this.data = data;
    }

    @Override
    public void run() {
        DefaultTableModel previewModel = new DefaultTableModel() {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };

        for (String[] datarow : data) {
            previewModel.addRow(Arrays.copyOf(datarow, datarow.length,
                    Object[].class));
        }

        JTable table = new JTable(previewModel);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel(
                "Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));

        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        contentHolder.addTab("Preview", container);
        contentHolder.validate();
        contentHolder.repaint();
    }
}
}

这里至少有两个问题:

  1. JTable(或JScrollPane)根本不渲染
  2. JScrollPane 没有框架本身那么宽,我不知道为什么

我在 Swing 方面并不是那么好,所以我可能会遗漏一些基本的东西。我检查了数据文件是否被正确读取,并且数据模型包含正确数量的行(1000+)。所以表不应该是空的。

建议?

【问题讨论】:

  • 为了尽快获得更好的帮助,请发布MCTaRE(经过测试和可读的最小完整示例)。
  • 您是从哪里以及如何调用此代码的?
  • @Sanjeev 如果 OP 添加了 MCTaRE,您的两个问题都会得到解答。
  • @AndrewThompson 添加了一个指向 pastebin 的链接,一个单一的类,它几乎模仿了与真实代码相同的条件,减去了一整块其他组件和动作侦听器等
  • "添加了一个指向 pastebin 的链接.." 如果是 MCTaRE,它应该足够短,可以编辑到问题中。

标签: java swing user-interface jtable jscrollpane


【解决方案1】:
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel("Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));

JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
contentHolder.addTab("Preview", container);
    //contentHolder.validate(); <- NO good
    //contentHolder.repaint();  <- --"---
}
  • JPanel 使用 FlowLayout (在 API 中实现,仅接受 PreferredSize,默认情况下不可调整大小),正确输出如 attn 图像所示,您必须将 JPanel 的默认 LayoutManager 更改为 @987654324 @,然后是代码行

.

container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
  • 将扩展JComponents 并且可以按您的预期工作,但我认为tablePanel 应该放在CENTER 区域中

编辑:

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

    private JPanel panel1;
    private JTabbedPane tabs;
    private JButton runButton;
    private JFrame frame = new JFrame();
    private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
    private Object[][] data = {
        {"igor", "B01_125-358", "1.124.01.125", true},
        {"lenka", "B21_002-242", "21.124.01.002", true},
        {"peter", "B99_001-358", "99.124.01.001", false},
        {"zuza", "B12_100-242", "12.124.01.100", true},
        {"jozo", "BUS_011-358", "99.124.01.011", false},
        {"nora", "B09_154-358", "9.124.01.154", false},
        {"xantipa", "B01_001-358", "1.124.01.001", false},};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public boolean isCellEditable(int row, int column) {
            switch (column) {
                case 3:
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public Class getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public MyFrame() {
        tabs = new JTabbedPane();
        panel1 = new JPanel();
        runButton = new JButton("go!");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                //
            }
        });
        panel1.add(runButton);
        tabs.addTab("first tab", panel1);
        JTable table = new JTable(model);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel("Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));
        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        tabs.addTab("Preview", container);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tabs);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyFrame frame = new MyFrame();

            }
        });
    }
}

编辑第二个。例如

来自代码(包括您关于将数据填充到模型的想法)

import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

    private JPanel panel1;
    private JTabbedPane tabs;
    private JButton runButton;
    private JFrame frame = new JFrame();
    private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
    private Object[][] data = {
        {"igor", "B01_125-358", "1.124.01.125", "true"},
        {"lenka", "B21_002-242", "21.124.01.002", "true"},
        {"peter", "B99_001-358", "99.124.01.001", "false"},
        {"zuza", "B12_100-242", "12.124.01.100", "true"},
        {"jozo", "BUS_011-358", "99.124.01.011", "false"},
        {"nora", "B09_154-358", "9.124.01.154", "false"},
        {"xantipa", "B01_001-358", "1.124.01.001", "false"},};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public boolean isCellEditable(int row, int column) {
            switch (column) {
                case 3:
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public Class getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public MyFrame() {
        tabs = new JTabbedPane();
        panel1 = new JPanel();
        runButton = new JButton("go!");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                List<String[]> data = new LinkedList<String[]>();
                for (int i = 1; i < 10; i++) {
                    data.add(new String[]{"entry1", "value1", "value2", "value3"});
                }
                for (String[] datarow : data) {
                    model.addRow(Arrays.copyOf(datarow, datarow.length, Object[].class));
                }
            }
        });
        panel1.add(runButton);
        tabs.addTab("first tab", panel1);
        JTable table = new JTable(model);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel("Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));
        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        tabs.addTab("Preview", container);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tabs);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyFrame frame = new MyFrame();

            }
        });
    }
}

【讨论】:

  • 更改LayoutManager 有助于缩放ScrollPane 的区域,但无论是这还是将对齐移动到中心都不会对渲染产生影响。
  • SSCCE, MCVE, MCTRE 的示例,然后可以提出建议(JFrame???、JTabbedPane、setPreferredScrollableViewportSize),否则所有内容都被排除在 MilkyWay 之外
  • 我不明白你的意思,你能澄清一下吗?
  • 是的,上面的示例代码在我的机器上运行.. 上面的代码中缺少导入,我刚刚意识到.. 我将添加它们
  • 忽略我之前的评论,你真正想做什么,1. 向 JTabbedPane 添加一个新选项卡或 2. 更改 JTable 的数据
【解决方案2】:

跟随 mKorbel 的脚步,我最终做了一些调试。我在这里提供它以防其他人遇到同样的问题。

当底层 DataModel 在初始化时提供一个数据矩阵时,表格看起来还不错,这感觉很奇怪

private DefaultTableModel model = new DefaultTableModel(data, columnNames)

但在使用空构造函数创建时,它会无法正确显示

private DefaultTableModel model = new DefaultTableModel()

稍后使用model.addRow(Object[] row);添加行

我开始查看source code,结果是使用空的构造函数,模型(私有字段)的行数和列数被初始化为 0 并且之后没有正确更新。我在调试时注意到了这一点,因为我的表的尺寸为 1370 x 0,这当然不能正确显示。

因为我不想提前硬编码行数/列数,所以最好的做法是将我的“行”转换为矩阵并通过构造函数将数据提供给model(很像 mKorbel 所做的) .有趣的部分来了,如果你想提供数据,那么你还需要提供列名。你必须有列名的事实是违反直觉的(恕我直言),如果你没有/不需要标题会发生什么?数据已经是表格形式了,所以我不明白为什么列名如此重要。

无论如何,以下代码至少会呈现表格:

String[] colNames = new String[data[1].length];
for(int i=0; i<colNames.length; i++)
    colNames[i] = "C" + i;

DefaultTableModel model = new DefaultTableModel(data,colNames){
    @Override
    public boolean isCellEditable(int row, int column){
        return false;
    }};

我接受这一点是因为它指出了问题的根源,但如果没有 mKorbel 的回答,我将无法查明问题,因此请为他/她的回答投赞成票 :)

【讨论】:

  • 这解决了我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 2016-04-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多