输入文本时叠加Swing文本标签

时间:2015-04-07 20:28:09

标签: java swing label overlay

我的程序中的各种表单使用JTables,我已经能够使用Key Listener在用户输入时选择一行。这很好用,但我想向用户提供一些反馈,以显示正在输入的文本。

我尝试过创建框架/标签,但无法正确显示它们。

我的基本想法是 - 创建框架(如果它不存在),创建标签并设置文本。例如:

private void showSearchLabel(String search) {
    if (null == searchTextFrame) {
        searchTextFrame = new JFrame("searchTextFrame");
        searchTextFrame.setBackground(new Color(0, 0, 0, 0));
        searchTextFrame.setUndecorated(true);
        searchTextFrame.setAlwaysOnTop(true);

        searchTextFrame.getContentPane().setLayout(new java.awt.BorderLayout());
        searchTextLabel = new JLabel();
        searchTextFrame.getContentPane().add(searchTextLabel);
        searchTextFrame.pack();
        searchTextFrame.setVisible(true);
    }

    searchTextLabel.setText(search);

}

showSearchLabel由Key Listener调用,它将最近的按键添加到搜索字符串中。 Backspace清除字符串(并删除框架/标签)。 Enter键选择表格中的项目,还应删除框架/标签。

我错过了什么?

编辑:澄清 - 使用上面的代码,根本没有显示。

如果我在创建标签时设置文本,则第一个字符是可见的(在该点可以预期,用户只键入一个字符)。在此之后调用 .setText(search),文本不会更新。注意 - 这在屏幕的顶部/左上角可见,这不是我想要的地方(理想情况下,希望它在JTable中显示)。

2 个答案:

答案 0 :(得分:2)

新的JLabel()有“标题的空字符串”。它的首选大小为零。你可以

  • 在构造函数中添加所需的空格。

    searchTextLabel = new JLabel("        ");
    
  • 在致电pack()后,在封闭的框架上调用setVisible()

    f.setVisible(true);
    …
    searchTextFrame.pack();
    
  • 在构造函数中添加一个空格以建立高度,并在封闭的validate()上调用Container

    searchTextLabel = new JLabel(" ");
    …
    f.setVisible(true);
    …
    searchTextLabel.setText(search);
    searchTextLabel.validate();
    

答案 1 :(得分:2)

在过去的几个月中,我不得不多次重复这样的事情,使用一系列不同的UI方法(隐藏字段直到用户输入,然后通过BorderLayout使其可见;屏幕上的静态字段;等等...)并试图构建一个更简洁和可重用的库机制,这将允许我配置任何JTable具有简单的可过滤支持。

我使用JTextField而不是JLabel的一个原因是,它处理的用户输入比您或我可能生成的任何内容(在合理的时间内)更好,但那是我;)

就个人而言,我不想打开任何新窗口,因为这会引入其他问题,例如焦点相关问题以及在某些平台上隐藏在当前窗口后面的窗口等。

同样地,我几次“取消隐藏”一个字段,布局被迫改变,这看起来很丑陋,并且并不总是需要让滤镜字段始终可见。相反,我试图实现的是一个“弹出”字段,它与表本身一起显示,但是能够在父JScrollPane的可视区域内的任何位置显示...

现在,这种方法可能不适合您的需求,但这是我一直努力的方向......

Filter

同样,核心概念是提供不需要我扩展JTable的功能,但可以包含现有的JTable。核心功能由实用程序类提供,并通过两个interfaces进行管理,这两个JTable提供对某些核心功能的外部控制(过滤器如何应用于JTextField以及取消操作如何工作)。实用程序类还提供了配置取消筛选字段的键盘操作的方法

显示的JTable实际上已添加到JTable本身。我曾想过试图在视图中强制“偏移”,所以所有的行都被按下了,但我知道如何做到这一点的唯一方法就是扩展public class TableUtilities { private static WeakHashMap<JTable, FilterSupport> mapFilters = new WeakHashMap(25); public static void installFilterSupport(JTable table, IFilterListener listener, KeyStroke escapeKey) { FilterSupport support = new FilterSupport(table, listener, escapeKey); mapFilters.put(table, support); } public static void uninstallFilterSupport(JTable table) { FilterSupport support = mapFilters.remove(table); if (support != null) { support.uninstall(); } } protected static class FilterSupport implements IFilterSupport { private JViewport viewport; private JTable table; private JTextField searchField; private Timer filterTimer; private HierarchyListener hierarchyListener; private ChangeListener changeListener; private IFilterListener filterListener; public FilterSupport(JTable table, IFilterListener listener, KeyStroke escapeKey) { this.table = table; this.filterListener = listener; table.setFillsViewportHeight(true); hierarchyListener = new HierarchyListener() { @Override public void hierarchyChanged(HierarchyEvent e) { long flags = e.getChangeFlags(); if ((flags & HierarchyEvent.PARENT_CHANGED) != 0) { if (e.getChanged().equals(table)) { JTable table = (JTable) e.getChanged(); if (e.getChangedParent() instanceof JViewport) { if (table.getParent() == null) { uninstall(); } else { install(); } } } } } }; changeListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { JViewport viewport = (JViewport) e.getSource(); Rectangle viewRect = viewport.getViewRect(); searchField.setSize(searchField.getPreferredSize()); int x = (viewRect.x + viewRect.width) - searchField.getWidth(); int y = viewRect.y; searchField.setLocation(x, y); } }; table.addHierarchyListener(hierarchyListener); searchField = new JTextField(20); searchField.setVisible(false); searchField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { filterChanged(); } @Override public void removeUpdate(DocumentEvent e) { filterChanged(); } @Override public void changedUpdate(DocumentEvent e) { filterChanged(); } }); searchField.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { cancelField(); } }); filterTimer = new Timer(250, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { applyFilter(); } }); filterTimer.setRepeats(false); table.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { if (Character.isLetterOrDigit(e.getKeyChar())) { searchField.setVisible(true); table.revalidate(); table.repaint(); // ?? Should this maintain the current filter value? searchField.setText(null); searchField.requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { searchField.dispatchEvent(e); } }); } } }); Action escapeAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { cancelField(); } }; bindKeyStrokeTo(table, JComponent.WHEN_FOCUSED, "clear", escapeKey, escapeAction); bindKeyStrokeTo(searchField, JComponent.WHEN_FOCUSED, "clear", escapeKey, escapeAction); } protected void cancelField() { searchField.setVisible(false); table.requestFocusInWindow(); table.revalidate(); table.repaint(); if (filterListener != null) { filterListener.filterCancelled(table, this); } } public void filterChanged() { filterTimer.restart(); } protected void applyFilter() { if (filterListener != null) { filterListener.filterChanged(table, searchField.getText()); } } protected void uninstall() { filterTimer.stop(); if (viewport != null) { if (changeListener != null) { viewport.removeChangeListener(changeListener); } table.remove(searchField); searchField.setVisible(false); } viewport = null; } protected void install() { if (viewport != null) { uninstall(); } Container parent = table.getParent(); if (parent instanceof JViewport) { viewport = (JViewport) parent; viewport.addChangeListener(changeListener); table.add(searchField); } } @Override public String getFilter() { return searchField.getText(); } @Override public void setFilter(String filter) { searchField.setText(filter); } } public static void bindKeyStrokeTo(JComponent parent, int condition, String name, KeyStroke keyStroke, Action action) { InputMap im = parent.getInputMap(condition); ActionMap am = parent.getActionMap(); im.put(keyStroke, name); am.put(name, action); } public static interface IFilterSupport { public String getFilter(); public void setFilter(String filter); } public static interface IFilterListener { public void filterChanged(JTable table, String filter); public void filterCancelled(JTable table, IFilterSupport support); } } 本身,这就是我所尝试的

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.WeakHashMap;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

public class TestSearchTable {

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

    public TestSearchTable() {
        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 {

        public TestPane() {
            setLayout(new BorderLayout());

            DefaultTableModel model = new DefaultTableModel(
                            new Object[][]{
                                {"Tiana", "Wilmer"},
                                {"Twana", "Wingate"},
                                {"Cody", "Baumgarten"},
                                {"Venus", "Espy"},
                                {"Savanna", "Buckmaster"},
                                {"Adrien", "Edgecomb"},
                                {"Lauretta", "Sassman"},
                                {"Vivienne", "Glasco"},
                                {"Cassy", "Merryman"},
                                {"Mitchel", "Jarvie"},
                                {"Kelsi", "Casebeer"},
                                {"Rosy", "Rizzi"},
                                {"Bernice", "Capote"},
                                {"Tijuana", "Launius"},
                                {"Jeffie", "Crownover"},
                                {"Selena", "Leavy"},
                                {"Damon", "Tulloch"},
                                {"Norris", "Devitt"},
                                {"Cecil", "Burgio"},
                                {"Queen", "Mechling"}},
                            new Object[]{"First Name", "Last name"}
            ) {

                @Override
                public boolean isCellEditable(int row, int column) {
                    return false;
                }

            };

            JTable table = new JTable(model);
            table.setAutoCreateRowSorter(true);
            TableUtilities.installFilterSupport(table,
                            new TableUtilities.IFilterListener() {
                                @Override
                                public void filterChanged(JTable table, String filter) {
                                    TableRowSorter sorter = (TableRowSorter) table.getRowSorter();
                                    if (filter == null || filter.trim().length() == 0) {
                                        filter = "*";
                                    }

                                    if (!filter.startsWith("*") || !filter.endsWith("*")) {
                                        filter = "*" + filter + "*";
                                    }
                                    filter = wildcardToRegex(filter);
                                    filter = "(?i)" + filter;
                                    sorter.setRowFilter(RowFilter.regexFilter(filter));
                                }

                                @Override
                                public void filterCancelled(JTable table, TableUtilities.IFilterSupport support) {
//                                  support.setFilter(null);
                                }
                            },
                            KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
            add(new JScrollPane(table));
        }

    }

    public static String wildcardToRegex(String wildcard) {

        StringBuilder s = new StringBuilder(wildcard.length());
        s.append('^');

        for (int i = 0, is = wildcard.length(); i < is; i++) {

            char c = wildcard.charAt(i);
            switch (c) {
                case '*':
                    s.append(".*");
                    break;
                case '?':
                    s.append(".");
                    break;
                // escape special regexp-characters
                case '(':
                case ')':
                case '[':
                case ']':
                case '$':
                case '^':
                case '.':
                case '{':
                case '}':
                case '|':
                case '\\':
                    s.append("\\");
                    s.append(c);
                    break;
                default:
                    s.append(c);
                    break;
            }

        }

        s.append('$');
        return (s.toString());

    }

}

我的考试班......

{{1}}