PaintComponent 的一些问题 [英] Some issues with paintComponent

查看:50
本文介绍了PaintComponent 的一些问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用paintComponent 绘制形状时遇到了一个不清楚的问题.

public class Shape extends JPanel {私人字符串形状;私有布尔值 isFill;私有整数 x;私人内部 y;私有整数宽度;私有整数高度;私人颜色颜色;公共形状(字符串形状,布尔值 isFill,int x,int y,int 宽度,int 高度,颜色颜色){this.shape = 形状;this.isFill = isFill;this.x = x;this.y = y;this.width = 宽度;this.height = 高度;this.color = 颜色;}@覆盖公共布尔等于(对象 O){if (O instanceof Shape){if (this.getWidth() == ((Shape) O).getWidth() && this.getHeight() == ((Shape) O).getHeight()){返回真;}}返回假;}@覆盖公共无效paintComponent(图形g){super.paintComponent(g);g.setColor(this.getColor());如果 (this.getShape().equals(Constants.IS_RECTANGLE)){如果 (this.isFill()){g.fillRect(this.getX(), this.getY(),this.getWidth(),this.getHeight());}别的{g.drawRect(this.getX(), this.getY(),this.getWidth(),this.getHeight());}}别的{如果 (this.isFill()){g.fillOval(this.getX(), this.getY(),this.getWidth(),this.getHeight());}别的{g.drawOval(this.getX(), this.getY(),this.getWidth(),this.getHeight());}}}公共无效drawShape(JPanel面板){panel.add(this);panel.setVisible(true);}

这是我的 Shape 类,我想将一些添加到面板中(使用 JPanel).

公共类 GuiManagement {公共 JFrame createScreen(){//创建屏幕JFrame frame = new JFrame();frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setTitle(Constants.APP_NAME);frame.setSize(Constants.SCREEN_WIDTH,Constants.SCREEN_HEIGHT);返回帧;}public JPanel createPanel(JFrame frame, int x, int y, int width, int height, String borderSpace){//创建一个面板,在屏幕中设置它的边界和方向JPanel 面板 = new JPanel();panel.setLayout(null);panel.setBounds(x,y,width,height);frame.add(panel, borderSpace);panel.setVisible(true);返回面板;}

这些是我创建和返回框架和面板的 2 个函数.

public static void main (String [] args){GuiManagement g = new GuiManagement();JFrame frame = g.createScreen();JPanel 面板 = g.createPanel(frame,0,0,800,800,BorderLayout.NORTH);panel.setBackground(Color.GREEN);Shape s = new Shape(Oval",true,40,40,100,100,Color.DARK_GRAY);s.drawShape(面板);frame.setLayout(new BorderLayout(30,30));frame.setVisible(true);}

这就是主类.现在,程序应该绘制一个简单的椭圆形,但是当我运行 main 函数时,看起来面板为绘制形状分配了正确的空间(框架的绿色部分是我创建的面板),但是绘制它只在那个空间的一小部分.我在下图中添加了一个问题示例.

您可以看到形状现在在 Shape 组件内偏移.

相反,您应该从 0x0 开始绘制,这将是 Shape 组件的上/左角.

我修改了 Shape 代码以使用...

if (this.isFill()) {g.fillOval(0, 0, this.getWidth(), this.getHeight());} 别的 {g.drawOval(0, 0, this.getWidth(), this.getHeight());}

它现在生成...

恕我直言,以这种方式使用组件是个坏主意.null 布局是出了名的难以管理,如果您只想绘制形状,那么纯自定义绘制路线通常更好/更易于管理.

这个想法基本上构建了一个组件,可以绘制任意数量的形状"对象

因为我喜欢从一个抽象"的概念开始,它可以建立起来,所以我从一个Shape的基本概念开始,它定义了所有Shape<的所有信息/code> 实现需要...

公共接口形状{公共矩形 getBounds();公共布尔 isFilled();公共颜色 getColor();公共无效油漆(Graphics2D g2d);}

然后我定义了一个 abstract 实现,它涵盖了核心/通用功能......

公共抽象类 AbstractShape 实现 Shape {私人矩形边界;私人布尔值填充;私人颜色颜色;public AbstractShape(矩形边界,布尔值填充,颜色颜色){this.bounds = 边界;this.fill = 填充;this.color = 颜色;}公共矩形 getBounds() {返回界限;}公共布尔 isFilled() {回填;}公共颜色 getColor() {返回颜色;}}

然后我定义了实际的实现,在这种情况下,我只做了OvalShape,但你可以有一个三角形、矩形、弧形和其他形状......

public class OvalShape extends AbstractShape {公共椭圆形(矩形边界,布尔值填充,颜色颜色){超级(边界,填充,颜色);}@覆盖公共无效油漆(Graphics2D g2d){g2d.setColor(this.getColor());矩形边界 = getBounds();如果(isFilled()){g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);} 别的 {g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);}}}

然后,我们需要一些方法来显示这些形状...

public class ShapeContainer extends JPanel {私人列表<形状>形状;公共形状容器(){形状 = 新的 ArrayList<>(25);}公共无效添加(形状形状){形状.添加(形状);重绘();}@覆盖公共维度 getPreferredSize() {返回新维度(200, 200);}@覆盖受保护的无效paintComponent(图形g){super.paintComponent(g);对于(形状形状:形状){Graphics2D g2d = (Graphics2D) g.create();shape.paint(g2d);g2d.dispose();}}}

这意味着,所有形状都在容器坐标上下文中工作,如果您想在轨道上添加新功能,您无需担心尝试翻译它们...

而且因为我知道这可能有点需要接受,一个可运行的例子......

import java.awt.Color;导入 java.awt.Dimension;导入 java.awt.Graphics;导入 java.awt.Graphics2D;导入 java.awt.Rectangle;导入 java.util.ArrayList;导入 java.util.List;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.SwingUtilities;公共类测试{公共静态无效主(字符串 [] args){新测试();}公共测试(){SwingUtilities.invokeLater(new Runnable() {@覆盖公共无效运行(){JFrame frame = new JFrame();Shape shape = new OvalShape(new Rectangle(25, 24, 50, 50), true, Color.RED);ShapeContainer 容器 = new ShapeContainer();容器.添加(形状);框架.添加(容器);框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共接口形状{公共矩形 getBounds();公共布尔 isFilled();公共颜色 getColor();公共无效油漆(Graphics2D g2d);}公共抽象类 AbstractShape 实现了 Shape {私人矩形边界;私人布尔值填充;私人颜色颜色;public AbstractShape(矩形边界,布尔值填充,颜色颜色){this.bounds = 边界;this.fill = 填充;this.color = 颜色;}公共矩形 getBounds() {返回界限;}公共布尔 isFilled() {回填;}公共颜色 getColor() {返回颜色;}}公共类 OvalShape 扩展 AbstractShape {公共椭圆形(矩形边界,布尔值填充,颜色颜色){超级(边界,填充,颜色);}@覆盖公共无效油漆(Graphics2D g2d){g2d.setColor(this.getColor());矩形边界 = getBounds();如果(isFilled()){g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);} 别的 {g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);}}}公共类 ShapeContainer 扩展 JPanel {私人列表<形状>形状;公共形状容器(){形状 = 新的 ArrayList<>(25);}公共无效添加(形状形状){形状.添加(形状);重绘();}@覆盖公共维度 getPreferredSize() {返回新维度(200, 200);}@覆盖受保护的无效paintComponent(图形g){super.paintComponent(g);对于(形状形状:形状){Graphics2D g2d = (Graphics2D) g.create();shape.paint(g2d);g2d.dispose();}}}}

I'm having an unclear problem with drawing shapes using paintComponent.

public class Shape extends JPanel {
private String shape;
private boolean isFill;
private int x;
private int y;
private int width;
private int height;
private Color color;

public Shape(String shape, boolean isFill, int x, int y, int width, int height, Color color) {
    this.shape = shape;
    this.isFill = isFill;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.color = color;
}
@Override
public boolean equals (Object O){
    if (O instanceof Shape){
        if (this.getWidth() == ((Shape) O).getWidth() && this.getHeight() == ((Shape) O).getHeight()){
            return true;
        }
    }
    return false;
}

@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.setColor(this.getColor());
    if (this.getShape().equals(Constants.IS_RECTANGLE)){
        if (this.isFill()){
            g.fillRect(this.getX(), this.getY(),this.getWidth(),this.getHeight());
        }
        else{
            g.drawRect(this.getX(), this.getY(),this.getWidth(),this.getHeight());
        }
    }
    else{
        if (this.isFill()){
            g.fillOval(this.getX(), this.getY(),this.getWidth(),this.getHeight());
        }
        else{
            g.drawOval(this.getX(), this.getY(),this.getWidth(),this.getHeight());
        }
    }
}

public void drawShape(JPanel panel){
    panel.add(this);
    panel.setVisible(true);
}

This is my Shape class, and I want to add some into a panel (using JPanel).

public class GuiManagement {

public JFrame createScreen(){
    // Creating the screen
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle(Constants.APP_NAME);
    frame.setSize(Constants.SCREEN_WIDTH,Constants.SCREEN_HEIGHT);
    return frame;
}

public JPanel createPanel(JFrame frame, int x, int y, int width, int height, String borderSpace){
    // Creates a panel, set its bounds and direction in the screen
    JPanel panel = new JPanel();
    panel.setLayout(null);
    panel.setBounds(x,y,width,height);
    frame.add(panel, borderSpace);
    panel.setVisible(true);
    return panel;
}

Those are my 2 functions that creates and returns a frame and panel.

public static void main (String [] args){
    GuiManagement g = new GuiManagement();
    JFrame frame = g.createScreen();
    JPanel panel = g.createPanel(frame,0,0,800,800,BorderLayout.NORTH);
    panel.setBackground(Color.GREEN);
    Shape s = new Shape("Oval",true,40,40,100,100,Color.DARK_GRAY);
    s.drawShape(panel);

    frame.setLayout(new BorderLayout(30,30));
    frame.setVisible(true);
}

And that's the main class. Now, the program should draw a simple oval, but when I'm running the main function, it looks like the panel allocates the right space for drawing the shape (The green part of the frame is the panel I created), but draws it only in a small part of that space. I added an example of the problem in the picture below. PRINT SCREEN EXAMPLE OF THE PROBLEM HERE!!!

Thanks for your help! :)

解决方案

So, you have a series of compounding issues and a fundamental misunderstanding of how the coordinate system works in Swing.

Doing...

g.fillRect(this.getX(), this.getY(),this.getWidth(),this.getHeight());

is a bad idea.

The getX and getY represent the location of the component within it's parent component space, so you've now offset the position of your drawing by x * 2 and y * 2

I renamed the getX and getY functions

Well, that's not in your original code, and it would just cause more mayhem

So, I setup a small test using...

Shape shape = new Shape("", true, 25, 25, 50, 50, Color.RED);
shape.setBorder(new LineBorder(Color.BLUE));
shape.setBounds(25, 25, 50, 50);

(I modified the Shape to always paint a oval) and this produces...

You can see that the shape is now offset within then Shape component.

Instead, you should paint from 0x0, which will be the top/left corner of the Shape component.

I modified the Shape code to use...

if (this.isFill()) {
    g.fillOval(0, 0, this.getWidth(), this.getHeight());
} else {
    g.drawOval(0, 0, this.getWidth(), this.getHeight());
}

and it now generates...

IMHO, using a component in this way is a bad idea. null layouts are notoriously difficult to manager and if all you want to do is paint shapes, then a pure custom painting route is generally better/easier to manager.

This idea basically constructs a single component which can paint any number of "shape" objects

Because I like to start with a "abstract" concept, which can be built up from, I start with a basic concept of a Shape, which defines all the information all Shape implementations would need...

public interface Shape {
    public Rectangle getBounds();
    public boolean isFilled();
    public Color getColor();
    public void paint(Graphics2D g2d);
}

Then I define an abstract implementation of which covers the core/common functionality...

public abstract class AbstractShape implements Shape {
    private Rectangle bounds;
    private boolean filled;
    private Color color;

    public AbstractShape(Rectangle bounds, boolean filled, Color color) {
        this.bounds = bounds;
        this.filled = filled;
        this.color = color;
    }

    public Rectangle getBounds() {
        return bounds;
    }

    public boolean isFilled() {
        return filled;
    }

    public Color getColor() {
        return color;
    }

}

And then I define the actual implementations, in this case, I've only done the OvalShape, but you could have a triangle, rectangle, arc and over shapes...

public class OvalShape extends AbstractShape {

    public OvalShape(Rectangle bounds, boolean filled, Color color) {
        super(bounds, filled, color);
    }

    @Override
    public void paint(Graphics2D g2d) {
        g2d.setColor(this.getColor());
        Rectangle bounds = getBounds();
        if (isFilled()) {
            g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
        } else {
            g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);
        }
    }

}

Then, we need some way to show those shapes...

public class ShapeContainer extends JPanel {
    private List<Shape> shapes;

    public ShapeContainer() {
        shapes = new ArrayList<>(25);
    }

    public void add(Shape shape) {
        shapes.add(shape);
        repaint();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Shape shape : shapes) {
            Graphics2D g2d = (Graphics2D) g.create();
            shape.paint(g2d);
            g2d.dispose();
        }
    }



}

This means, all the shapes work within the containers coordinate context and you don't need to worry about trying to translate them should you want to add new features down the track...

And because I know that's probably a bit to take in, a runnable example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                Shape shape = new OvalShape(new Rectangle(25, 24, 50, 50), true, Color.RED);

                ShapeContainer container = new ShapeContainer();
                container.add(shape);

                frame.add(container);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Shape {
        public Rectangle getBounds();
        public boolean isFilled();
        public Color getColor();
        public void paint(Graphics2D g2d);
    }

    public abstract class AbstractShape implements Shape {
        private Rectangle bounds;
        private boolean filled;
        private Color color;

        public AbstractShape(Rectangle bounds, boolean filled, Color color) {
            this.bounds = bounds;
            this.filled = filled;
            this.color = color;
        }

        public Rectangle getBounds() {
            return bounds;
        }

        public boolean isFilled() {
            return filled;
        }

        public Color getColor() {
            return color;
        }

    }

    public class OvalShape extends AbstractShape {

        public OvalShape(Rectangle bounds, boolean filled, Color color) {
            super(bounds, filled, color);
        }

        @Override
        public void paint(Graphics2D g2d) {
            g2d.setColor(this.getColor());
            Rectangle bounds = getBounds();
            if (isFilled()) {
                g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
            } else {
                g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);
            }
        }

    }

    public class ShapeContainer extends JPanel {
        private List<Shape> shapes;

        public ShapeContainer() {
            shapes = new ArrayList<>(25);
        }

        public void add(Shape shape) {
            shapes.add(shape);
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Shape shape : shapes) {
                Graphics2D g2d = (Graphics2D) g.create();
                shape.paint(g2d);
                g2d.dispose();
            }
        }



    }
}

这篇关于PaintComponent 的一些问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆