java 如何在swing中实现动态GUI

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6355544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 15:31:44  来源:igfitidea点击:

How to implement dynamic GUI in swing

javaswingtablemodeltablecellrenderertablecelleditor

提问by Rolf

First of all, apologies for posting something perhaps a bit excessively specific, but I'm not very experienced with Swing, and can't seem to find good examples that fit my needs.

首先,很抱歉发布了一些可能有点过于具体的内容,但我对 Swing 的经验不是很丰富,而且似乎找不到适合我需要的好例子。

So I'm trying to figure out the best way to implement the a dynamic GUI for choosing filtering criteria in Swing:

所以我试图找出实现动态 GUI 以在 Swing 中选择过滤条件的最佳方法:

Mockup of GUI to implement

要实现的 GUI 模型

The underlying model is a class containing a list of criteria that can be negated (i.e. applied with a NOT-prefix), and a property indicating whether these should be combined with AND or OR.

底层模型是一个包含可以否定的标准列表(即使用 NOT 前缀)的类,以及指示这些是否应该与 AND 或 OR 组合的属性。

The GUI would allow the user to add, change or remove criteria, and select the combination operator (and/or). The first criterium would naturally not have a combination-selector, and the third and subsequent criteria would simply use the same combination-operator as the second one.

GUI 将允许用户添加、更改或删除标准,并选择组合运算符(和/或)。第一个标准自然不会有组合选择器,而第三个和后续标准将简单地使用与第二个相同的组合运算符。

The X-buttons on the right would be used to delete a criterium. When the Add-button is pressed, a new line of components would be added to the bottom. As changes are made, these would be reflected in the underlying model.

右侧的 X 按钮将用于删除标准。当按下添加按钮时,将在底部添加一行新的组件。随着更改的进行,这些将反映在基础模型中。

Of course I could implement this quite "primitively" by simply adding components to a JPanel and then updating the model accordingly, but I would prefer a neater solution, such as that provided by a TableModel.

当然,我可以通过简单地向 JPanel 添加组件然后相应地更新模型来实现这一点,但我更喜欢更简洁的解决方案,例如 TableModel 提供的解决方案。

So I'm wondering if a table with a custom TableModel and TableCellRenderer/Editor would be the best approach, or if there is a better way to implement something like this. If table is indeed the best approach, I would appreciate some pointers to how one would use TableCellRenderers or -Editors to accomplish this.

所以我想知道带有自定义 TableModel 和 TableCellRenderer/Editor 的表是否是最好的方法,或者是否有更好的方法来实现这样的东西。如果 table 确实是最好的方法,我会很感激一些关于如何使用 TableCellRenderers 或 -Editors 来实现这一点的指针。

Thanks in advance.

提前致谢。

回答by mKorbel

only example, everything is hardcoded, for good understanding

唯一的例子,一切都是硬编码的,以便于理解

EDIT:

编辑:

as kleopatra's noticed, moved JTable#fireTableDataChanged() from ActionListener to the TableModel, amended all ClassNames start with lowerCase

正如 kleopatra 所注意到的,将 JTable#fireTableDataChanged() 从 ActionListener 移动到 TableModel,修改了所有以小写开头的 ClassNames

import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;

public class ComponentTableTest {

    private JFrame frame;
    private JTable CompTable = null;
    private CompTableModel CompModel = null;
    private JButton addButton = null;

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ComponentTableTest().makeUI();
            }
        });
    }

    public void makeUI() {
        CompTable = CreateCompTable();
        JScrollPane CompTableScrollpane = new JScrollPane(CompTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        JPanel bottomPanel = CreateBottomPanel();
        frame = new JFrame("Comp Table Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(CompTableScrollpane, BorderLayout.CENTER);
        frame.add(bottomPanel, BorderLayout.SOUTH);
        frame.setPreferredSize(new Dimension(800, 400));
        frame.setLocation(150, 150);
        frame.pack();
        frame.setVisible(true);
    }

    public JTable CreateCompTable() {
        CompModel = new CompTableModel();
        CompModel.addRow();
        JTable table = new JTable(CompModel);
        table.setRowHeight(new CompCellPanel().getPreferredSize().height);
        table.setTableHeader(null);
        CompCellEditorRenderer compCellEditorRenderer = new CompCellEditorRenderer();
        table.setDefaultRenderer(Object.class, compCellEditorRenderer);
        table.setDefaultEditor(Object.class, compCellEditorRenderer);
        return table;
    }

    public JPanel CreateBottomPanel() {
        addButton = new JButton("Add Comp");
        addButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                Object source = ae.getSource();

                if (source == addButton) {
                    CompModel.addRow();
                    //CompModel.fireTableDataChanged(); // moved to TableModel
                }
            }
        });
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(addButton);
        return panel;
    }
}

class CompCellEditorRenderer extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {

    private static final long serialVersionUID = 1L;
    private CompCellPanel renderer = new CompCellPanel();
    private CompCellPanel editor = new CompCellPanel();

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        renderer.setComp((Comp) value);
        return renderer;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        editor.setComp((Comp) value);
        return editor;
    }

    @Override
    public Object getCellEditorValue() {
        return editor.getComp();
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return false;
    }
}

class CompTableModel extends DefaultTableModel {

    private static final long serialVersionUID = 1L;

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

    public void addRow() {
        super.addRow(new Object[]{new Comp(0, 0, "", "")});
        //super.fireTableDataChanged();
    }
}

class Comp {

    int type;
    int relation;
    String lower;
    String upper;

    public Comp(int type, int relation, String lower, String upper) {
        this.type = type;
        this.relation = relation;
        this.lower = lower;
        this.upper = upper;
    }
}

class CompCellPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel labelWith = new JLabel("With ");
    private JComboBox typeCombo = new JComboBox(new Object[]{"height", "length", "volume"});
    private JComboBox relationCombo = new JComboBox(new Object[]{"above", "below", "between"});
    private JTextField lowerField = new JTextField();
    private JLabel labelAnd = new JLabel(" and ");
    private JTextField upperField = new JTextField();
    private JButton removeButton = new JButton("remove");

    CompCellPanel() {
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        relationCombo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                enableUpper(relationCombo.getSelectedIndex() == 2);
            }
        });
        enableUpper(false);
        removeButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) SwingUtilities.getAncestorOfClass(JTable.class, (Component) e.getSource());
                int row = table.getEditingRow();
                table.getCellEditor().stopCellEditing();
                ((DefaultTableModel) table.getModel()).removeRow(row);
            }
        });
        add(labelWith);
        add(typeCombo);
        add(relationCombo);
        add(lowerField);
        add(labelAnd);
        add(upperField);
        add(Box.createHorizontalStrut(100));
        add(removeButton);
    }

    private void enableUpper(boolean enable) {
        labelAnd.setEnabled(enable);
        upperField.setEnabled(enable);
    }

    public void setComp(Comp Comp) {
        typeCombo.setSelectedIndex(Comp.type);
        relationCombo.setSelectedIndex(Comp.relation);
        lowerField.setText(Comp.lower);
        upperField.setText(Comp.upper);
        enableUpper(Comp.relation == 2);
    }

    public Comp getComp() {
        return new Comp(typeCombo.getSelectedIndex(), relationCombo.getSelectedIndex(), lowerField.getText(), upperField.getText());
    }
}

回答by StanislavL

I think such a custom TableMOdel and TableCellRenderer/Editor is the best choice. http://download.oracle.com/javase/tutorial/uiswing/components/table.htmlThat would be good to start.

我觉得这样的自定义TableMODEl 和TableCellRenderer/Editor 是最好的选择。 http://download.oracle.com/javase/tutorial/uiswing/components/table.html最好开始。

回答by BaSche

add all Components for a search criteria to a panel and add/remove the specific Panel. I don't think a Tablemodel is a good choice here.

将搜索条件的所有组件添加到面板并添加/删除特定面板。我不认为 Tablemodel 是这里的好选择。

回答by Ryan

Netbeans has a nice ui that does something similar to what you describe: Task List Filter KeywordPanel

Netbeans 有一个不错的用户界面,它执行类似于您描述的操作: 任务列表过滤器关键字面板

Why not stand on the shoulders of giants? The Netbeans panels look nice and work well. The implementation is even cleanly separated between ui and model code. If I was in your shoes (and it was June of 2011), I'd base my solution on the source here:

为什么不站在巨人的肩膀上?Netbeans 面板看起来不错并且运行良好。实现甚至在 ui 和模型代码之间完全分离。如果我在你的鞋子里(那是 2011 年 6 月),我的解决方案基于这里的来源:

http://hg.netbeans.org/main/file/14d339767aef/tasklist.ui/src/org/netbeans/modules/tasklist/filter

http://hg.netbeans.org/main/file/14d339767aef/tasklist.ui/src/org/netbeans/modules/tasklist/filter

KeywordPanel.java contains this cryptic comment: "The GUI is based on the one in Mozilla's mail tool".

KeywordPanel.java 包含这个神秘的评论:“GUI 基于 Mozilla 邮件工具中的那个”。

I wonder what that could be?

我想知道那可能是什么?

Sorry for the late answer.

抱歉回复晚了。