【问题标题】:How to draw a Round rectangle in java with normal rectangle outline如何在java中用普通矩形轮廓绘制一个圆角矩形
【发布时间】:2013-01-11 04:07:11
【问题描述】:

对于我的 java 应用程序,我需要一个圆形矩形,其轮廓看起来像一个普通矩形,像这样

我知道你可以通过在其中绘制一个普通矩形和一个 RoundRect 来做到这一点,但我不想在其中绘制一个 RoundRect,因为我想在其中绘制其他东西。

所以是一个带有正常角的圆形矩形。我如何在 Java 中绘制它?

问题是如果我使用图层,矩形看起来像这样: 边角填错了颜色。我该如何防止呢?

【问题讨论】:

  • 您不能堆叠图层并绘制一个矩形,添加一个 RoundRect 图层,然后在白色区域内添加另一个包含您需要的任何内容的图层吗?
  • 另外你应该添加一个与你正在使用的图形库相对应的标签(swing?)。
  • "我知道你可以通过在其中绘制一个普通矩形和一个 RoundRect 来做到这一点,但我不想在其中绘制一个 RoundRect,因为我想在其中绘制其他东西。 " 所以最后画那个'东西'。我真的没有看到这里的问题。
  • 也许另外一个具有给定笔画宽度的drawRoundRect(x, y, w, h, 1, 1) 会填充三角形?

标签: java swing awt java-2d paint


【解决方案1】:

我可以想到两种方法。首先是生成一个Shape,代表方形外边缘和圆形内边缘。

第二种方法是使用AlphaComposite 来生成屏蔽结果。

public class TestMask {

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

    public TestMask() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new MaskedPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class MaskedPane extends JPanel {

        public MaskedPane() {
            setBackground(Color.RED);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            BufferedImage outter = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = outter.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.BLACK);
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.dispose();
            BufferedImage inner = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            g2d = inner.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.BLACK);
            g2d.fillRoundRect(10, 10, getWidth() - 20, getHeight() - 20, 20, 20);
            g2d.dispose();

            BufferedImage masked = applyMask(outter, inner, AlphaComposite.DST_OUT);
            g.drawImage(masked, 0, 0, this);

        }

        public BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
            BufferedImage maskedImage = null;
            if (sourceImage != null) {

                int width = maskImage.getWidth();
                int height = maskImage.getHeight();

                maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                Graphics2D mg = maskedImage.createGraphics();

                int x = (width - sourceImage.getWidth()) / 2;
                int y = (height - sourceImage.getHeight()) / 2;

                mg.drawImage(sourceImage, x, y, null);
                mg.setComposite(AlphaComposite.getInstance(method));
                mg.drawImage(maskImage, 0, 0, null);
                mg.dispose();
            }

            return maskedImage;
        }

        public BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage) {
            return (BufferedImage) applyMask(sourceImage, maskImage, AlphaComposite.DST_IN);
        }
    }
}

更新了形状示例

终于有时间打了一个...

public class TestMask {

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

    public TestMask() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ShapedPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ShapedPane extends JPanel {

        public ShapedPane() {
            setBackground(Color.GREEN);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.BLACK);
            g2d.fill(new RounedFrame(getWidth(), getHeight(), 10, 20));
            g2d.dispose();
        }
    }

    public class RounedFrame extends Path2D.Float {

        public RounedFrame(float width, float height, float thickness, float radius) {

            moveTo(0, 0);
            lineTo(width, 0);
            lineTo(width, height);
            lineTo(0, height);
            lineTo(0, 0);

            float innerWidth = width - thickness;
            float innerHeight = height - thickness;

            moveTo(thickness + radius, thickness);
            lineTo(innerWidth - radius, thickness);

            curveTo(innerWidth, thickness, innerWidth, thickness, innerWidth, thickness + radius);

            lineTo(innerWidth, innerHeight - radius);
            curveTo(innerWidth, innerHeight, innerWidth, innerHeight, innerWidth - radius, innerHeight);
            lineTo(thickness + radius, innerHeight);
            curveTo(thickness, innerHeight, thickness, innerHeight, thickness, innerHeight - radius);
            lineTo(thickness, thickness + radius);
            curveTo(thickness, thickness, thickness, thickness, thickness + radius, thickness);

            closePath();

            setWindingRule(WIND_EVEN_ODD);

        }
    }
}

更新

根据 Andrew 的评论,您可以通过使用 Area 来简化形状示例的使用

您可以用这个替换上面示例中的paintComponent...

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Area area = new Area(new Rectangle(0, 0, getWidth(), getHeight()));
    area.subtract(new Area(new RoundRectangle2D.Float(10, 10, getWidth() - 20, getHeight() - 20, 20, 20)));

    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(Color.BLACK);
    g2d.fill(area);
    g2d.dispose();
}

这更简单:D

【讨论】:

  • 为演示文稿的美感 +1。形状版本 (RounedFrame) 看起来像要求的那样。
【解决方案2】:

类似:

paintComponent(Graphics g) {
    //If you want more: Graphics2D g2 = (Graphics2D) g;
    Rect rect = getBounds();
    g.setColor(Color.BLACK);
    g.fillRect(rect.x, rect,y, rect.width, rect.height);
    rect.grow(-4, -4);
    g.setColor(getBackground());
    g.fillRoundRect(rect.x, rect,y, rect.width, rect.height, 5, 5);
}

例如

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class CustomBorderWithContent {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                int w = 200;
                int h = 100;
                int pad = 4;

                BufferedImage img = new BufferedImage(
                        w, h, BufferedImage.TYPE_INT_RGB);
                Graphics2D g = img.createGraphics();
                g.setRenderingHint(
                        RenderingHints.KEY_ANTIALIASING, 
                        RenderingHints.VALUE_ANTIALIAS_ON);

                // Ripped/adapted from Joop's answer
                g.setColor(Color.BLACK);
                g.fillRect(0, 0, w, h);
                g.setColor(Color.ORANGE);
                g.fillRoundRect(pad, pad, w-2*pad, h-2*pad, 25, 25);

                // Now..
                g.setColor(Color.BLUE);
                g.drawString("Something else..", 20, 25);

                g.dispose();

                JOptionPane.showMessageDialog(
                        null, new JLabel(new ImageIcon(img)));
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

【讨论】:

  • 感谢您的回复。但实际上我正在寻找别的东西。很难解释。我知道可以使用图层,但我需要这个圆形矩形而不是其他东西,然后我得到了这个效果:tinypic.com/r/2ldbm7m/6,角落被错误的颜色填充
  • 我希望您不介意我编辑您的答案以添加 SSCCE。如果你没有先说出来,我会添加我自己的答案。
  • @AndrewThompson 感谢您的修饰。我将尝试按照示例进行操作。很抱歉没有发布您的答案。
  • @MadProgrammer 我喜欢您的两种方法(并且可能会使用 Area 来定义组合的 Shape),但认为纠正 OP 的假设很重要,即使用Joop 概述的技术。
  • @MadProgrammer 哈哈。我只是浏览了你的帖子,看到了“形状”并猜到你是这样做的!也许我应该按照我的意思添加一个“第四个例子”。但是哇..这里真正的问题不是“如何做到这一点?”,而是“如何从无数可能的方式中进行选择?”。 :)
猜你喜欢
  • 2018-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
相关资源
最近更新 更多