implemented JSearchBar
parent
a49cef4e00
commit
a3205a1cce
Binary file not shown.
|
@ -1,5 +1,116 @@
|
|||
package nt.UI.control;
|
||||
|
||||
public class JSearchBar {
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.awt.TextField;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JWindow;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import nt.UI.control.interfaces.SearchBarFinder;
|
||||
|
||||
public class JSearchBar extends JSearchTextField{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
protected static final File SYMBOLS_FILE = null;
|
||||
|
||||
protected SearchBarFinder finder;
|
||||
protected SearchDropDown dropDown;
|
||||
protected boolean completionActive = false;
|
||||
protected String lastEntered = "";
|
||||
private final JSearchBarController controller;
|
||||
|
||||
public JSearchBar(SearchBarFinder finder) {
|
||||
this.finder = finder;
|
||||
this.dropDown = new SearchDropDown();
|
||||
setFont(new Font("LigatureSymbols", Font.PLAIN, 13));
|
||||
|
||||
this.controller = new JSearchBarController(this);
|
||||
controller.setDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
super.setVisible(b);
|
||||
txtSearch.setText("\uE116 search");
|
||||
txtSearch.setHorizontalAlignment(JTextField.CENTER);
|
||||
}
|
||||
|
||||
protected void doCompletion() {
|
||||
System.out.println("completion");
|
||||
String[] tokens = this.finder.getSearchResults(txtSearch.getText());
|
||||
if(tokens.length > 1) {
|
||||
this.dropDown.putItems(tokens);
|
||||
if(!this.dropDown.isVisible()) {
|
||||
this.dropDown.setVisible(true);
|
||||
}
|
||||
}else {
|
||||
if(this.dropDown.isVisible()) {
|
||||
this.dropDown.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void startCompletion() {
|
||||
this.completionActive = true;
|
||||
this.dropDown.setVisible(true);
|
||||
}
|
||||
protected void stopCompletion() {
|
||||
this.completionActive = false;
|
||||
this.dropDown.setVisible(false);
|
||||
}
|
||||
|
||||
protected class SearchDropDown extends JWindow{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int ROW_COUNT = 5;
|
||||
|
||||
protected DefaultListModel<String> data = new DefaultListModel<>();
|
||||
protected JList<String> list = new JList<>(data);
|
||||
protected JScrollPane scrollPane = new JScrollPane(list);
|
||||
|
||||
public SearchDropDown() {
|
||||
this.list.setVisibleRowCount(ROW_COUNT);
|
||||
setAlwaysOnTop(true);
|
||||
add(this.scrollPane);
|
||||
}
|
||||
|
||||
public void putItems(String[] tokens) {
|
||||
this.data.clear();
|
||||
for(String token : tokens) {
|
||||
this.data.addElement(token);
|
||||
}
|
||||
positionMenu();
|
||||
}
|
||||
|
||||
public void positionMenu() {
|
||||
JSearchBar parent = JSearchBar.this;
|
||||
if(parent.isShowing()) {
|
||||
if (this.list.getFixedCellHeight() < 0) {
|
||||
this.list.setFixedCellHeight(this.getFontMetrics(this.getFont()).getHeight() + 2);
|
||||
}
|
||||
int x, y, width, height;
|
||||
Dimension dim = parent.getSize();
|
||||
x = parent.getLocationOnScreen().x;
|
||||
y = parent.getLocationOnScreen().y + dim.height;
|
||||
width = dim.width;
|
||||
height = this.list.getFixedCellHeight() * ROW_COUNT;
|
||||
setSize(new Dimension(width, height));
|
||||
setLocation(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
package nt.UI.control;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.HierarchyBoundsListener;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import nt.UI.util.DocumentAdapter;
|
||||
|
||||
public class JSearchBarController extends KeyAdapter implements DocumentListener, FocusListener, ComponentListener, HierarchyBoundsListener, ListSelectionListener{
|
||||
|
||||
private static final String COMPLETION_CANCEL_KEY = "comp.cancel";
|
||||
private static final String SELECT_KEY = "comp.select";
|
||||
|
||||
private static final KeyStroke COMPLETION_CANCEL_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
|
||||
private static final KeyStroke SELECT_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
||||
|
||||
private JSearchBar searchBar;
|
||||
|
||||
protected JSearchBarController(JSearchBar searchBar) {
|
||||
this.searchBar = searchBar;
|
||||
|
||||
searchBar.txtSearch.addFocusListener(this);
|
||||
searchBar.txtSearch.addKeyListener(this);
|
||||
searchBar.txtSearch.getDocument().addDocumentListener(this);
|
||||
InputMap inputMap = searchBar.txtSearch.getInputMap();
|
||||
inputMap.put(COMPLETION_CANCEL_STROKE, COMPLETION_CANCEL_KEY);
|
||||
|
||||
ActionMap actionMap = searchBar.txtSearch.getActionMap();
|
||||
actionMap.put(COMPLETION_CANCEL_KEY, new AbstractAction() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setDefaultState();
|
||||
}
|
||||
});
|
||||
|
||||
searchBar.txtSearch.addComponentListener(this);
|
||||
searchBar.txtSearch.addHierarchyBoundsListener(this);
|
||||
searchBar.addActionListener(e -> setDefaultState());
|
||||
|
||||
searchBar.dropDown.list.addListSelectionListener(this);
|
||||
|
||||
}
|
||||
|
||||
protected void setDefaultState() {
|
||||
JTextField txt = this.searchBar.txtSearch;
|
||||
this.searchBar.showCancelButton(false);
|
||||
txt.setText("search");
|
||||
txt.setFont(txt.getFont().deriveFont(Font.ITALIC));
|
||||
this.searchBar.repaint();
|
||||
this.searchBar.stopCompletion();
|
||||
Window win = SwingUtilities.getWindowAncestor(searchBar);
|
||||
if(win != null) {
|
||||
win.requestFocus();
|
||||
}
|
||||
}
|
||||
protected void setEnteredState() {
|
||||
JTextField txt = this.searchBar.txtSearch;
|
||||
this.searchBar.showCancelButton(true);
|
||||
txt.setFont(txt.getFont().deriveFont(Font.PLAIN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
JTextField bar = this.searchBar.txtSearch;
|
||||
if(bar.getText().toLowerCase().equals("search")) {
|
||||
bar.setText("");
|
||||
}
|
||||
setEnteredState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
JTextField bar = this.searchBar.txtSearch;
|
||||
if(bar.getText().isEmpty() || bar.getText().toLowerCase().equals("search")) {
|
||||
setDefaultState();
|
||||
}else {
|
||||
setEnteredState();
|
||||
}
|
||||
this.searchBar.stopCompletion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if(this.searchBar.completionActive) {
|
||||
JList<?> list = searchBar.dropDown.list;
|
||||
int index = list.getSelectedIndex();
|
||||
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
|
||||
index = index >= list.getModel().getSize()? list.getModel().getSize()-1:++index;
|
||||
}else if(e.getKeyCode() == KeyEvent.VK_UP) {
|
||||
index = index <= -1? -1 : --index;
|
||||
}
|
||||
list.setSelectedIndex(index);
|
||||
list.ensureIndexIsVisible(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if(this.searchBar.completionActive) {
|
||||
this.searchBar.dropDown.positionMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
if(this.searchBar.completionActive) {
|
||||
this.searchBar.dropDown.positionMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ancestorMoved(HierarchyEvent e) {
|
||||
if(this.searchBar.completionActive) {
|
||||
this.searchBar.stopCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ancestorResized(HierarchyEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
String val = searchBar.dropDown.list.getSelectedValue();
|
||||
if(val != null) {
|
||||
JTextField field = searchBar.txtSearch;
|
||||
field.setText(val);
|
||||
field.setCaretPosition(field.getText().length());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
if(searchBar.txtSearch.getDocument().getLength() > 0) {
|
||||
if(!searchBar.completionActive) {
|
||||
searchBar.startCompletion();
|
||||
}
|
||||
searchBar.doCompletion();
|
||||
}else {
|
||||
searchBar.stopCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
searchBar.doCompletion();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package nt.UI.control;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class JSearchTextField extends JPanel{
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JLabel lblLens;
|
||||
protected JTextField txtSearch;
|
||||
protected JButton btnCancel;
|
||||
private Component horizontalStrut;
|
||||
private Component horizontalStrut_1;
|
||||
|
||||
public JSearchTextField() {
|
||||
super();
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
|
||||
Font symbols = new Font("LigatureSymbols", Font.PLAIN, 18);
|
||||
|
||||
horizontalStrut_1 = Box.createHorizontalStrut(20);
|
||||
add(horizontalStrut_1);
|
||||
lblLens = new JLabel("\uE116");
|
||||
lblLens.setFont(symbols);
|
||||
add(lblLens);
|
||||
|
||||
horizontalStrut = Box.createHorizontalStrut(10);
|
||||
add(horizontalStrut);
|
||||
|
||||
txtSearch = new JTextField() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void setText(String txt) {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
txtSearch.setText("search");
|
||||
txtSearch.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
txtSearch.setBackground(getBackground());
|
||||
add(txtSearch);
|
||||
txtSearch.setColumns(10);
|
||||
|
||||
btnCancel = new JButton("\uE10f");
|
||||
btnCancel.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
btnCancel.setBorderPainted(false);
|
||||
btnCancel.setFont(symbols);
|
||||
btnCancel.setOpaque(false);
|
||||
btnCancel.setVisible(false);
|
||||
add(btnCancel);
|
||||
|
||||
setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
setPreferredSize(btnCancel.getPreferredSize());
|
||||
setMinimumSize(btnCancel.getMinimumSize());
|
||||
}
|
||||
|
||||
public void addActionListener(ActionListener l) {
|
||||
this.btnCancel.addActionListener(l);
|
||||
}
|
||||
public void removeActionListener(ActionListener l) {
|
||||
this.btnCancel.removeActionListener(l);
|
||||
}
|
||||
public void showCancelButton(boolean b) {
|
||||
this.btnCancel.setVisible(b);
|
||||
System.out.println(b);
|
||||
revalidate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color bg) {
|
||||
super.setBackground(bg);
|
||||
for(Component c : getComponents()) {
|
||||
c.setBackground(bg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeground(Color fg) {
|
||||
super.setForeground(fg);
|
||||
for(Component c : getComponents()) {
|
||||
c.setForeground(fg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package nt.UI.control.interfaces;
|
||||
|
||||
public interface SearchBarFinder {
|
||||
|
||||
public String[] getSearchResults(String token);
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package nt.UI.tests;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||
|
||||
import nt.UI.control.JSearchBar;
|
||||
import nt.UI.control.JSearchTextField;
|
||||
import nt.UI.control.interfaces.SearchBarFinder;
|
||||
import javax.swing.BoxLayout;
|
||||
import java.awt.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
public class UITestMain extends JFrame{
|
||||
|
||||
private static final boolean DEBUG_LAF = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
if(DEBUG_LAF) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(new MetalLookAndFeel());
|
||||
} catch (UnsupportedLookAndFeelException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UITestMain frame = new UITestMain();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
public UITestMain() {
|
||||
setSize(400,400);
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
|
||||
getContentPane().add(new JSearchBar(new SearchBarFinder() {
|
||||
|
||||
@Override
|
||||
public String[] getSearchResults(String token) {
|
||||
List<String> list = Arrays.asList("a aa aaa aaaa b bb bbb bbbb bbbbb ab aabb bbaa baba".split(" "));
|
||||
LinkedList<String> results = new LinkedList<>();
|
||||
for(String tok : list) {
|
||||
if(tok.startsWith(token)) {
|
||||
System.out.println(tok + " " + token);
|
||||
results.add(tok);
|
||||
}
|
||||
}
|
||||
return results.toArray(new String[0]);
|
||||
}
|
||||
}));
|
||||
|
||||
Component verticalStrut = Box.createVerticalStrut(300);
|
||||
getContentPane().add(verticalStrut);
|
||||
|
||||
JButton btnBtn = new JButton("btn");
|
||||
getContentPane().add(btnBtn);
|
||||
|
||||
JSearchTextField searchTextField = new JSearchTextField();
|
||||
getContentPane().add(searchTextField);
|
||||
|
||||
searchTextField.requestFocus();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package nt.UI.util;
|
||||
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
public abstract class DocumentAdapter implements DocumentListener{
|
||||
|
||||
public enum DEType {
|
||||
INSERT, REMOVE, CHANGE
|
||||
};
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
documentChanged(e, DEType.INSERT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
documentChanged(e, DEType.REMOVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
documentChanged(e, DEType.CHANGE);
|
||||
}
|
||||
|
||||
public abstract void documentChanged(DocumentEvent e, DEType type);
|
||||
|
||||
}
|
Loading…
Reference in New Issue