如何立即渲染JPopupMenu?

时间:2016-08-14 14:22:41

标签: java swing scala jpopupmenu

我正在实施一款游戏,玩家可以通过右键点击游戏板并从弹出菜单中选择其中一个来放置一块。在"热门座位"模式,两个玩家都使用相同的UI,因此显示了不同的菜单实例。

问题在于调用JMenuItem.show方法会导致首先呈现错误的菜单,然后快速替换为正确的菜单(您可以判断,因为菜单条目中使用的图标对于每个玩家具有不同的背景颜色)

我可以在调用Thread.sleep(1000)后立即添加show来加剧问题。然后在右键单击时,我会看到之前显示的其他播放器的菜单(或在第一次调用时只有正确大小的背景)一秒钟,然后刷新菜单,然后呈现正确的片段。

有没有办法立即呈现正确的菜单?

不确定这是否很重要,但repaint分支中的点击处理回调中无法调用isPopupTrigger

编辑:在Scala中添加示例

import java.awt.event._
import javax.swing._

object MenuDemo extends App {
  val frame = new JFrame()
  frame.setTitle("Menu Demo")
  frame.setSize(600, 400)
  frame.setLocation(0, 0)
  frame.addWindowListener(new WindowAdapter {
    override def windowClosing(e: WindowEvent): Unit = System.exit(0)
  })

  var index = 0
  def tick() = index = (index + 1) % 2

  def makeMenuItem(i: Int) = {
    val menuItem = new JMenuItem("item in menu #" + i)
    menuItem.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = tick()
    })
    menuItem
  }

  def makeMenu(i: Int) = {
    val menu = new JPopupMenu()
    menu.add(makeMenuItem(i))
    menu
  }

  val menus: Seq[JPopupMenu] = Seq(0, 1).map(i => makeMenu(i))

  def showMenu(e: MouseEvent): Unit = {
    menus(index).show(e.getComponent, e.getX, e.getY)
    Thread.sleep(1000)
  }

  val panel = new JPanel()
  panel.add(new JLabel("right click me"))

  panel.addMouseListener(new MouseAdapter {
    override def mousePressed(e: MouseEvent): Unit = {
      if (e.isPopupTrigger) showMenu(e)
    }

    override def mouseReleased(e: MouseEvent): Unit = {
      if (e.isPopupTrigger) showMenu(e)
    }
  })

  frame.getContentPane.add(panel)
  frame.setVisible(true)
}

修改2

我只在Mac上看到此行为。在Windows上,延迟发生在菜单显示之前。

1 个答案:

答案 0 :(得分:0)

听起来调用show方法后可能会重新组织菜单项。例如,javax.swing.event.PopupMenuListener.popupMenuWillBecomeVisible可能会根据上下文重置菜单项。

如果是这种情况,你可以通过两个不同的弹出菜单实例来避免闪烁,并根据上下文在其中一个上调用show。

相关问题