MouseEvent之前的Java JTree valueChanged事件

时间:2009-09-23 22:09:05

标签: java jtree

在这种情况下,我有一个带标签窗格的jFrame,在选项卡中我有几个jTable和一个jTree。我希望能够根据用户是使用ctrl / shift + click还是常规点击来链接表和树之间的选择。 (如果按住ctrl并单击第一个表/树,它会添加到整体选择中,如果使用常规单击,则会清除其他表/树中的选择)。目前我遇到了Java的jTree组件问题。我添加了一个TreeSelectionListener和一个带有实现两个接口的类的MouseListener,称之为MyBigListener; 即。

MyBigListener listener = new MyBigListener();
jTree1.addMouseListener( listener );
jTree1.addTreeSelectionListener( listener );

MyBigListener implements TreeSelectionListener, MouseListener {
  private boolean chained = false;
  public synchronized setChained(boolean ch){
    chained = ch;
  }
  public synchronized boolean isChained(){
    return chained
  }
  public void valueChanged(TreeSelectionEvent e){
    if(isChained()){ blah... }
  }

  public void mousePressed(MouseEvent e){
    setChained(e.isControlDown() || e.isShiftDown());
  }
}

我的计划是设置一个布尔标志,如果用户使用ctrl / shift + click,我可以在树选择监听器实现的valueChanged(TreeSelectionEvent e)期间检查。 我希望能够在valueChanged TreeSelectionEvents之前处理鼠标事件,但问题是我在valueChanged treeSelection事件之后收到鼠标事件。对我来说这似乎很奇怪,我在鼠标按下事件触发之前收到选择更改,当选择更改实际上是由鼠标按下时启动的。 (我已经同步了布尔标志设置,这有助于突出事件的错误顺序。)

我已经尝试过添加keyListener等替代方案,但是当焦点位于一个单独的框架上时这不起作用,当用户按住ctrl然后点击进入jTree使其同时接收到专注并解雇任何价值改变选择事件。

任何帮助将不胜感激,谢谢!

- 编辑 - @akf 我在选项卡窗格中有单独的jTable和jTree,它们用作节点图中数据的摘要/控制面板。我在选项卡窗格中使用这些组件来协调选择显示在单独的jFrame中的图形。每个表都可以像jTree一样适合它的选择。这是在棘手的窗格之间进行协调。到目前为止,这对jTable组件工作正常,因为我将鼠标事件的结果激活新的选择,我可以判断shift / ctrl按钮是否已关闭,制定我的新选择,并将其传递给父框架,该框架协调所有选择之间的选择窗格并将最终选择发送到图表。但是,父母需要知道它是否需要在窗格之间链接选择,或者压缩其他窗格。使用jTables它再次没问题,因为我点击了鼠标点击选择更改。 jTree更像是一个问题,因为我正在做一些强制选择。如果单击分支,则会强制所有叶子进入选择。我需要实现一个TreeSelectionListener来实现这一点,但只获得valueChanged(TreeSelectionEvent)来实现更改。我添加了一个mouseListener来监听ctrl +点击和shift +点击,但显然事件并不总是以相同的顺序发生..至少到目前为止我在mousePressed事件之前收到valueChanged事件,所以检查是否有ctrl +选择已被修改后点击发生的帖子。

现在,我正在发布一个挂起的选择更改,然后让MouseListener抓住它并将其发送到链中,但如果这些事件不能保证以相同的顺序发生,那么在某些时候它会失败。实施延迟器也让我误解了。

感谢您的帮助。

- EDIT2-- @ykaganovich

我认为重写fireValueChanged方法更接近正确的方法。根据我对哪些操作应该对其他组件进行“链式”选择的定义,我需要在valuChanged方法触发之前收集一些关于正在发生的事情的上下文。这基本上意味着在我可以通过谁触发它来定义它意味着什么的情况下自己调用它。即如果鼠标事件导致它并且ctrl关闭,则设置我需要设置(解释)然后触发。如果由于键盘事件而发生变化,请再次设置我需要设置的内容,然后触发。我不认为TreeSelectionModel是要走的路,因为我仍然不知道事件发生时的情况。我想这意味着我需要重写部分jTree来做这个,但我想我会看到它是怎么回事。感谢。

3 个答案:

答案 0 :(得分:1)

您可能会在树选择事件之前或之后收到鼠标事件。最好不要依赖这样的订单。原因是树选择事件是响应鼠标事件而引起的。是否在侦听器之前或之后调用了鼠标事件侦听器?可能是。

这种事情与PL& F的实施密切相关。

答案 1 :(得分:1)

不要这样做,而是覆盖JTree.fireValueChanged

尝试这样的事情(未经测试):

class ChainedSelectionEvent extends TreeSelectionEvent {
  ChainedSelectionEvent(TreeSelectionEvent e) {
    super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath);
  }
}

protected void fireValueChanged(TreeSelectionEvent e) {
  if(chained) { // figure out separately
      super.fireValueChanged(new ChainedSelectionEvent(e));
  } else {
      super.fireValueChanged(e);
  }
}

然后在监听器中检查实例的ChainedSelectionEvent

修改

实际上,我认为正确的方法是实现自己的TreeSelectionModel,并在那里覆盖fireValueChanged。假设setSelectionPath(s)方法暗示了一个新的选择,并且add/removeSelectionPath(s)意味着链接,你可以干净地区分这两个。我不喜欢明确地听键盘或鼠标事件,因为有多种方法可以更改选择(例如,如果有人按住SHIFT并按下向下箭头,则不会发生鼠标事件。)< / p>

答案 2 :(得分:0)

这里的关键是要了解JTree是否随BasicTreeUI.MouseHandler一起提供,请参阅javax.swing.plaf.basic.BasicTreeUI。

回答中心问题,“什么触发fireValueChanged”,答案是“这个鼠标处理程序”......当你去tree.getMouseListeners()时,它被证明是唯一的鼠标监听器。

所以你必须用你自己的版本替换这个默认的鼠标监听器......这有点棘手。我使用Jython,每个人都需要发现。但是,这段代码不应该太难转换成Java:

  from javax.swing.plaf.basic import BasicTreeUI      
  def makeMouseHandlerClass():
    class MouseHandlerClass( BasicTreeUI.MouseHandler ):
      def mousePressed( self, mouseEvent ):
        genLog.info( "mouse handler MOUSE PRESSED!" )
        nTFSelf.mousePressedStatus = True
        BasicTreeUI.MouseHandler.mousePressed( self, mouseEvent )
        nTFSelf.mousePressedStatus = False

    return MouseHandlerClass
  suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ]
  nTFSelf.taskTree.removeMouseListener( suppliedMouseHandler  ) 
  nTFSelf.taskTree.addMouseListener( makeMouseHandlerClass()( nTFSelf.taskTree.getUI() ))

...基本上等效的Java在这里将BasicTreeUI.MouseHandler扩展为MyMouseHandler,然后在最后一行替换为新的MyMouseHandler(tree.getUI())...“nTFSelf”这里仅仅是对代码的“this”对象,其中所有这些都是写的......