【问题标题】:Getting the position of a Swing Component relative to the screen获取 Swing 组件相对于屏幕的位置
【发布时间】:2020-10-07 01:06:56
【问题描述】:

我有一个名为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 jdialog


【解决方案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.com/javase/7/docs/api/javax/swing/SwingUtilities.html

【讨论】:

  • 在我接受这个作为答案之前,您能否详细说明如何使用 SwingUtilites.convertPointToScreen,或者至少链接到它的文档?
  • 当然,我刚刚添加了一些示例代码和文档链接。希望这有助于解决问题。
  • @Parzavil,或者至少请链接到它的文档?为什么你需要一个文档链接。我相信您能够自己阅读 API。您应该始终拥有指向 JDK 文档的链接。 在我接受此作为答案之前 - 仍在等待您接受上一个问题的答案:stackoverflow.com/a/62306672/131872
  • @camickr 是的,当然,我找到了文档。我只是认为,对于刚接触编码的人来说,链接到文档是一个好习惯,因为我总是发现文档有点压倒性,而且链接起来总是有很大帮助。很抱歉没有接受您之前的回答,这一定是我忘记了,谢谢你提醒我:D
【解决方案2】:

我需要将 JDialogs 的位置设置为低于其父级..

使用Window.setLocationRelativeTo(Component)

这只会将 JDialog 放在 JTextFiled 的顶部

实际上,它比这更微妙。例如,它将考虑对话框是否会离开屏幕,然后将其重新打开。如果位置基于“屏幕上的位置”,则需要明确处理。

【讨论】:

  • 这只会将 JDialog 放在 JTextFiled 的顶部......
猜你喜欢
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多