Java:双击时忽略单击?

plicqrtu  于 2023-01-19  发布在  Java
关注(0)|答案(6)|浏览(130)

有谁能想出一个好办法来忽略Java中双击所带来的单击?
我希望每一个都有不同的行为,这样:

  • 单击在单击点上绘制十字光标
  • 双击在屏幕上选择一个对象,但是在点击点上画十字线

......有谁能想出一个办法来做到这一点吗?也许是某种计时器设置?一个想法赞赏:-)
......是的,我知道我犯了一个最令人发指的可用性/UI错误。

    • 编辑#2:**

即使这样做的延迟,由于计时器是疯狂的-我放弃这个解决方案,并使用中键选择,而不是双击...

    • 编辑:**

谢谢cgull-这是我能够想出给你的确认,有没有简单的方法来做到这一点(注意,如果我设置计时器〈200奇数赛车之间的点击和计时器,但只要我设置为一个值〉200的事情工作只是桃色):

public void mouseClicked(MouseEvent e) {
    System.out.println( "Click at (" + e.getX() + ":" + e.getY() + ")" );
    if (e.getClickCount() == 2) {  
        System.out.println( "  and it's a double click!");
        wasDoubleClick = true;
    }else{
        Integer timerinterval = (Integer) 
          Toolkit.getDefaultToolkit().getDesktopProperty(
                      "awt.multiClickInterval");
        timer = new Timer(timerinterval.intValue(), new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                if (wasDoubleClick) {
                    wasDoubleClick = false; // reset flag
                } else {
                    System.out.println( "  and it's a simple click!");
                }
            }    
        });
        timer.setRepeats(false);
        timer.start();
    }
}
qgelzfjb

qgelzfjb1#

实际上,您需要在MouseAdapter的重写mouseClicked()方法中设置一个Timer来检测两次点击之间的时间间隔。默认间隔(ms)可以通过查询Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval")找到。如果在计时器到期之前检测到另一次鼠标点击,则您可以双击,否则一旦计时器到期,您可以处理单击。

s8vozzvw

s8vozzvw2#

实际上,我认为有一个更简单的解决方案(使用InputEvent的getWhen()方法):

class DCListener extends MouseAdapter{

    private long maxTimeBetweenClicks; // in millis
    private long firstClickTime=0;
    private Runnable eventHandler;

    public DCListener(long maxTimeBetweenClicks,Runnable eventHandler){
        this.maxTimeBetweenClicks=maxTimeBetweenClicks;
        this.eventHandler=eventHandler;
    }

    public void mouseClicked(MouseEvent e){

        if((e.getWhen()-firstClickTime)<=maxTimeBetweenClicks){
            firstClickTime=0; // 3 clicks are not 2 double clicks
            eventHandler.run();
        }else{
            firstClickTime=e.getWhen();
        }

    }
}
gv8xihay

gv8xihay3#

您是否已经尝试过实现MouseListener接口?
我认为MouseEvent有一个点击计数方法(或属性)来知道这一点。
我打赌你已经经历过了,那么你面临的问题是什么?
也许你能做的就是用一个线程或其他东西来编码单击和双击之间的时间间隔。
因此,只有在300毫秒内没有发出另一次点击时,单击才有效。(可配置)
其理念是:

public void listen for the single click() 
    if (  in x time there has not been another click  ) 
    then 
        we have a single click
        proceed with your single click handling
    else 
        we have a double click
       proceed with your double click handling

或者类似的东西。

xuo3flqw

xuo3flqw4#

替代解决方案:
在我找到这个问题的解决方案之前我就想通了。想法是一样的,使用计时器,虽然更复杂:)。
使用SwingWorker

class BackgroundClickHandler extends SwingWorker<Integer, Integer> {
  @Override
  protected Integer doInBackground() throws Exception {
    Thread.sleep(200);
    // Do what you want with single click
    return 0;
  }

}

mouseClicked()方法中,您可以执行以下操作:

if (event.getClickCount() == 1) {
  // We create a new instance everytime since
  // the execute() method is designed to be executed once
  clickHandler = new BackgroundClickHandler();

  try {
    clickHandler.execute();
  } catch(Exception e) {
    writer.println("Here!");
  }
}

if (event.getClickCount() == 2) {
  clickHandler.cancel(true);

  //Do what you want with double click
}

我希望它能有用。

8cdiaqws

8cdiaqws5#

多亏了这个线程,我才做出了这个类似的解决方案,这是我想象的方式。它让一个Timer线程(其中的单击事件被安排为200毫秒的延迟)一直保持活动状态--这可能会让一些人感到不安,但毕竟启动一个线程是昂贵的,不是吗?
最后一次TimerTask的跟踪被保留,如果双击到达,则调用它的cancel()方法。如果双击在200 ms内到达,则取消它的单击,如果晚了,则没有效果。
我使用JavaFX,但这应该不重要。核心的东西是X1 M3 N1 X和X1 M4 N1 X。

import java.util.Timer;
import java.util.TimerTask;
import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.MouseButton;

class SomeController {
    private static final long MAX_MULTICLICK_INTERVAL = 200; //the milliseconds delay
    private final Timer singleLeftClickTimer = new Timer(true); //isDeamon = true, will be terminated with the rest of the app
    private TimerTask lastSingleClickTask;

    private void onMouseClickedFiltered(MouseEvent event) {
        //TODO process clicks
        //For the primary button you get only single clicks that were not followed by double clicks within 200ms
        //Double clicks and all clicks of other buttons go through unchanged
    }

    @FXML
    private void onMouseClicked(MouseEvent event) {
        if (event.getButton() != MouseButton.PRIMARY) {
            onMouseClickedFiltered(event);
        } else if (event.getClickCount() == 2) {
            lastSingleClickTask.cancel(); //if 200ms passed from associated single click, this will have no effect
            onMouseClickedFiltered(event);
        } else if (event.getClickCount() == 1) {
            lastSingleClickTask = new TimerTask() {
                @Override
                public void run() {
                    onMouseClickedFiltered(event);
                }
            };
            singleLeftClickTimer.schedule(lastSingleClickTask, MAX_MULTICLICK_INTERVAL);
        } // else: might swallow primary button clicks with clickCount outside 1 and 2 which is ok for me
    }
}
ulydmbyx

ulydmbyx6#

在查找这个问题的答案时,我正在考虑一个不同的解决方案,但没有找到,所以我分享了我的想法:
其他解决方案在单击处理中引入的延迟有点痛苦,因为您会得到这种延迟的响应。然而,这些解决方案是最容易实现的,并且不会打扰其余的代码。
另一种选择是:

单击可产生的所有事件都是可撤消的,并且在关联的双击事件到达时撤消

实现撤销是一个有趣的主题,但为了简单起见,我将给予一个非常基本的例子:

import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;

class SomeController {

    private static final long MAX_MULTICLICK_INTERVAL = 200; //the milliseconds delay
    private long lastSingleClickTime = 0;

    private int singleClickCounter = 0, doubleClickCounter = 0;

    private void singleClick(MouseEvent event) {
        singleClickCounter++;
    }

    private void undoSingleClick(MouseEvent event) {
        singleClickCounter--;
    }

    private void doubleClick(MouseEvent event) {
        doubleClickCounter++;
    }

    @FXML
    private void onMouseClicked(MouseEvent event) {
        if (event.getClickCount() == 2) {
            if (System.currentTimeMillis() <= lastSingleClickTime + MAX_MULTICLICK_INTERVAL) {
                undoSingleClick(event);
                lastSingleClickTime = 0; //if another double-click arrived we don't want to undo anything
            }
            doubleClick(event);
        } else if (event.getClickCount() == 1) {
            lastSingleClickTime = System.currentTimeMillis(); //in AWT use the event.getWhen() method instead
            singleClick(event);
        } // else: might swallow button clicks with clickCount outside 1 and 2 which is ok for me
        System.out.printf("Single clicks: %d, double clicks: %d\n", singleClickCounter, doubleClickCounter);
    }
}

注意,这里主要、次要和中间按钮事件是混合的,您应该跟踪每个按钮的lastSingleClickTime,或者将处理仅限于主要按钮,因为它通常是唯一使用双击的按钮。
对于一个实现撤销的数据模型,我们会记住单击触发的Action(假设它是一个类,具有run()undo()方法,执行相反的操作),并在双击事件到达时在Action示例上调用.undo()

相关问题