Как реализовать динамический графический интерфейс в качели

Прежде всего, приношу извинения за публикацию чего-то, возможно, слишком конкретного, но я не очень разбираюсь в Swing и, похоже, не могу найти хороших примеров, соответствующих моим потребностям.

Итак, я пытаюсь найти лучший способ реализовать динамический графический интерфейс для выбора критериев фильтрации в Swing:

Мокет графического интерфейса для реализации

Базовая модель — это класс, содержащий список критериев, которые можно инвертировать (т. е. применять с префиксом НЕ), и свойство, указывающее, следует ли их комбинировать с И или ИЛИ.

Графический интерфейс позволит пользователю добавлять, изменять или удалять критерии и выбирать оператор комбинации (и/или). Первый критерий, естественно, не будет иметь комбинационного селектора, а третий и последующие критерии будут просто использовать тот же комбинационный оператор, что и второй.

Кнопки X справа будут использоваться для удаления критерия. При нажатии кнопки «Добавить» новая строка компонентов будет добавлена ​​внизу. По мере внесения изменений они будут отражаться в базовой модели.

Конечно, я мог бы реализовать это довольно «примитивно», просто добавив компоненты в JPanel, а затем соответствующим образом обновив модель, но я бы предпочел более аккуратное решение, например, предоставляемое TableModel.

Поэтому мне интересно, будет ли таблица с пользовательской TableModel и TableCellRenderer/Editor лучшим подходом, или есть ли лучший способ реализовать что-то подобное. Если таблица действительно лучший подход, я был бы признателен за некоторые указатели на то, как можно использовать TableCellRenderers или -Editors для достижения этой цели.

Заранее спасибо.


person Rolf    schedule 15.06.2011    source источник
comment
Для справки: единственное число критериев – criterion. См. также критерий, своего рода велогонки.   -  person trashgod    schedule 15.06.2011
comment
Упс, не мой родной язык :)   -  person Rolf    schedule 16.06.2011


Ответы (4)


единственный пример, все жестко запрограммировано, для лучшего понимания

РЕДАКТИРОВАТЬ:

как заметила клеопатра, переместил JTable#fireTableDataChanged() из ActionListener в TableModel, исправил все имена классов, начинающиеся с нижнего регистра

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());
    }
}
person mKorbel    schedule 15.06.2011
comment
-1 за вызов fireXX из-за пределов модели, -1 за несоблюдение соглашений об именах java ... давайте, вы можете сделать лучше, чем это :-) - person kleopatra; 15.06.2011
comment
все еще не удовлетворен - fireDataChanged не нужен: по умолчанию достаточно хорошо себя вести, чтобы запустить rowsInserted :) - person kleopatra; 15.06.2011
comment
@kleopatra согласилась с этим, а также удалила другие мои объявления. - person mKorbel; 15.06.2011
comment
@kleopatra хорошо, действительно отличный улов, но чтобы избежать игры с бесполезным значением, необходимым для JTable#fireTableRowsInserted(int firstRow, int lastRow); затем я отключил JTable#fireTableDataChanged(), не беспокойтесь, это DefalutTableModel :-) - person mKorbel; 15.06.2011
comment
+1 Хороший пример. Я думаю, вы имеете в виду, что все имена методов начинаются с нижнего регистра. Кроме того, мне интересно, может ли Comp быть enum, один для type и один для relation. - person trashgod; 15.06.2011

Я думаю, что такой пользовательский TableMOdel и TableCellRenderer/Editor - лучший выбор. http://download.oracle.com/javase/tutorial/uiswing/components/table.html Хорошо бы начать.

person StanislavL    schedule 15.06.2011

добавить все Компоненты для критерия поиска на панель и добавить/удалить конкретную панель. Я не думаю, что Tablemodel - хороший выбор.

person BaSche    schedule 15.06.2011
comment
Не могли бы вы как-то обосновать это мнение? Это просто кажется излишним, или что? - person Rolf; 15.06.2011
comment
хотя, безусловно, это вопрос вкуса, я склонен согласиться - @Rolf: я не вижу в этом требовании особой табличности. Пример кода mKorbel представляет собой сдутую таблицу (с одним столбцом), которая не является списком по той единственной причине, что JList не поддерживает редактирование :-) - person kleopatra; 15.06.2011
comment
Я согласен, что графический интерфейс не особенно табличный. Однако, как вы сказали, JList не поддерживает редактирование, так что плохого в использовании таблицы, даже если она выдает себя за список? На самом деле, я больше думал о таблице из четырех столбцов, где селектор комбинации, отрицание, критерий и кнопка удаления будут иметь свои собственные столбцы. - person Rolf; 15.06.2011
comment
Более того, у вас есть предложение элегантного способа реализовать это без таблицы? - person Rolf; 15.06.2011

Netbeans имеет приятный пользовательский интерфейс, который делает что-то похожее на то, что вы описываете: Task List Filter KeywordPanel

Почему бы не встать на плечи гигантов? Панели Netbeans выглядят красиво и хорошо работают. Реализация даже четко разделена между пользовательским интерфейсом и кодом модели. Если бы я был на вашем месте (а это был июнь 2011 года), я бы основывал свое решение на источнике здесь:

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

KeywordPanel.java содержит этот загадочный комментарий: «Графический интерфейс основан на графическом интерфейсе почтового инструмента Mozilla».

Интересно, что это может быть?

Извините за столь поздний ответ.

person Ryan    schedule 31.12.2013