9

Googleのようなオートコンプリート用のjavax.swing.JTextFieldwithを構築しようとしています。javax.swing.JList

  • 単語を書くとき、Googleいくつかの一致を表示し、

    • 押すと、とを使用 して一致  ▼  するものを選択できます  ▲    ▼  
    •   ◀ と で入力を編集できます  ▶  
    • キーを押す   Enter         と、ボックス内のコンテンツが検索されます。
    • Escボックスを押すと元の入力に変わります。

私の申請は聖書に関するもので、聖書を勉強しているときに特定の単語を探したいと思っています。Java2sAutoTextFieldを見たことがありますが、矢印キーでこの特定の動作がありません。

4

6 に答える 6

10

これには、カスタムコード化されたコンポーネントが必要です。間違いなくJTextFieldを拡張するクラスであり、そのクラスにはJListを含むJPopupMenuがあります。1つのコンポーネントのように見えるように、テキストフィールドの真下にJPopupMenuを配置する必要があります。

次のトリックは、入力時にフィルタリングすることです。私は通常、Java6 TableRowSorterをJTableと組み合わせて使用​​し、そこにデータを事前に入力します。JTextFieldにいくつかの変更リスナーが必要であり、入力された各キーをインターセプトしてデータをフェッチします。

  1. キーが押されました
  2. DB(または同様のエントリを取得するためのデータストレージ)でクエリを実行します
  3. JTableにそれらの全体を入力します
  4. 取得したデータをフィルタリングするために、JTextFieldエントリに基づいて正規表現でRowFilterを設定します
  5. キーリスナーでアクションを管理する

編集

私が言ったことを示すために、サンプルのスイングアプリを作成しました。これはコピー/貼り付けの例であり、すぐに機能するはずです(JDK 1.6以降が必要です)。私は基本的にあなたが望むものを手に入れました、そして私はあなたに空白を埋めるようにあなたに言う場所にコメントを置きます..例えばEscape keyイベントは消費され、あなたはそれであなたが望むことを何でもすることができます。

initTableModel()メソッドは、テーブルモデルをデータで初期化するだけです。通常は、データベースなどのデータをテーブルモデルに動的に入力する必要があります。多くの調整が可能ですが、これはたとえば酒です;)したがって、これは、目標を完全に達成するために変更するのに十分な例になるはずです。これ以上で、あなたは私に$$$を支払わなければなりません:)

package test.text.googleclone;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

public class SearchAutoFillTest {

private JFrame frame = null;
private JTextField searchField = null;
private JPopupMenu popup = null;

private JTable searchTable = null;
private TableRowSorter<DefaultTableModel> rowSorter = null;
private DefaultTableModel searchTableModel = null;

public SearchAutoFillTest() {
    searchTableModel = new DefaultTableModel();
    initTableModel();

    rowSorter = new TableRowSorter<DefaultTableModel>(searchTableModel);
    searchTable = new JTable(searchTableModel);
    searchTable.setRowSorter(rowSorter);
    searchTable.setFillsViewportHeight(true);
    searchTable.getColumnModel().setColumnSelectionAllowed(false);
    searchTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    searchTable.getTableHeader().setReorderingAllowed(false);
    searchTable.setPreferredSize(new Dimension(775, 100));
    searchTable.setGridColor(Color.WHITE);

    searchField = new JTextField();
    searchField.getDocument().addDocumentListener(new DocumentListener() {
        @Override
        public void changedUpdate(DocumentEvent e) {
            showPopup(e);
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            showPopup(e);
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            showPopup(e);
        }
    });

    searchField.addKeyListener(new KeyListener() {
        @Override
        public void keyTyped(KeyEvent e) {

        }

        @Override
        public void keyReleased(KeyEvent e) {
            int code = e.getKeyCode();
            switch(code)
            {
                case KeyEvent.VK_UP:
                {
                    cycleTableSelectionUp();
                    break;
                }

                case KeyEvent.VK_DOWN:
                {
                    cycleTableSelectionDown();
                    break;
                }

                case KeyEvent.VK_LEFT:
                {
                    //Do whatever you want here
                    break;
                }

                case KeyEvent.VK_RIGHT:
                {
                    //Do whatever you want here
                    break;
                }
            }
        }

        @Override
        public void keyPressed(KeyEvent e) {

        }
    });

    KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE");
    searchField.getInputMap().put(keyStroke, "ESCAPE");
    searchField.getActionMap().put("ESCAPE", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            //Do what you wish here with the escape key.
        }
    });

    popup = new JPopupMenu();
    popup.add(searchTable);
    popup.setVisible(false);
    popup.setBorder(BorderFactory.createEmptyBorder());

    JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
    searchPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
    searchPanel.add(searchField, BorderLayout.CENTER);

    frame = new JFrame();
    frame.setLayout(new BorderLayout(5, 5));
    frame.add(searchPanel, BorderLayout.NORTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 500);
    center(frame);
    frame.setVisible(true);
}

private final void newFilter() {
    RowFilter<DefaultTableModel, Object> rf = null;

    try {
        rf = RowFilter.regexFilter(getFilterText(), 0);
    }
    catch(PatternSyntaxException e) {
        return;
    }

    rowSorter.setRowFilter(rf);
}

private final String getFilterText() {
    String orig = searchField.getText();
    return "("+orig.toLowerCase()+")|("+orig.toUpperCase()+")";
}

private void showPopup(DocumentEvent e) {
    if(e.getDocument().getLength() > 0) {
        if(!popup.isVisible()) { 
            Rectangle r = searchField.getBounds();
            popup.show(searchField, (r.x-4), (r.y+16));
            popup.setVisible(true);
        }

        newFilter();
        searchField.grabFocus();

    }
    else {
        popup.setVisible(false);
    }
}

private void cycleTableSelectionUp() {
    ListSelectionModel selModel = searchTable.getSelectionModel();
    int index0 = selModel.getMinSelectionIndex();
    if(index0 > 0) {
        selModel.setSelectionInterval(index0-1, index0-1);
    }
}

private void cycleTableSelectionDown() {
    ListSelectionModel selModel = searchTable.getSelectionModel();
    int index0 = selModel.getMinSelectionIndex();
    if(index0 == -1) {
        selModel.setSelectionInterval(0, 0);
    }
    else if(index0 > -1) {
        selModel.setSelectionInterval(index0+1, index0+1);
    }
}

private void initTableModel() {
    String[] columns = new String[] {"A"};
    String[][] data = new String[][]
    {
        new String[] {"a"},
        new String[] {"aa"},
        new String[] {"aaab"},
        new String[] {"aaabb"},
        new String[] {"aaabbbz"},
        new String[] {"b"},
        new String[] {"bb"},
        new String[] {"bbb"},
        new String[] {"bbbbbbb"},
        new String[] {"bbbbbbbeee"},
        new String[] {"bbbbbbbeeexxx"},
        new String[] {"ccc"},
        new String[] {"cccc"},
        new String[] {"ccccc"},
        new String[] {"cccccaaaa"},
        new String[] {"ccccccaaaa"},
    };

    searchTableModel.setDataVector(data, columns);
}

private void center(Window w) {
    int screenWidth  = Toolkit.getDefaultToolkit().getScreenSize().width;
    int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;

    int windowWidth = w.getWidth();
    int windowHeight = w.getHeight();

    if (windowHeight > screenHeight) {
        return;
    }

    if (windowWidth > screenWidth) {
        return;
    }

    int x = (screenWidth - windowWidth) / 2;
    int y = (screenHeight - windowHeight) / 2;

    w.setLocation(x, y);
}

public static void main(String ... args) {
    new SearchAutoFillTest();
}
}
于 2012-05-11T14:06:47.450 に答える
3

このコンポーネントはオートコンプリートと呼ばれ、いわゆるスイング拡張プロジェクトに含まれています。

http://swingx.java.net/をご覧ください。デモ付きのWebスタートがあります:http
://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp

于 2012-05-15T12:27:51.790 に答える
3
  • JToolBar / MenuBarに配置された AutoComplete JTextField を使用します。使用前に ArrayList をソートする必要があることに注意してください。

  • JPopup の代わりに装飾されていない JDialog を使用します (まだいくつかの重要なバグがあります)。

    a) JTextField または JMenuBar または JFrame を親とする JDialog を 1 つだけ作成します。

    b) 画面上に JDialog が表示される前に常に AutoComplete JTextField から getBounds を検索します。この Bounds は、JDialog を画面上に正しく配置するためのものです。

    c) JDialog#setVisible(true) を invokeLater() にラップします

  • JDialog.setVisible(false) のエスケープをオーバーライドします。

  • JButton を閉じる/非表示にして、フォーカスロストの残りの重要なメソッドを上書きしないようにします(このカレンダーには、フォーカスロスト、マウスクリックなどに関する優れた回避策があります ....、カレンダー機能をコンパレータの結果に置き換えるのは非常に簡単である可能性があります。ダウンロードコードソース)

  • そこに置くことができます (私の見解) 6 / 9 / 最大 12 個のボタン、たとえば setBackground(Color.white) によって JButton Feels を削除できます。できません。JDialog とこれらの JButtons で何かをしないでください。ジョブは setText("result from Comparator") のみになります

  • AutoComplete JTextField の ArrayList がソートされた場合、2 つの選択肢があります。

    a) ポップアップ JDialog の 6 / 9 / 最大 12 ボタンの setText() に fils 個別の配列を追加することにより、AutoComplete 機能からバイアスをオーバーライドするのが最も簡単です。文章

    b)別の方法は、最初の6 / 9 /最大12の一致を検索する(同じオートコンプリート機能)ための独自のコンパレータを作成することです。

  • 6 / 9 / 最大 12 個の JButton からイベントをキャプチャするには、putClientPropertyまたはEventHandlerまたはSwing Actionsを使用します。ここでは、テキストが空であるかどうかのみをテストします:-)、

  • そのイベントはスケーラブルであり、デフォルトでこのアクションからの出力を有効/無効にできる(JButtons テキストが空の場合)ため、おそらくSwing Actions最良の方法である可能性があります

于 2012-05-15T20:21:26.813 に答える
1

それは次のようなものです。

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.*;


public class Component extends JComponent {
    private final static String[] terms = {"Jesus",
        "Jesus walks on water" //...
    };
    private static ArrayList<String> recent = new ArrayList<String>();

    JTextField jtf;
    JList jl;
    public Component(){
        // set up design
        jtf = new JTextField();
        jtf.setSize(this.getWidth() - 25, 25);
        this.add(jtf);
        //...
        // add key listeners
    }
    class Listener implements KeyListener{

        @Override
        public void keyPressed(KeyEvent arg0) {

        }

        @Override
        public void keyReleased(KeyEvent arg0) {

        }

        @Override
        public void keyTyped(KeyEvent arg0) {
            if (arg0.getKeyCode() == KeyEvent.VK_DOWN){
                // set next item on list
            }
            else if (arg0.getKeyCode() == KeyEvent.VK_UP){
                // set previous item on list
            }
            else if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
                // search
            }
            else if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
                jtf.setText("");
            }
                                    else{
                                         // check list for matches
                                    }
        }

    }
}
于 2012-05-13T20:14:06.280 に答える
1

/ではなく( Swing guideJComboBoxを参照)が必要なようです。JTextFieldJList

もちろん、ドロップダウン ボタンがありますが、これを処理する方法はいくつかあります -こちらを参照してください。

于 2012-05-04T15:36:06.153 に答える
0

デフォルトの動作では、すべての主要なイベントがフォーカスのあるコンポーネントに送信されます。KeyListenerしたがって、あなたがする必要があるのは、実際に他のコンポーネントに行き、両方にインストールする必要があるキーを識別することです。

そのリスナーで、イベントを他のコンポーネントに転送できます。

イベントを新しいコンポーネントにディスパッチする方法については、この回答を参照してください。あなたの場合、sourceは他のコンポーネントである必要があります(テキストフィールドが最初にイベントを受信した場合はリスト、またはその逆の場合)。

于 2012-05-04T15:24:31.623 に答える