2012-12-09 87 views
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中有一个名为的JTextArea“ textarea的”。此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); 
     } 
    }); 
} 

}

+1

的Swing,AWT,SWT ..? –

+0

以可执行格式发布您的代码。 – vels4j

+0

以可执行格式添加代码。 –

回答

1

嗯,你的诊断是绝对现货上:

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

因此,要解决这个使用JFrameGlassPane附加MouseXXXListener S.这样的拖曳时,我们可以得到正确的坐标,这个解决方案的主要问题是的glassPane会消耗被表示为其它部件上JFrame事件这可以通过适当地将重新调度MouseEvent s内克服):

  • 创建JPanel(这的glassPane/JPanel将吨透过setOpaque(false)),请在这里附上xxxAdapters

  • 创建自定义监听器类redispacth MouseEvent s到必要的组件(如的glassPane将消耗所有事件JTextArea/JScollPane

  • 通过JFrame#setGlassPane(..)设置JPanel为您JFrame的玻璃面板。

  • 设置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 
     } 
    } 
} 
+1

非常感谢您以这种有益的方式回答您的问题!我的下一个问题是重新调度鼠标事件,但你预料到了这一点。再次谢谢你。 –

+0

@Joe很高兴能有所帮助 –

+0

我用你的代码解决了一个小问题,当你点击滚动条并将鼠标移动到JFrame边界之外时,会出现'java.lang.IllegalArgumentException:null source '在这一行上引发异常'componentPoint.x,componentPoint.y,e.getClickCount(),e.​​isPopupTrigger()));'。 –

1

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

如果你想看到从上面textarea的内容,改变就在这里

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

对于不完全清楚的道歉,“更高的动作”有点模糊回顾它。当我这样说时,我引用了整个JFrame相对于整个屏幕向上移动。就像当你要抓住一个窗口并将它拖到屏幕的一个新部分时(除了我的情况),当你开始拖动时,窗口立即将它自己偏移到屏幕上。 无所谓,谢谢你的提示:)。 –