3

有问题的代码:

    textArea.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
            posX = e.getX();
            posY = e.getY();
        }
    });
    textArea.addMouseMotionListener(new MouseAdapter() {
        public void mouseDragged(MouseEvent e) {
            setLocation(e.getXOnScreen() - posX, e.getYOnScreen() - posY);
        }
    });

背景:

我有一个 JFrame,在那个 JFrame 中有一个 JScrollPane,在 JScrollPane 中有一个名为“textArea”的 JTextArea。这个 JTextArea 占据了整个 JFrame 并且 JFrame 是未修饰的。所以给出一些观点,这通常是 JFrame 的样子......

示例图像

当鼠标在 JTextArea 内单击并移动时,整个窗口被拖动。一切都设置为无法专注于这项工作,这意味着它是一个覆盖。

问题:

上面列出的代码运行良好,世界和平。但是一旦有足够的文本出现垂直滚动条(由于换行,没有水平滚动条),拖动窗口就会成为问题。当您单击并开始移动时,JFrame 会立即在屏幕上移动得更高。JTextArea 中的行,当您尝试移动它时,它会向上移动。我认为 get*OnScreen() 方法是有问题的,因为它都与 JTextArea 相关。

有问题的班级:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main extends JFrame {
    private JTextArea textArea;
    private JScrollPane textAreaScroll;
    private int posX = 0;
    private int posY = 0;

public Main() {
    initComponents();
    initListeners();
    for(int i = 0; i < 20; i++){
        addLine(i+" Hello");            
    }
}

public void addLine(String line){
    textArea.append("\n> "+line);
    textArea.setCaretPosition(textArea.getDocument().getLength());
}

private void initListeners(){
    textArea.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
            posX = e.getX();
            posY = e.getY();
        }
    });
    textArea.addMouseMotionListener(new MouseAdapter() {
        public void mouseDragged(MouseEvent e) {
            setLocation(e.getXOnScreen() - posX, e.getYOnScreen() - posY);
        }
    });
}

private void initComponents() {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {}

    textAreaScroll = new JScrollPane();
    textArea = new JTextArea();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setUndecorated(true);
    setAlwaysOnTop(true);
    setAutoRequestFocus(false);
    setBackground(new Color(130,210,255,130));
    setFocusCycleRoot(false);
    setFocusable(false);
    setFocusableWindowState(false);
    setName("main");
    setOpacity(0.4f);
    setResizable(false);

    textAreaScroll.setBorder(null);
    textAreaScroll.setFocusable(false);
    textAreaScroll.setRequestFocusEnabled(false);

    textArea.setEditable(false);
    textArea.setBackground(new Color(0, 0, 0));
    textArea.setColumns(20);
    textArea.setFont(new Font("Consolas", 0, 14));
    textArea.setForeground(new Color(255, 255, 255));
    textArea.setLineWrap(true);
    textArea.setRows(5);
    textArea.setText("> Hello world!\n> another line!");
    textArea.setBorder(null);
    textArea.setFocusable(false);
    textArea.setRequestFocusEnabled(false);
    textAreaScroll.setViewportView(textArea);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(textAreaScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            );
    layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(textAreaScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE)
            );

    pack();
}

public static void main(String args[]) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            new Main().setVisible(true);
        }
    });
}

}

4

2 回答 2

1

您是说JFrame 在屏幕上立即移动得更高。JTextArea 中的行,但实际上它是向下滚动的,因此只有最后几行可见。

如果您想从顶部查看 textArea 内容,请在此处进行更改

initComponents();
initListeners();
for (int i = 0; i < 20; i++) {
   addLine(i + " Hello");
}
//set scrolling position to top
textArea.setCaretPosition(0);
于 2012-12-09T09:11:55.340 回答
1

好吧,您的诊断绝对正确:

当您单击并开始移动时,JFrame 会立即在屏幕上移动得更高。JTextArea 中的行,当您尝试移动它时,它会向上移动。我认为 get*OnScreen() 方法是有问题的,因为它都与 JTextArea 相关。

因此,要解决此问题,请使用GlassPane附加JFrames MouseXXXListener,因此我们可以在拖动时获得正确的坐标,此解决方案的主要问题是glasspane将消耗用于其他组件的事件JFrame,这可以通过MouseEvent适当地重新分配 s 来克服) :

  • 创建JPanel(此glassPane /JPanel将通过 透明setOpaque(false)),附在xxxAdapters此处。

  • 创建自定义侦听器类以 redispacthMouseEvent到必要的组件(因为glasspane将使用JTextArea/的所有事件JScollPane

  • 设置JPanel为您JFramevia的 GlassPane JFrame#setGlassPane(..)

  • 设置JFrame可见而不是通过设置glassPane可见setVisible(true)(如果您在框架可见之前将其设置为可见,这已经是一段时间的 Swing 故障,它将不会显示)。

这是您的固定代码:

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.MouseInputAdapter;

public class Main extends JFrame {

    private JTextArea textArea;
    private JScrollPane textAreaScroll;
    private JPanel glassPane;//create variable for glasspane

    public Main() {
        initComponents();
        initListeners();
        for (int i = 0; i < 20; i++) {
            addLine(i + " Hello");
        }
    }

    public void addLine(String line) {
        textArea.append("\n> " + line);
        textArea.setCaretPosition(textArea.getDocument().getLength());
    }

    private void initListeners() {
        GlassPaneListener gpl = new GlassPaneListener(textAreaScroll.getVerticalScrollBar(), this);
        //add the adapters/listeners to the glasspane
        glassPane.addMouseMotionListener(gpl);
        glassPane.addMouseListener(gpl);
    }

    private void initComponents() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        }

        textAreaScroll = new JScrollPane();
        textArea = new JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setUndecorated(true);
        setAlwaysOnTop(true);
        setAutoRequestFocus(false);
        setBackground(new Color(130, 210, 255, 130));
        setFocusCycleRoot(false);
        setFocusable(false);
        setFocusableWindowState(false);
        setName("main");
        setOpacity(0.4f);
        setResizable(false);

        textAreaScroll.setBorder(null);
        textAreaScroll.setFocusable(false);
        textAreaScroll.setRequestFocusEnabled(false);

        textArea.setEditable(false);
        textArea.setBackground(new Color(0, 0, 0));
        textArea.setColumns(20);
        textArea.setFont(new Font("Consolas", 0, 14));
        textArea.setForeground(new Color(255, 255, 255));
        textArea.setLineWrap(true);
        textArea.setRows(5);
        textArea.setText("> Hello world!\n> another line!");
        textArea.setBorder(null);
        textArea.setFocusable(false);
        textArea.setRequestFocusEnabled(false);
        textAreaScroll.setViewportView(textArea);
        textAreaScroll.setPreferredSize(new Dimension(200, 200));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(textAreaScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(textAreaScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE));

        //create and make glasspane not opaque
        glassPane = new JPanel();
        glassPane.setOpaque(false);

        //set glasspane as JFrame glassPane
        setGlassPane(glassPane);

        pack();

        setVisible(true);//set JFrame visible

        //glassPane can only be setVisible after JFrame is visible
        glassPane.setVisible(true);
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });
    }
}

class GlassPaneListener extends MouseInputAdapter {

    private int posX = 0;
    private int posY = 0;
    Toolkit toolkit;
    private final Container contentPane;
    private final Component textAreaScroll;
    private final Component glassPane;
    private final JFrame frame;
    private boolean wasClickOnInterestedComponent = false;

    public GlassPaneListener(Component textAreaScroll, JFrame frame) {
        toolkit = Toolkit.getDefaultToolkit();
        this.textAreaScroll = textAreaScroll;
        this.frame = frame;
        this.glassPane = frame.getGlassPane();
        this.contentPane = frame.getContentPane();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (!redispatchMouseEvent(e)) {
            frame.setLocation(e.getXOnScreen() - posX, e.getYOnScreen() - posY);
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (!redispatchMouseEvent(e)) {//check if event was redispatched if not its meant for us :)
            posX = e.getX();
            posY = e.getY();
        }
    }

    @Override
    public void mouseReleased(MouseEvent me) {
        wasClickOnInterestedComponent = false;
    }

    private boolean redispatchMouseEvent(MouseEvent e) {
        Point glassPanePoint = e.getPoint();
        Container container = contentPane;
        Point containerPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, contentPane);

        // The mouse event is probably over the content pane.
        // Find out exactly which component it's over.
        Component component = SwingUtilities.getDeepestComponentAt(container, containerPoint.x,
                containerPoint.y);

        if ((component != null) && (component.equals(textAreaScroll)) || wasClickOnInterestedComponent) {
            wasClickOnInterestedComponent = true;//so that if we drag iur cursor off JScrollBar tghe window wont be moved
            // Forward events over the scrollbar
            Point componentPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, component);
            component.dispatchEvent(new MouseEvent(component, e.getID(), e.getWhen(), e.getModifiers(),
                    componentPoint.x, componentPoint.y, e.getClickCount(), e.isPopupTrigger()));
            return true;//the event was redispatched
        } else {
            return false;//event was not redispatched
        }
    }
}
于 2012-12-09T14:18:17.963 回答