Como implementar a GUI dinâmica no swing

Primeiro de tudo, desculpas por postar algo talvez um pouco excessivamente específico, mas eu não sou muito experiente com o Swing, e parece que não consigo encontrar bons exemplos que atendam às minhas necessidades.

Então, estou tentando descobrir a melhor maneira de implementar a GUI dinâmica para escolher os critérios de filtragem no Swing:

Maquete da GUI para implementar

O modelo subjacente é uma class que contém uma lista de critérios que podem ser negados (ou seja, aplicados com um prefixo NOT) e uma propriedade indicando se devem ser combinados com AND ou OR.

A GUI permitiria ao usuário adicionar, alterar ou remover critérios e selecionar o operador de combinação (e / ou). O primeiro critério naturalmente não teria um seletor de combinação, e o terceiro critério e subsequente usaria simplesmente o mesmo operador de combinação que o segundo.

Os botões X à direita seriam usados ​​para excluir um critério. Quando o botão Adicionar for pressionado, uma nova linha de componentes será adicionada à parte inferior. À medida que as mudanças são feitas, estas seriam refletidas no modelo subjacente.

É claro que eu poderia implementar isso de forma bastante “primitiva” simplesmente adicionando componentes a um JPanel e atualizando o modelo de acordo, mas preferiria uma solução mais simples, como a fornecida por um TableModel.

Então, eu estou querendo saber se uma tabela com um TableModel e um TableCellRenderer / Editor personalizados seria a melhor abordagem, ou se há uma maneira melhor de implementar algo assim. Se a tabela é, de fato, a melhor abordagem, eu gostaria de receber algumas dicas de como usar os TableCellRenderers ou -Editors para conseguir isso.

Desde já, obrigado.

único exemplo, tudo é codificado, para uma boa compreensão

EDITAR:

como notou o kleopatra, moveu o JTable # fireTableDataChanged () de ActionListener para o TableModel, emendou todos os ClassNames iniciados com lowerCase

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

Eu acho que um TableMOdel e um TableCellRenderer / Editor tão personalizados são a melhor escolha. http://download.oracle.com/javase/tutorial/uiswing/components/table.html Isso seria bom para começar.

adicione todos os componentes para um critério de pesquisa a um painel e adicione / remova o painel específico. Eu não acho que um Tablemodel seja uma boa escolha aqui.

O Netbeans tem um ui legal que faz algo semelhante ao que você descreve: Filtro de palavras-chave do filtro de lista de tarefas

Por que não ficar de pé sobre os ombros dos gigantes? Os painéis do Netbeans ficam bem e funcionam bem. A implementação é ainda claramente separada entre o código da interface do usuário e o código do modelo. Se eu estivesse no seu lugar (e já era junho de 2011), eu basearia minha solução na fonte aqui:

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

KeywordPanel.java contém este comentário enigmático: “A GUI é baseada na ferramenta de email do Mozilla”.

Eu me pergunto o que isso poderia ser?

Desculpe pela resposta tardia.