1

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

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 +单击在选择已被修改后发生的帖子。我需要实现一个 TreeSelectionListener 来做到这一点,但只获得一个 valueChanged(TreeSelectionEvent) 来实现更改。我添加了一个 mouseListener 来监听 ctrl+clicks 和 shift+clicks,但显然事件并不总是以相同的顺序发生.. 至少到目前为止我在 mousePressed 事件之前收到 valueChanged 事件,所以检查是否是 ctrl +单击在选择已被修改后发生的帖子。我需要实现一个 TreeSelectionListener 来做到这一点,但只获得一个 valueChanged(TreeSelectionEvent) 来实现更改。我添加了一个 mouseListener 来监听 ctrl+clicks 和 shift+clicks,但显然事件并不总是以相同的顺序发生.. 至少到目前为止我在 mousePressed 事件之前收到 valueChanged 事件,所以检查是否是 ctrl +单击在选择已被修改后发生的帖子。

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

感谢你目前的帮助。

--EDIT2-- @ykaganovich

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

4

3 回答 3

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 并按下向下箭头,您将不会收到鼠标事件)。

于 2009-09-24T06:12:17.830 回答
1

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

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

于 2009-09-24T03:00:08.497 回答
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,然后在最后一行替换为 new MyMouseHandler(tree.getUI())...这里的“nTFSelf”只是对“this " 正在编写所有这些的代码的对象...

于 2012-02-29T18:38:37.703 回答