拖动textarea

时间:2012-12-09 07:17:00

标签: java swing draggable jtextarea

问题代码:

    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的样子......

example image

当鼠标在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);
        }
    });
}

}

2 个答案:

答案 0 :(得分:1)

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

如果您想从顶部看到textArea内容,请点击此处

initComponents();
initListeners();
for (int i = 0; i < 20; i++) {
   addLine(i + " Hello");
}
//set scrolling position to top
textArea.setCaretPosition(0);

答案 1 :(得分:1)

你的诊断绝对是正确的:

  

当您单击并开始移动时,JFrame会立即移动   在屏幕上更高。 JTextArea中的线条移动得越高   当你试图移动它时。我假设get * OnScreen()方法   是问题,因为它与JTextArea都有关。

因此要解决此问题JFrame使用MouseXXXListener附加JFrame因此我们可以在拖动时获得正确的坐标,此解决方案的主要问题是 glasspane < / em>将使用适用于MouseEvent上其他组件的事件,这可以通过适当地重新调整JPanel来克服:

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

  • 将redispacth JTextArea的自定义侦听器类创建为必要的组件(因为 glasspane 将消耗所有事件到JScollPane / JPanel

  • 通过JFrameJFrame#setGlassPane(..)设为JFrame的GlassPane。

  • 设置setVisible(true)可见而不是通过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 } } } 设置 glassPane (如果在框架可见之前将其设置为可见,这已经是一段时间的Swing故障了它不会被显示出来。)

这是您的固定代码:

{{1}}