不使用 JLayeredPane 将 jcomponent 移到后面
Move jcomponent to back without using JLayeredPane
我写了一个 DragAndDrop MouseListener。
组件 A 是组件 B 后面的“背景”图像。两者都位于 JPanel 上。
我已将图像设为可拖动。但是,我希望图像在拖动时保持在组件 B 后面。
但是,每次我拖动图像时,我想 Java 都会给它焦点或其他东西,所以它会被带到最前面。
有什么方法可以让图片在拖的时候一直在后面吗?
我知道我可以使用 JLayeredPane
并在每次拖动时使用 moveToBack
方法,但我宁愿不使用 JLayeredPane 而只使用 JPanel。 JPanel 是否有 moveToBack
等效项?
或者有没有办法让组件保留当前层(也许“不获得焦点”)以便我可以将它拖到当前层中?
这里有一个例子
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class OverlapTester extends JFrame {
public static final long serialVersionUID = 172L;
public static void main(String[] args) {
OverlapTester frame = new OverlapTester();
frame.initialize();
}
public void initialize() {
setLayout(null);
JButton bottom = new JButton("bottom");
JButton top = new JButton("top");
bottom.setBounds(0,0,100,100);
top.setBounds(0,0,50,50);
add(top);
add(bottom);
int bottomZOrder = 0;
bottom.addMouseListener(new MouseListener(){
@Override
public void mouseEntered(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseExited(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseReleased(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mousePressed(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseClicked(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
bottom.addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseMoved(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
}
Component A is a "background" image that is behind Component B. Both are located on a JPanel.
Swing 组件是根据 ZOrder
绘制的。最高的ZOrder
先画
ZOrder
被分配为一个组件被添加到面板。所以添加的第一个分量给出ZOrder 0
,第二个分量ZOrder 1
.
所以最后将你的“背景”图像添加到面板,它总是具有最高的 ZOrder
这意味着它首先被绘制,因此其他组件将被绘制在它上面。
例如:
panel.add(someOtherComponent);
panel.add(background);
或者您可以使用:
Container.setComponentZOrder(...)
添加组件后动态更改 ZOrder
的方法。
编辑:
我提供的答案是 either/or 解决方案。您只需要选择一种方法。
您正确实施了第一种方法,即最后添加“背景”组件。所以没有必要再玩 ZOrder。当 ZOrder 将保持固定时,这种方法非常有效。
第二种方法是当您希望 ZOrder 动态更改时,比如当您有多个组件并且您希望在与每个组件交互时更改它。但是,您错误地实施了这种方法。您对 ZOrder 使用了“0”,这意味着该组件将始终最后绘制,因此位于任何其他组件之上。
在您当前的示例中,无需动态更改 ZOrder,因此您可以删除所有相关代码。
As you can see the bottom button is consistently being added to the forefront
Swing 绘画经过优化以假设组件不重叠。
但是,对于 JButton,当您将鼠标悬停在按钮上以重新绘制边框时,它具有自动重新绘制逻辑。因此,当按钮被重新绘制时,它仍然绘制在另一个组件之上。
所以你需要告诉Swing不要优化绘画。因此,当一个组件被重新绘制时,它们将在重叠时全部被重新绘制。您可以通过覆盖 isOptimizedDrawingEnabled(...)
方法来执行此操作,如下所示:
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.*;
public class OverlapTester extends JFrame {
public static void main(String[] args) {
OverlapTester frame = new OverlapTester();
frame.initialize();
}
public void initialize() {
JPanel contentPane = new JPanel(null)
{
@Override
public boolean isOptimizedDrawingEnabled()
{
return false;
}
};
add(contentPane);
// setLayout(null);
JButton bottom = new JButton("bottom");
JButton top = new JButton("top");
bottom.setBounds(0,0,100,100);
top.setBounds(0,0,50,50);
// add(top);
// add(bottom);
contentPane.add(top);
contentPane.add(bottom);
// int bottomZOrder = 0;
int bottomZOrder = 1;
bottom.addMouseListener(new MouseListener(){
@Override
public void mouseEntered(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseExited(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseReleased(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mousePressed(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseClicked(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
bottom.addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseMoved(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
}
我写了一个 DragAndDrop MouseListener。
组件 A 是组件 B 后面的“背景”图像。两者都位于 JPanel 上。
我已将图像设为可拖动。但是,我希望图像在拖动时保持在组件 B 后面。
但是,每次我拖动图像时,我想 Java 都会给它焦点或其他东西,所以它会被带到最前面。
有什么方法可以让图片在拖的时候一直在后面吗?
我知道我可以使用 JLayeredPane
并在每次拖动时使用 moveToBack
方法,但我宁愿不使用 JLayeredPane 而只使用 JPanel。 JPanel 是否有 moveToBack
等效项?
或者有没有办法让组件保留当前层(也许“不获得焦点”)以便我可以将它拖到当前层中?
这里有一个例子
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class OverlapTester extends JFrame {
public static final long serialVersionUID = 172L;
public static void main(String[] args) {
OverlapTester frame = new OverlapTester();
frame.initialize();
}
public void initialize() {
setLayout(null);
JButton bottom = new JButton("bottom");
JButton top = new JButton("top");
bottom.setBounds(0,0,100,100);
top.setBounds(0,0,50,50);
add(top);
add(bottom);
int bottomZOrder = 0;
bottom.addMouseListener(new MouseListener(){
@Override
public void mouseEntered(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseExited(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseReleased(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mousePressed(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseClicked(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
bottom.addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseMoved(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
}
Component A is a "background" image that is behind Component B. Both are located on a JPanel.
Swing 组件是根据 ZOrder
绘制的。最高的ZOrder
先画
ZOrder
被分配为一个组件被添加到面板。所以添加的第一个分量给出ZOrder 0
,第二个分量ZOrder 1
.
所以最后将你的“背景”图像添加到面板,它总是具有最高的 ZOrder
这意味着它首先被绘制,因此其他组件将被绘制在它上面。
例如:
panel.add(someOtherComponent);
panel.add(background);
或者您可以使用:
Container.setComponentZOrder(...)
添加组件后动态更改 ZOrder
的方法。
编辑:
我提供的答案是 either/or 解决方案。您只需要选择一种方法。
您正确实施了第一种方法,即最后添加“背景”组件。所以没有必要再玩 ZOrder。当 ZOrder 将保持固定时,这种方法非常有效。
第二种方法是当您希望 ZOrder 动态更改时,比如当您有多个组件并且您希望在与每个组件交互时更改它。但是,您错误地实施了这种方法。您对 ZOrder 使用了“0”,这意味着该组件将始终最后绘制,因此位于任何其他组件之上。
在您当前的示例中,无需动态更改 ZOrder,因此您可以删除所有相关代码。
As you can see the bottom button is consistently being added to the forefront
Swing 绘画经过优化以假设组件不重叠。
但是,对于 JButton,当您将鼠标悬停在按钮上以重新绘制边框时,它具有自动重新绘制逻辑。因此,当按钮被重新绘制时,它仍然绘制在另一个组件之上。
所以你需要告诉Swing不要优化绘画。因此,当一个组件被重新绘制时,它们将在重叠时全部被重新绘制。您可以通过覆盖 isOptimizedDrawingEnabled(...)
方法来执行此操作,如下所示:
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.*;
public class OverlapTester extends JFrame {
public static void main(String[] args) {
OverlapTester frame = new OverlapTester();
frame.initialize();
}
public void initialize() {
JPanel contentPane = new JPanel(null)
{
@Override
public boolean isOptimizedDrawingEnabled()
{
return false;
}
};
add(contentPane);
// setLayout(null);
JButton bottom = new JButton("bottom");
JButton top = new JButton("top");
bottom.setBounds(0,0,100,100);
top.setBounds(0,0,50,50);
// add(top);
// add(bottom);
contentPane.add(top);
contentPane.add(bottom);
// int bottomZOrder = 0;
int bottomZOrder = 1;
bottom.addMouseListener(new MouseListener(){
@Override
public void mouseEntered(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseExited(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseReleased(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mousePressed(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseClicked(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
bottom.addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
@Override
public void mouseMoved(MouseEvent e) {
e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
}