我有一个名为SuggestionField
的类,它将向用户显示一个项目列表以自动完成其输入。输入的内容显示在JDialog(suggestionFrame
)中。我需要将JDialogs的位置设置为低于其父级,但是我无法获得相对于屏幕的父级(JTextField
)X和Y。
问题示例
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
public class Runner {
public static void main(String[] args) {
JFrame frame = new JFrame();
String[] items = new String[]{"Tiger", "Wolf", "Car", "Cat", "Space", "Sing", "Scene"};
SuggestionField suggestionField = new SuggestionField(new ArrayList<>(Arrays.asList(items)), frame);
frame.setDefaultCloseOperation(3);
frame.setSize(100, 65);
frame.setLocationRelativeTo(null);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,1));
panel.add(suggestionField);
frame.add(panel);
frame.setVisible(true);
}
public static class SuggestionField extends JTextField implements DocumentListener, KeyListener {
String[] values = new String[0];
ArrayList<String> displayValues = new ArrayList<>(0);
JDialog suggestionFrame;
JPanel suggestionPanel = new JPanel();
Color backGround = new Color(109, 104, 104, 133);
Color selectBackGround = new Color(109, 104, 104, 133);
Color textColor = new Color(5, 19, 88, 255);
Color selectTextColor = new Color(115, 134, 238, 255);
BoxLayout bl = new BoxLayout(suggestionPanel, BoxLayout.Y_AXIS);
int selectedEntry = 0;
public SuggestionField(ArrayList<String> values, JFrame parentDisplay) {
this.getDocument().addDocumentListener(this);
this.addKeyListener(this);
suggestionFrame = new JDialog(parentDisplay);
suggestionFrame.add(suggestionPanel);
suggestionFrame.setUndecorated(true);
suggestionFrame.setAlwaysOnTop(true);
suggestionFrame.setFocusable(false);
suggestionPanel.setFocusable(false);
bl.maximumLayoutSize(suggestionPanel);
this.values = values.toArray(this.values).clone();
}
public boolean updateSuggestions() {
boolean added = false;
boolean add;
displayValues.clear();
for (int i = 0;i < values.length;i++) {
add = true;
for (int k = 0;k < this.getText().length() && k < values[i].length();k++) {
if (values[i].toUpperCase().charAt(k) != this.getText().toUpperCase().charAt(k)) {
add = false;
break;
}
}
if (add && !values[i].equalsIgnoreCase(this.getText()) && values[i].length() > this.getText().length()) {
added = true;
displayValues.add(values[i]);
}
}
return added;
}
private void updateDisplay() {
suggestionFrame.setSize(this.getWidth(), 16 * displayValues.size());
suggestionPanel.removeAll();
suggestionPanel.setLayout(new BoxLayout(suggestionPanel, BoxLayout.Y_AXIS));
for (int i = 0;i < displayValues.size();i++) {
JLabel a = new JLabel(displayValues.get(i));
if (i == selectedEntry) {
a.setBackground(selectBackGround);
a.setForeground(selectTextColor);
} else {
a.setBackground(backGround);
a.setForeground(textColor);
}
suggestionPanel.add(a);
}
suggestionPanel.revalidate();
suggestionFrame.revalidate();
suggestionFrame.setLocation(this.getX(), this.getY() + this.getHeight());
suggestionFrame.setVisible(true);
}
@Override
public void insertUpdate(DocumentEvent e) {
if (updateSuggestions()) {
updateDisplay();
} else suggestionFrame.setVisible(false);
selectedEntry = 0;
this.requestFocus();
}
@Override
public void removeUpdate(DocumentEvent e) {
if (updateSuggestions()) {
updateDisplay();
} else suggestionFrame.setVisible(false);
selectedEntry = 0;
this.requestFocus();
}
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int ID = e.getKeyCode();
switch (ID) {
case 40:
if (selectedEntry < displayValues.size() - 1) selectedEntry++;
updateDisplay();
break;
case 38:
if (selectedEntry > 0) selectedEntry--;
updateDisplay();
break;
case 10:
this.setText(displayValues.get(selectedEntry));
break;
case 27:
suggestionFrame.setVisible(false);
break;
}
this.requestFocus();
this.grabFocus();
}
@Override
public void keyReleased(KeyEvent e) {
}
}
}
[在updateDisplay()
(第97行)方法中,是否可以通过任何方式获取JTextField
的suggestionFrame
的绝对位置
您可以使用SwingUtilities.convertPointToScreen
执行此操作。
只需传递(x,y + height)和您的输入字段以获取显示下拉菜单的起点。
JButton component = new JButton();
Point pt = new Point(component.getLocation());
pt.y += component.getHeight();
SwingUtilities.convertPointToScreen(pt, component);
// pt is now in screen coords... so you can use it to position the pop-up
完整的文档可以在这里找到:https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html
我需要将JDialogs的位置设置为其父对象的下面。
使用Window.setLocationRelativeTo(Component)
。
这将把JDialog放在JTextFiled的顶部
实际上,比这更微妙。例如,将考虑是否将对话框从屏幕上移开并重新打开。如果将位置基于“屏幕上的位置”,则需要明确处理。
Window.setLocationRelativeTo(Component)