【发布时间】:2019-02-06 22:01:44
【问题描述】:
我有一个 BVH 播放器,它有 9 个视图,它们在计时器上运行以对其进行动画处理,我试图在每个面板的顶部放置控件以单独控制变换操作。
这些按钮正在我的paintComponent 后面呈现,但有时可以单击。我还有一个 MouseListener 来调整骨架的变换,有时它可以工作。我可以发布听众,但我认为这并不重要。
我尝试了 graphics.dispose 和 graphics2d.dispose 的各种组合,并尝试更改 super.paintComponent(g) 的位置,结果很奇怪,但效果不佳。
下面是显示问题的视频。如果您仔细观察,当您将鼠标悬停在它们应该在的位置时,您会看到弹出的按钮。您还会看到,当我 g.dispose() 时,它在两个地方的按钮变得陌生,但只在一个地方单击(这不是它们最明显的地方)。
https://youtu.be/CyFpUlbFI1U
这是我的源代码:
public SkeletonPlayer(int camera, double scale, int rotLeftRight, int rotUpDown, double translateLeftRight, double translateUpDown) {
this.camera = camera;
this.scale = scale;
this.rotLeftRight = rotLeftRight;
this.rotUpDown = rotUpDown;
this.translateLeftRight = translateLeftRight;
this.translateUpDown = translateUpDown;
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.translate(getWidth() / 2, getHeight() / 2);
AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
at.rotate(Math.toRadians(90), Math.toRadians(90), Math.toRadians(90));
for (int n = 0; n < MainFrame.skeleton[camera].getNodes().size(); n++) {
Node node = MainFrame.skeleton[camera].getNodes().get(n);
int x1 = (int) (scale * node.getPosition().getX());
int y1 = (int) (-scale * node.getPosition().getY());
g2d.setColor(Color.RED);
g2d.fillOval((int) (x1 - 2), (int) (y1 - 2), 4, 4);
g2d.setColor(Color.BLACK);
//g2d.drawString(node.getName(), x1 + 10, y1);
for (Node child : node.getChildrens()) {
int x2 = (int) (scale * child.getPosition().getX());
int y2 = (int) (-scale * child.getPosition().getY());
g2d.drawLine(x1, y1, x2, y2);
}
}
int x1 = (int) (scale * groundPlane.rootNode.getPosition().getX());
int y1 = (int) (-scale * groundPlane.rootNode.getPosition().getY());
g2d.setColor(Color.BLACK);
g2d.fillOval((int) (x1 - 2), (int) (y1 - 2), 4, 4);
for (int n = 1; n < groundPlane.nodes.size(); n++) {
Node node = groundPlane.nodes.get(n);
int x2 = (int) (scale * node.getPosition().getX());
int y2 = (int) (-scale * node.getPosition().getY());
g2d.setColor(Color.BLACK);
g2d.fillOval((int) (x2 - 2), (int) (y2 - 2), 4, 4);
g2d.setColor(Color.GREEN);
g2d.drawLine(x1, y1, x2, y2);
//System.out.println("line:" + x1 + "," + y1 + " " + x2 + "," + y2);
}
}
};
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
panel.addMouseWheelListener(this);
MigLayout layout = new MigLayout(
"insets 10, gap 10, wrap", // Layout Constraints
"[fill,grow][fill,grow][fill,grow]", // Column constraints with default align
"[fill,grow][fill,grow][fill,grow]");
panel.setLayout(layout);
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
panel.add(new JButton("here"));
}
这是计时器:
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
update();
}
}, 0, (long) Math.round(motion.getFrameTime() * 1000));
private static void update() {
for (int i = 0; i < NUM_SKELETON_PLAYERS; i++) {
MainFrame.skeleton[i].setPose((int) frameIndex, i);
skeletonPlayers[i].groundPlane.setPose(i);
skeletonPlayers[i].panel.repaint();
}
//skeleton.setPose(null);
frameIndex += 1;
if (frameIndex > motion.getFrameSize() - 1) {
frameIndex = 0;
}
}
【问题讨论】:
-
首先,Swing 不是线程安全的,因此您不应该从事件调度线程之外对其进行更新。其次,您会看到
Graphics上下文的转换(平移和旋转),因为Graphics是一个共享上下文,您对其所做的任何更改都会影响之后绘制的任何其他组件。最好使用Graphics2D g2d = (Graphics2D) g.create();(完成后使用g2d.dispose()) -
我确实使用 Graphics2D... 请参阅发布的代码。我不知道你在调度线程之外更新是什么意思,你指的是定时器吗?我应该使用其他一些触发机制来计时绘图帧吗?
-
“我确实使用 Graphics2D... 请参考发布的代码” 但是,正如我所说,您正在更改上下文的状态,然后用于之后绘制所有其他组件,应用相同的转换,这将搞砸其他组件的渲染方式,这就是为什么我建议使用
Graphics#create来“复制”状态信息,所以你不要'不要搞砸原件。 “我应该使用其他触发机制来计时绘制帧吗?” - SwingTimer将是我的第一个建议 -
您还应该阅读文档,因为
at.rotate(Math.toRadians(90), Math.toRadians(90), Math.toRadians(90));没有意义
标签: java swing jpanel paintcomponent jcomponent