【问题标题】:Java Swing: Making a graceful Jscrollpane with or without a JTableJava Swing:使用或不使用 JTable 制作优雅的 Jscrollpane
【发布时间】:2018-05-08 23:46:50
【问题描述】:

我需要一个 UI 来一遍又一遍地收集类似的数据,最好将其描述为批处理条目。要输入批处理,我需要一个滚动窗格来调整用户输入的任何数据大小。为了顺利完成这项工作,我依靠附加到 jscrollpane 的 jtable,并将行作为 jpanel。我在使用此解决方案时遇到了一些麻烦,即

  1. 我不知道如何访问我的 jpanel 中的文本字段
  2. 我不知道如何在我的 jtable 上添加更多 jpanel 作为行。

我可以补充一点,在尝试将许多 jpanel 一次又一次地添加到一个 jscrollpane 之后,我跳到了这个解决方案(这可能不一定是最好的),但这并不奏效。这个替代方案失败,因为似乎通过 setviewportview 添加 jpanel 并不是为了接受新面板来扩展视图。相同的变体是 一个 jpanel 附加到一个滚动窗格,然后添加 许多 jpanel在附加到滚动窗格的主面板上,但视图没有展开并且滚动窗格保持不变。我已经检查了oracle's scrollpane tutorial并看到了客户端的动态变化以及如何重新验证客户端但不知道如何这将适用于我添加新 jpanel 的情况(除非我将它们添加到一个 jpanel 上,我会在添加新 jpanel 时不断设置新的客户首选大小。)

注意:

  1. 我不断添加的 jpanel 并不是真正新的,因为我正在对其进行迭代。
  2. 我尝试过的另一个第三个解决方案是使用灵活的网格布局,它的行是用户可以选择的变量“x”,并且可以添加多个“x”jpanel,问题是,这是主要问题,滚动窗格不能很好地允许扩展,因此它也没有适应新的视图。
  3. 请注意,我需要的滚动窗格不应附加到 JFrame,而应附加到 JFrame 内的内部视图(如仅在 borderLayout UI 中的 North 或 Center 的滚动窗格)。
  4. 我知道作为一行的 jpanel 可以替换为普通行,其中行上的每个单元格都可以充当 jtextfield、jlabel 或我需要的任何组件,但这种方法是针对特定需要制作的JTable 看起来像一个实际的物理文档。

如何制作一个可以动态扩展以添加 jpanels 的良好滚动窗格?

下面的代码显示了两次添加 jpanels 以希望扩展滚动窗格的尝试,但都失败了。

解决方案一将每个单元格呈现为 jpanel,但我无法访问 jpanel 上的文本字段,因此我无法从用户那里获取数据,也无法添加另一行来创建批处理。

    public class JTablePanelRow extends JFrame implements ActionListener{

    JButton addRow = new JButton("Add Row");
    JTable table = new JTable();
    JScrollPane spane = new JScrollPane();
    JPanel mainPanel = new JPanel(new BorderLayout());
    JPanel panelRow = new JPanel();
    JLabel lblName = new JLabel("NAME");
    JTextField txName = new JTextField();
    JLabel lblAge = new JLabel("AGE");
    JTextField txAge = new JTextField();
    TblModel tblmodel = new TblModel();

     public static void main(String[] args) {

     JTablePanelRow tblPane = new JTablePanelRow();
     tblPane.init();

     }

    void init(){
        panelRow.setLayout(new GridLayout(2,2,4,4));
        panelRow.add(lblName);
        panelRow.add(txName);
        panelRow.add(lblAge);
        panelRow.add(txAge); 
        table.setModel(tblmodel);
        table.setRowHeight(50);
        table.getColumn("A").setCellRenderer(new     PanelRenderer(panelRow));
        spane.setViewportView(table);
        addRow.addActionListener(this);
        mainPanel.add(addRow,"North");
        mainPanel.add(spane,"Center");
        this.getContentPane().add(mainPanel);
        this.setVisible(true);
        this.setSize(new Dimension(400,500));
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==addRow){
            tblmodel.addNewRow();

        }
      }
    }


    class TblModel extends AbstractTableModel{


        @Override
        public int getRowCount() {
        return 1;
        }

        @Override
        public int getColumnCount() {
        return 1;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
        return "";
        }

        public void addNewRow(){
               //how to add the jpanel again
        } 

       }

       class PanelRenderer extends DefaultTableCellRenderer{
       JPanel entryPn = new JPanel();

       public PanelRenderer(JPanel entryPn){
       this.entryPn = entryPn;

       }

       @Override
       public Component getTableCellRendererComponent(JTable table, Object value,
  boolean isSelected, boolean hasFocus, int row, int column) {

       entryPn.setPreferredSize(new Dimension(200,50));
       entryPn.setBackground(Color.pink);

       return entryPn;}

          }

解决方案二尝试通过灵活的网格布局添加 jpanel,但 jpanel 未添加或不可滚动。

public class GridLayoutTrick extends JFrame{

  JPanel mainPanel = new JPanel(new BorderLayout());
  JScrollPane scroll = new JScrollPane();
  JPanel entryPanel = new JPanel();
  JPanel rowPanel = new JPanel();
  int batchNumber = 10;
  JPanel northPanel = new JPanel();


 public static void main(String[] args) {
     GridLayoutTrick glt = new GridLayoutTrick();
     glt.init();
  }

  void init(){
      rowPanel.setBackground(Color.PINK);
      rowPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK,5));
      rowPanel.setPreferredSize(new Dimension(100,50));
      entryPanel.setLayout(new GridLayout(batchNumber,1,4,4));
          for(int i = 0;i < batchNumber;i++){
              entryPanel.add(rowPanel);
          }

      entryPanel.setBackground(Color.BLUE);
      scroll.setViewportView(entryPanel);
      mainPanel.add(northPanel,"North");
      mainPanel.add(scroll,"Center");
      this.getContentPane().add(mainPanel);
      this.setVisible(true);
      this.setSize(new Dimension(400,400));
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      } 
    }

【问题讨论】:

  • 为什么不让表格可编辑? TableModel 应该携带每一行的数据,然后可以将其拆分为单独的列
  • 另一种选择可能是有一个“输入”窗格,当用户点击并添加/更新按钮时,会将数据添加到表模型中
  • @MadProgrammer 你的意思是让 jtable 单元格可编辑吗?我在 TableModel 中通过覆盖 isCellEditable 方法将其设置为 true 来做到这一点,但我很震惊地意识到,一旦我单击单元格,就无法选择 jpanel 上的文本字段,它就像一个 jtable 行!!!至于您建议的带有添加/更新按钮的“输入”窗格的替代方案,事实上,这就是我所拥有的,正在努力的是 scrollpane 以允许用户可以看到的批处理条目整批而不是“零碎”条目..
  • 问题是,我会让每个单元格负责编辑特定字段,而不是让面板中包含多个字段

标签: java swing


【解决方案1】:

解决方案二尝试通过灵活的网格布局添加 jpanel,但 jpanel 未添加或不可滚动。

      for(int i = 0;i < batchNumber;i++){
          entryPanel.add(rowPanel);
      }

您只有 1 个“rowPanel”。

每次您想将“rowPanel”添加到“entryPanel”时,都需要创建一个单独的实例。

  mainPanel.add(northPanel,"North");
  mainPanel.add(scroll,"Center");

不要使用魔法常量。使用 API 中的字段:

  1. BorderLayout.PAGE_START
  2. BorderLayout.CENTER

虽然我真的认为 MadProgrammer 的建议是一个更好的解决方案。

【讨论】:

  • 哦!我现在明白了。谢谢,甚至不知道魔术常数是什么:-)
  • 由于在 jtable 中使用 jpanel 作为一行,因此 jscrollpane 的正常工作得到了保证,对于解决方案一,我将如何访问此 jpanel 中的 jtextfield?
  • 您不会将 JPanel 用作 JTable 中的一行。我从来没有建议过。使用 JTable 的要点是每条数据都在自己的单元格中,您可以通过 TableModel 访问单元格中的数据。
  • 谢谢,你没有建议我使用 JPanel。无论如何,似乎 JTable 行可以呈现为 jpanel 的唯一原因是仅用于显示目的而无需输入。再次感谢。
【解决方案2】:

我不知道为什么你不只使用JTable 的可编辑功能,你只是通过尝试使用JPanel 作为单元格渲染器让自己的生活变得更加困难/编辑器

您应该首先仔细查看How to use tables,以更好地了解表格的使用方式

以下是一个过于简化的示例,它允许您添加任意数量的行并编辑表格中每个单元格的值...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {
        private DefaultTableModel model;

        public TestPane() {
            setLayout(new BorderLayout());
            model = new DefaultTableModel(new Object[]{"Name", "Age"}, 0);
            JTable table = new JTable(model);

            add(new JScrollPane(table));

            JButton btn = new JButton("Add");
            add(btn, BorderLayout.SOUTH);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.addRow(new Object[] {"", ""});
                    table.editCellAt(model.getRowCount() - 1, 0);
                    table.getEditorComponent().requestFocusInWindow();
                }
            });
        }

    }

}

就个人而言,我会设置一个容器对象来保存数据并通过自定义TableModel 对其进行管理,但这就是我。

我还会考虑实现continuous editing model 以允许用户在“连续”编辑模式下轻松地在表格中移动

【讨论】:

  • 谢谢兄弟,我明白了。我使用 jpanel 的主要原因,诚然它确实让生活变得更加艰难,是因为我需要 UI 看起来几乎与客户端业务流程中使用的物理文档格式完全相同。客户不太精通计算机,并且他们的手动文档与“数字文档”的一对一表示,即 UI 的外观将有助于提高用户友好性。我想我现在将按照您给出的示例使用正常行。顺便说一句,你是我的超级英雄!!!我可以给你发一封电子邮件到 0beeshr0@*,不要问我是怎么得到它的 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 2023-03-19
  • 1970-01-01
  • 2015-10-02
  • 2015-02-13
  • 2017-12-28
  • 2014-01-24
相关资源
最近更新 更多