所以,我想对JFrame
中的某些组件进行Z排序。
public class aBLUEBox extends JPanel{
int xPos = 19;
int yPos = 20;
int width = 10;
int height = 80;
public void paintBox(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(xPos,yPos,width,height);
}
}
public class CreateWindow extends JFrame{
CreateWindow(){
this.setTitle("Layering Test");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(1920/2,1080/2);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setVisible(true);
}
}
public class LayerMain {
CreateWindow window;
static aBLUEBox BLUEBox;
static aREDBox REDBox; //A Different Component just like aBLUEBox, but with an altered PaintBox() method which paints a red box instead of a blue one.
PanelRenderer RendererP;
LayerMain(){
BLUEBox = new aBLUEBox();
REDBox = new aREDBox();
RendererP = new PanelRenderer(); //holds the PaintComponent Method. Class for this is shown below.
window = new CreateWindow();
window.add(BLUEBox);
window.add(REDBox);
window.setComponentZOrder(BLUEBox, 0);
window.setComponentZOrder(REDBox, 0); //puts red on 0, moving blue up to 1.
//So now, BLUEBox's Z-order is 1, thus BLUEBox is on top of REDBox.
System.out.println("Z-order of blue = " + window.getComponentZOrder(BLUEBox)); //Prints 1
System.out.println("Z-order of Red = " + window.getComponentZOrder(REDBox)); //Prints 0
window.add(RendererP);
RendererP.repaint(); //Should Paint both box's.
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new LayerMain();
}
});
}
}
然后,我想使用repaint()
调用来渲染那些组件。
public class PanelRenderer extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
//JPanels:
LayerMain.BLUEBox.paintBox(g); //Paints Blue first, not that it should matter.
LayerMain.REDBox.paintBox(g); //Paints Red Second, not that it should matter.
System.out.println("PaintComponent invoked.");
}
}
应该在顶部/下方呈现的内容应与框架中组件的Z-index相对应。(例如,索引为1的组件应在组件的顶部呈现索引0)
但是,当将渲染器(JPanel
)添加到窗口(JFrame
)并调用paintComponent
时,什么也没有发生。从字面上看,没有油漆。
注释掉主类中的Z顺序代码,以便至少可以进行某些绘制,但是在蓝色的顶部绘制红色(因为在PaintComponent方法中,最后绘制红色,因此绘制在顶部),不是我想要的。
//window.setComponentZOrder(BLUEBox, 0);
//window.setComponentZOrder(REDBox, 0); //puts red on 0, moving blue up to 1.
为什么组件在paintComponent
中以它们被调用的顺序显示而不在JFrame
中被设置为它们的顺序显示?
import java.awt.*;
import javax.swing.*;
public class LayerMain {
CreateWindow window;
static ColoredBox blueBox;
//A Different Component just like aBLUEBox, but with an altered
// PaintBox() method which paints a red box instead of a blue one.
static ColoredBox redBox;
PanelRenderer rendererP;
LayerMain(){
blueBox = new ColoredBox(Color.BLUE);
redBox = new ColoredBox(Color.RED);
//holds the PaintComponent Method. Class for this is shown below.
rendererP = new PanelRenderer();
window = new CreateWindow();
window.add(blueBox);
window.add(redBox);
window.setComponentZOrder(blueBox, 0);
window.setComponentZOrder(redBox, 0); //puts red on 0, moving blue up to 1.
//So now, blueBox's Z-order is 1, thus blueBox is on top of redBox.
System.out.println("Z-order of blue = " + window.getComponentZOrder(blueBox)); //Prints 1
System.out.println("Z-order of Red = " + window.getComponentZOrder(redBox)); //Prints 0
window.add(rendererP);
rendererP.repaint(); //Should Paint both box's.
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new LayerMain();
});
}
}
class PanelRenderer extends JPanel{
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//JPanels:
LayerMain.blueBox.paintBox(g); //Paints Blue first, not that it should matter.
LayerMain.redBox.paintBox(g); //Paints Red Second, not that it should matter.
System.out.println("PaintComponent invoked.");
}
}
class CreateWindow extends JFrame{
CreateWindow(){
this.setTitle("Layering Test");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(1920/2,1080/2);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setVisible(true);
}
}
class ColoredBox extends JPanel {
int xPos = 19;
int yPos = 20;
int width = 10;
int height = 80;
Color color;
ColoredBox(Color color) {
super();
this.color = color;
}
public void paintBox(Graphics g){
g.setColor(color);
g.fillRect(xPos,yPos,width,height);
}
}
好,不。这绝对不是您应该尝试执行自定义绘制或使用自定义组件的方式。您无需为组件的渲染负责,因此PanelRenderer
毫无意义,也不应以这种方式真正使用static
,因为这只是懒惰且容易出错。
要么将其设为100%自定义绘画,要么使其面向100%的组件,而不是两者兼具
为什么组件按在PaintComponent中调用的顺序显示,而不按在JFrame中设置为的顺序显示?
因为您不负责绘制组件,并且弄乱了系统
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel blueBox;
private JPanel redBox;
private JPanel top, bottom;
public TestPane() {
blueBox = makeBox(Color.BLUE);
redBox = makeBox(Color.RED);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
// Filler
add(emptyBox(), gbc);
gbc.gridwidth = 2;
gbc.gridheight = 2;
gbc.fill = GridBagConstraints.BOTH;
add(blueBox, gbc);
gbc.gridx++;
gbc.gridy++;
add(redBox, gbc);
// Filler
gbc.gridx++;
gbc.gridy++;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.fill = GridBagConstraints.NONE;
add(emptyBox(), gbc);
JButton flip = new JButton("Flip");
flip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setComponentZOrder(bottom, 0);
JPanel temp = top;
top = bottom;
bottom = temp;
repaint();
}
});
gbc.gridx = 0;
gbc.gridy = 4;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(flip, gbc);
top = blueBox;
bottom = redBox;
}
protected JPanel emptyBox() {
JPanel box = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
};
box.setOpaque(false);
return box;
}
protected JPanel makeBox(Color color) {
JPanel box = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
box.setBackground(color);
return box;
}
}
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Box> boxes = new ArrayList<Box>(2);
public TestPane() {
boxes.add(new Box(Color.BLUE, 0, 0));
boxes.add(new Box(Color.RED, 50, 50));
setLayout(new BorderLayout());
JButton flip = new JButton("Flip");
flip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Ok, this is a cheat as I only have to boxes,
// if you had more, you'd need to move the box you
// higher in the rendering order closer to the end
// of the list
Collections.reverse(boxes);
repaint();
}
});
add(flip, BorderLayout.SOUTH);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Cheat, I should looping over the box array to calculate the
// area the boxes actuall occupy
int x = (getWidth() - 150) / 2;
int y = (getHeight() - 150) / 2;
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(x, y);
for (Box box : boxes) {
box.paint(g2d);
x += 50;
y += 50;
}
g2d.dispose();
}
}
public class Box {
private Color color;
private int x, y;
public Box(Color color, int x, int y) {
this.color = color;
this.x = x;
this.y = y;
}
public void paint(Graphics2D g2d) {
g2d.setColor(color);
g2d.fillRect(x, y, 100, 100);
}
}
}