Получение положения компонента Swing относительно экрана - PullRequest
0 голосов
/ 17 июня 2020

У меня есть класс под названием 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

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Для этого можно использовать 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

0 голосов
/ 17 июня 2020

Мне нужно установить положение JDialogs ниже его родительского ..

Используйте Window.setLocationRelativeTo(Component).

Это просто поместит JDialog поверх JTextFiled

На самом деле, это более тонко, чем это. Он примет во внимание, например, если диалоговое окно будет за пределами экрана, и вернет его обратно. Это то, что необходимо явно обработать, если основывать позицию на «местоположении на экране».

enter image description here

...