获取一个Swing组件相对于屏幕的位置。

问题描述 投票:0回答:1

我有一个类叫 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

java swing jtextfield
1个回答
1
投票

你可以使用 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.comjavase7docsapijavaxswingSwingUtilities.html。


0
投票

我需要将JDialogs的位置设置为低于其父节点。

使用 Window.setLocationRelativeTo(Component).

这只是将JDialog放在JTextFiled的上面。

事实上,它比这更微妙。例如,它会考虑到如果对话框不在屏幕上,就会把它移回屏幕上。如果根据 "在屏幕上的位置 "来确定位置,那就需要明确地处理这个问题。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.