【问题标题】:Java JTree valueChanged Event before MouseEventMouseEvent 之前的 Java JTree valueChanged 事件
【发布时间】:2009-09-23 22:09:05
【问题描述】:

情况就是这样,我有一个带有选项卡式窗格的 jFrame,在选项卡中我有几个 jTable 和一个 jTree。我希望能够根据用户是否使用 ctrl/shift + 单击而不是常规单击来链接表和树之间的选择。 (如果您按住 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 + 单击,我的计划是设置一个布尔标志,我可以在树选择侦听器实现的 valueChanged(TreeSelectionEvent e) 期间检查该标志。 我希望能够在 valueChanged TreeSelectionEvents 之前处理鼠标事件,但问题是我在 valueChanged TreeSelection 事件之后收到鼠标事件。这对我来说似乎很奇怪,我在鼠标按下事件触发之前收到了选择更改,而选择更改实际上是由按下鼠标发起的。 (我已经同步了布尔标志设置,具有讽刺意味的是,这有助于突出事件的错误顺序。)

我已经尝试过添加 keyListener 之类的替代方法,但是当焦点位于单独的帧上时这不起作用,当用户按住 ctrl 然后单击 jTree 导致它同时接收到聚焦并触发任何 valueChanged 选择事件。

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

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

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

感谢到目前为止的帮助。

--EDIT2-- @ykaganovich

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

【问题讨论】:

  • 您是否尝试像使用表中的第一列一样使用树,并尝试在树和表组件中进行选择,就好像它们是一个一样?

标签: java jtree


【解决方案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);
  }
}

然后在你的监听器中检查 instanceof ChainedSelectionEvent

编辑

实际上,我认为正确的方法是实现您自己的 TreeSelectionModel,并在那里覆盖 fireValueChanged。假设setSelectionPath(s) 方法意味着一个新的选择,而add/removeSelectionPath(s) 意味着链接,你可以清楚地区分这两者。我不喜欢明确地听键盘或鼠标事件,因为改变选择的方法不止一种(例如,如果有人按住 SHIFT 并按下向下箭头,您将不会收到鼠标事件)。

【讨论】:

  • 我想我在这里仍然会遇到同样的问题,因为事件发生乱序而无法确定是否应该链接选择。谁控制 fireValueChanged 的​​调用?树本身?如果我不需要的话,我不想完全重写 jTree,尽管我已经把它搞砸了,添加了拖放支持。嗯......我想我可以在我的树中覆盖它,在那里实现一个 MouseListener,并且只调用这个方法作为鼠标事件的结果,但是分支折叠/展开的选择变得更加棘手......我想我讨厌jTrees :)
  • 我认为这应该可行。 JTree 将调用 fireValueChanged 以响应选择。我认为您永远不必明确地处理 MouseEvents。
  • 我需要处理 MouseEvents,因为这是我知道用户是否在按住 shift 或 ctrl 按钮时添加/删除某些内容的唯一方法。这是我对何时链接某物的定义。我同意它不干净,但我可以让 KeyListener 基本上做同样的事情来捕获这些事件并做出响应。对于我何时链接或不链接的定义,我想我需要捕获用户可以修改选择的所有方式,并在允许选择更改触发之前获得一些关于正在发生的事情的上下文。感谢您的帮助。
【解决方案2】:

您可以在树选择事件之前或之后获得鼠标事件。最好不要依赖这样的命令。原因是树选择事件是响应鼠标事件引起的。该鼠标事件侦听器是在您的侦听器之前还是之后调用的?也可以。

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

【讨论】:

    【解决方案3】:

    这里的关键是要了解 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,然后在最后一行替换为new MyMouseHandler(tree.getUI())...这里的“nTFSelf”只是对正在编写所有这些的代码的“this”对象...

    【讨论】:

      猜你喜欢
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多