【问题标题】:Is it possible for a scrollpane to have multiple tabs in Java?滚动窗格是否可以在 Java 中有多个选项卡?
【发布时间】:2020-10-02 21:31:09
【问题描述】:

所以我认为我需要拆分滚动窗格列表,因为我要显示的项目超过 100 个。我在想我可以有一个带有选项卡的滚动窗格,每个选项卡都有列表的不同部分。有点像选项卡式窗格,但仅用于滚动窗格,就像它只是一个组件一样。问题是我不知道该怎么做,也不知道是否可行。

【问题讨论】:

  • “我认为我需要拆分滚动窗格列表,因为我要显示的项目超过 100 个。” 此列表中的信息类型是什么?信息的各个“部分”之间划分的逻辑基础是什么?物种?日期?团队? .. 我需要这些信息,以便有机会确定如何最好地将数据呈现给应用程序的用户。 顺便说一句:“100”似乎不是很多。但是100个什么?
  • 通常,管理大量数据是通过用户过滤器来完成的。将一个 JTextField 添加到您的窗口中,每当用户在其中键入时,使用该文本作为搜索词并仅显示包含该词的列表项。 (理想情况下,您应该使用不重复的 javax.swing.Timer 开始搜索,每次文本更改时都会重新启动搜索,因此搜索在键入停止后大约一秒钟开始,因此快速键入多个字符不会启动几次搜索只是为了丢弃其中的大部分。)
  • @Andrew Thompson 这是可以使用 MIDI 演奏的乐器列表。我认为 100 个太多了,我想我可以按照他们的乐器家族来划分乐器。
  • @VGR 我正在考虑使用类似用户过滤器的东西,但我不确定每个用户都会知道所有不同的选项。
  • 您当然可以添加比单个文本字段更多的控件。您正在考虑哪些选项?

标签: java swing jscrollpane jlist jtabbedpane


【解决方案1】:

这是一个在JTable 中显示所有库的 MIDI 乐器的示例。它上面提供了三个组合框 (JComboBox) 和一个 JTextField

文本字段可以搜索(不区分大小写)用户输入的任何字符串。

组合可用于过滤:

  1. 乐器类别。
  2. 仪器类型。
  3. 乐器名称中的常用字符串。

哦,我输入了JList 的类别。它什么也不做,但如果我重新做一遍,我会从 LINE_START 位置的列表开始,并且只有列表。

import java.awt.*;
import java.awt.event.*;
import javax.sound.midi.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.border.EmptyBorder;

public class MidiInstrumentSearch {

    private JComponent ui = null;
    Instrument[] instruments;
    JLabel messageLabel = new JLabel("Message Label");
    JTable table;
    MidiInstrumentTableModel tm;
    TableRowSorter sorter;
    InstrumentCategory[] instrumentCategories = {
        new InstrumentCategory("All", 1, 10000),
        new InstrumentCategory("Piano", 1, 8),
        new InstrumentCategory("Chromatic Percussion", 9, 16),
        new InstrumentCategory("Organ", 17, 24),
        new InstrumentCategory("Guitar", 25, 32),
        new InstrumentCategory("Bass", 33, 40),
        new InstrumentCategory("Strings", 41, 48),
        new InstrumentCategory("Ensemble", 49, 56),
        new InstrumentCategory("Brass", 57, 64),
        new InstrumentCategory("Reed", 65, 72),
        new InstrumentCategory("Pipe", 73, 80),
        new InstrumentCategory("Synth Lead", 81, 88),
        new InstrumentCategory("Synth Pad", 89, 96),
        new InstrumentCategory("Synth Effects", 97, 104),
        new InstrumentCategory("Ethnic", 105, 112),
        new InstrumentCategory("Percussive", 113, 120),
        new InstrumentCategory("Sound Effects", 121, 128)
    };

    MidiInstrumentSearch() {
        try {
            initUI();
        } catch (MidiUnavailableException ex) {
            ex.printStackTrace();
        }
    }

    public final void initUI() throws MidiUnavailableException {
        if (ui != null) {
            return;
        }
        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));
        ui.add(messageLabel, BorderLayout.PAGE_END);
        
        ui.add(new JScrollPane(new JList(instrumentCategories)), 
                BorderLayout.LINE_START);

        Synthesizer synthesizer = MidiSystem.getSynthesizer();
        synthesizer.open();
        instruments = synthesizer.getAvailableInstruments();
        InstrumentPOJO[] inst = new InstrumentPOJO[instruments.length];
        for (int ii = 0; ii < inst.length; ii++) {
            inst[ii] = new InstrumentPOJO(instruments[ii]);
        }
        tm = new MidiInstrumentTableModel(inst);
        sorter = new TableRowSorter<>(tm);
        table = new JTable(tm);
        table.setRowSorter(sorter);
        ui.add(new JScrollPane(table));

        JToolBar toolBar = new JToolBar();
        toolBar.setLayout(new FlowLayout());
        ui.add(toolBar, BorderLayout.PAGE_START);

        final JComboBox categoryBox = new JComboBox<>(instrumentCategories);
        ActionListener categoryListener = (ActionEvent e) -> {
            InstrumentCategory ic = (InstrumentCategory) categoryBox.getSelectedItem();
            CategoryFilter categoryFilter = new CategoryFilter(ic);
            sorter.setRowFilter(categoryFilter);
            setNumber();
        };
        categoryBox.addActionListener(categoryListener);
        toolBar.add(new JLabel("Category"));
        toolBar.add(categoryBox);

        toolBar.add(new JLabel("Type"));
        String[] types = {"", "Instrument", "Drumkit"};
        final JComboBox typeBox = new JComboBox<>(types);
        toolBar.add(typeBox);
        ActionListener typeSearchListener = (ActionEvent e) -> {
            String s = typeBox.getSelectedItem().toString();
            SearchFilter sf = new SearchFilter(0, s);
            sorter.setRowFilter(sf);
            setNumber();
        };
        typeBox.addActionListener(typeSearchListener);

        String[] nameCommon = {
            "", "bass", "bell", "brass", "bs",
            "drum", "flute", "gt", "harp", "horn",
            "org", "orch", "pad", "piano",
            "sax", "str", "syn", "vox", "wave"
        };
        final JComboBox nameBox = new JComboBox(nameCommon);
        ActionListener nameListener = (ActionEvent e) -> {
            SearchFilter sf = new SearchFilter(1, nameBox.getSelectedItem().toString());
            sorter.setRowFilter(sf);
            setNumber();
        };
        nameBox.addActionListener(nameListener);
        toolBar.add(new JLabel("Name"));
        toolBar.add(nameBox);

        JTextField searchField = new JTextField("Enter to Search", 12);
        toolBar.add(searchField);
        ActionListener textSearchListener = (ActionEvent e) -> {
            SearchFilter sf = new SearchFilter(1, e.getActionCommand());
            sorter.setRowFilter(sf);
            setNumber();
        };
        searchField.addActionListener(textSearchListener);
    }

    private void setNumber() {
        int i = table.getRowCount();
        setNumber(i);
    }

    private void setNumber(int n) {
        messageLabel.setText(n + " presets");
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception useDefault) {
            }
            MidiInstrumentSearch o = new MidiInstrumentSearch();

            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);

            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());

            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);
    }
}

class InstrumentPOJO {

    private final Instrument instrument;
    private final String category;
    private final String name;
    private final int bank;
    private final int preset;

    InstrumentPOJO(Instrument instrument) {
        this.instrument = instrument;
        String s = instrument.toString();
        category = getTextBetween(s, "", ":");
        name = getTextBetween(s, ":", "bank");
        bank = Integer.parseInt(getTextBetween(s, "bank #", " preset"));
        String pre = "preset #";
        int index = s.indexOf(pre);
        s = s.substring(index + pre.length());
        preset = Integer.parseInt(s);
    }

    private String getTextBetween(String s, String s1, String s2) {
        int i1 = s.indexOf(s1);
        int c1 = i1 + s1.length();
        int i2 = s.indexOf(s2);
        return s.substring(c1, i2).trim();
    }

    @Override
    public String toString() {
        return getCategory() + " \t"
                + getName() + " \t"
                + getBank() + " \t"
                + getPreset() + " \t";
    }

    public Instrument getInstrument() {
        return instrument;
    }

    public String getCategory() {
        return category;
    }

    public String getName() {
        return name;
    }

    public int getBank() {
        return bank;
    }

    public int getPreset() {
        return preset;
    }
}

class MidiInstrumentTableModel extends AbstractTableModel {

    final static String[] colNames = {"Category", "Name", "Bank", "Preset"};
    InstrumentPOJO[] orchestra;

    MidiInstrumentTableModel(InstrumentPOJO[] orchestra) {
        this.orchestra = orchestra;
    }

    @Override
    public int getRowCount() {
        return orchestra.length;
    }

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

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        final InstrumentPOJO ip = orchestra[rowIndex];
        switch (columnIndex) {
            case 0:
                return ip.getCategory();
            case 1:
                return ip.getName();
            case 2:
                return ip.getBank();
            case 3:
                return ip.getPreset();
            default:
                return null;
        }
    }

    @Override
    public String getColumnName(int columnIndex) {
        return colNames[columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 0:
                return String.class;
            case 1:
                return String.class;
            case 2:
                return Integer.class;
            case 3:
                return Integer.class;
            default:
                return Integer.class;
        }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }
}

class SearchFilter extends RowFilter {

    int col;
    String target;

    SearchFilter(int col, String target) {
        this.col = col;
        this.target = target;
    }

    @Override
    public boolean include(Entry entry) {
        String s = entry.getValue(col).toString();
        return s.toLowerCase().contains(target.toLowerCase());
    }
}

class CategoryFilter extends RowFilter {

    InstrumentCategory cat;

    CategoryFilter(InstrumentCategory cat) {
        this.cat = cat;
    }

    @Override
    public boolean include(Entry entry) {
        int i = (Integer) entry.getValue(3) + 1;
        return (i >= cat.getFirst() && i <= cat.getLast());
    }
}

class InstrumentCategory {

    private final String name;
    private final int first;
    private final int last;

    public InstrumentCategory(String name, int first, int last) {
        this.name = name;
        this.first = first;
        this.last = last;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @return the first
     */
    public int getFirst() {
        return first;
    }

    /**
     * @return the last
     */
    public int getLast() {
        return last;
    }

    @Override
    public String toString() {
        return name;
    }
}

【讨论】:

  • 这是一个很好的例子,展示了一个包含工具列表的表格。在我看来,当我第一次问我的问题时,我好像在想象我看到一个带有标签的滚动窗格。我觉得我需要一种不同于表格的方法来完成我正在做的事情。如果我可以单击以突出显示一个选择并可以通过该选择触发一个事件,那么我可以找到一种方法来做到这一点。再说一次,桌子可能占用了太多空间。我不确定。
  • 有很多方法可以解决您的每个问题。因为很明显你还没有决定这个 GUI 应该是什么样子或者它应该如何工作,所以我不会花更多的时间在它上面。想出这些细节,我可能会重新审视它。至于它的外观.. 以最小尺寸提供 ASCII 艺术或 GUI 的 预期 布局的简单绘图,如果可调整大小,则具有更大的宽度和高度 - 以显示额外空间应该如何使用。
  • 我将继续为这个程序开发 GUI 并从那里开始。如果我觉得需要第二个意见,我会回到这篇文章或创建一个新的。我会提供一个图纸/图表。
猜你喜欢
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 2023-02-22
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多