使用计时器实现长按

时间:2013-11-27 11:17:29

标签: java swing timer

该程序基本上是拖放JPanel。我想实现长按以选择JPanel,并在少数教程中建议使用计时器。因此,我尝试使用计时器1000毫秒来选择一个JPanel,但它只在首选方式工作一次,但有一些闪烁的JPanel,我不明白为什么。它以后无法识别鼠标按下的功能。另一个问题是,当点击JPanel时,面板开始无意中被移除。实际上,当点击JPanel时没有任何事情发生,因为我没有为Clicked函数写任何内容。 请提供一些建议,以消除上述问题 提前谢谢。

package swappaneleg;

import java.awt.Color;
import java.awt.Component;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.TimerTask;
import javax.swing.*;


public class SwapPanelEg extends JPanel{
private static final long serialVersionUID = 1594039652438249918L;
private static final int PREF_W = 400;
private static final int PREF_H = 400;
private static final int MAX_COLUMN_PANELS = 8;
private JPanel columnPanelsHolder = new JPanel();

public SwapPanelEg(){
  columnPanelsHolder.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

  for (int i = 0; i < MAX_COLUMN_PANELS; i++) {
     int number = i + 1;
     int width = 20 + i * 3;
     int height = PREF_H - 30;
     columnPanelsHolder.add(new ColumnPanel(number, width, height));
  }

  MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
  columnPanelsHolder.addMouseListener(myMouseAdapter);
  columnPanelsHolder.addMouseMotionListener(myMouseAdapter);

  setLayout(new GridBagLayout());
  add(columnPanelsHolder);
}

@Override
public Dimension getPreferredSize() {
  return new Dimension(PREF_W, PREF_H);
}

private class MyMouseAdapter extends MouseAdapter {
private JComponent selectedPanel;
private Point deltaLocation;
private JPanel placeHolder = new JPanel();
private JComponent glassPane;
        java.util.Timer t;

  @Override
  public void mousePressed(final MouseEvent evt) {
     if (evt.getButton() != MouseEvent.BUTTON1) {
        return;
     }

     if(t == null) {
       t = new java.util.Timer();
     }
     t.schedule(new TimerTask() {
     public void run() {
         JPanel source = (JPanel) evt.getSource();
         selectedPanel = (JComponent) source.getComponentAt(evt.getPoint());

         if (selectedPanel == null) {
         return;
         }

         if (selectedPanel == source) {
         selectedPanel = null;
         return;
         }

         glassPane = (JComponent) SwingUtilities.getRootPane(source).getGlassPane();
         glassPane.setVisible(true);
         Point glassPaneOnScreen = glassPane.getLocationOnScreen();
         glassPane.setLayout(null);
         Point ptOnScreen = evt.getLocationOnScreen();
         Point panelLocOnScreen = selectedPanel.getLocationOnScreen();

         int deltaX = ptOnScreen.x + glassPaneOnScreen.x - panelLocOnScreen.x;
         int deltaY = ptOnScreen.y + glassPaneOnScreen.y - panelLocOnScreen.y;

         deltaLocation = new Point(deltaX, deltaY);

         Component[] allComps = source.getComponents();
         for (Component component : allComps) {

         if (component == selectedPanel) {
           placeHolder.setPreferredSize(selectedPanel.getPreferredSize());
           source.add(placeHolder);
           selectedPanel.setSize(selectedPanel.getPreferredSize());

           int x = ptOnScreen.x - deltaLocation.x;
           int y = ptOnScreen.y - deltaLocation.y;
           selectedPanel.setLocation(x, y);
           glassPane.add(selectedPanel);
           repaint();

         } 
         else {
           source.add(component);
           repaint();
         }
         }

         }
         },1000,500);

         revalidate();               
         repaint();
  }

  @Override
  public void mouseDragged(MouseEvent evt) {

     if (selectedPanel != null) {
        Point ptOnScreen = evt.getLocationOnScreen();

        int x = ptOnScreen.x - deltaLocation.x;
        int y = ptOnScreen.y - deltaLocation.y;
        selectedPanel.setLocation(x, y);
        selectedPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        selectedPanel.setOpaque(false);
        repaint();
         if(t != null)
                {
                    t.cancel();
                    t = null;
                }

     }


  }

  @Override
  public void mouseReleased(MouseEvent evt) {
     if (evt.getButton() != MouseEvent.BUTTON1) {
        return;
     }



     if (selectedPanel == null) {
        return;
     }

     JComponent source = (JComponent) evt.getSource();

     Component[] allComps = source.getComponents();
     JPanel overComponent = (JPanel) source.getComponentAt(evt
           .getPoint());



     if (overComponent != null && overComponent != placeHolder
           && overComponent != source) {
        for (Component component : allComps) {

             if (component == overComponent) {

                 source.add(overComponent);
                 source.add(selectedPanel);
                 source.remove(placeHolder);
              selectedPanel.setOpaque(true);
              selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));


            }
             else {
              source.add(component);
              source.remove(placeHolder);
              selectedPanel.setOpaque(true);
              selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));

           }
        }
     }

     else {
        for (Component component : allComps) {
            if (component == placeHolder) {
               source.add(selectedPanel);
               source.remove(placeHolder);
              } 
            else {
                source.remove(placeHolder);
              source.add(component);
              selectedPanel.setOpaque(true);
              selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));

           }
        }
     }  
     revalidate();
     repaint();
     selectedPanel = null;
     if(t != null)
                {
                    t.cancel();
                    t = null;
                }

  }
}


private static void createAndShowGui() {
  SwapPanelEg mainPanel = new SwapPanelEg();

  JFrame frame = new JFrame("SwapPanelEg");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.getContentPane().add(mainPanel);
  frame.pack();
  frame.setLocationByPlatform(true);
  frame.setVisible(true);
}

public static void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable() {
     public void run() {
        createAndShowGui();
     }
  });
}
}
class ColumnPanel extends JPanel {
private static final long serialVersionUID = 5366233209639059032L;
private int number;
private int prefWidth;
private int prefHeight;

public ColumnPanel(int number, int prefWidth, int prefHeight) {
  setName("ColumnPanel " + number);
  this.number = number;
  this.prefWidth = prefWidth;
  this.prefHeight = prefHeight;

  add(new JLabel(String.valueOf(number)));

  setBackground(Color.cyan);
}

@Override
public Dimension getPreferredSize() {
  return new Dimension(prefWidth, prefHeight);
}

public int getNumber() {
  return number;
}

}

2 个答案:

答案 0 :(得分:2)

我认为更好的解决方案是:

  • 首次按下鼠标时创建SwingTimer
  • 让它等一下,跟踪鼠标是否被释放或离开面板。
  • 如果在SwingTimer结束时没有释放且鼠标没有离开面板,则处理您的任务。

SwingTimer教程:http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

答案 1 :(得分:0)

建议的计时器代码:

private class InnerTimer implements Runnable {
    public boolean expired;
    public boolean cancelled;
    private long end;
    public void run() {
        expired = cancelled = false;
        end = System.currentTimeMillis() + 1000;
        while ( ! cancelled && ! expired) {
            if (System.currentTimeMillis() >= end) {
               expired = true;
            } else {
               try { Thread.sleep(100); } 
               catch(InterruptedException e) {/* no big deal */}
            }
        }
    }
}

在每个需要监听长按的面板中保留InnerTimer innerTimer = new InnerTimer();。在此类面板上按下鼠标时,请在单独的线程中启动此计时器:(new Thread(innerTimer)).start()。如果鼠标离开面板或被释放,请取消计时器:innerTimer.cancelled = true;。如果移动鼠标,请检查计时器是否自然过期:if (innerTimer.expired);如果是,则用户已成功长按此面板。如果它没有过期,那么只需取消定时器。

请注意,此代码有点快速和肮脏。然而,它很短且相对有效(除了它创建线程,但这些大部分都是睡眠很多,并且在1s之后无论如何都被丢弃)。使用Swing Timers可以避免线程创建开销,但更加冗长。