摆动 - 不规则形状的边框

时间:2015-12-15 10:02:37

标签: java swing border shape

我是摇摆中的新手,并且有一个问题,如何更好地绘制这个形状:

complicated shape

我以两种方式思考

  1. 绘制常规矩形并为其编写自定义边框?
  2. 绘制常规矩形+复合边框(包含2或3个边框)。但是在这里我没有成功地在形状内画出边框,是否有可能呢?像这样的东西: two borders figure.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBor der(在top,left,bottom,right,Color.WHITE之外),createMatteBorder(在top,left,bottom,right,Color.WHITE里面)),其中内边框是小矩形,外面是大矩形 - 不确定是否可能???
  3. 请提供建议,我们将非常感谢您的示例!

4 个答案:

答案 0 :(得分:1)

您可以使用多边形类(java.awt.Polygon

int xs = new int[]{1,2,3...7}; //your x-coordinates
int ys = new int[]{1,2,3...7}; //your y-coordinates
Shape irr = new Polygon(xs, ys, xs.length); 

如果您想使用某些边框,可以使用Graphics2D

public void paintComponent(Graphics gr){ 
    Graphics2D g2d = (Graphics2D)gr;

    GradientPaint redToWhite = new GradientPaint(0,0,color.RED,100, 0,color.WHITE);
    g2d.setPaint(redtowhite)
    g2d.fill(irr); //fill special color

    Stroke customBorder = getCustomBorder();
    g2d.setStroke(customBorder);
    g2d.draw(irr); //draw 'special' borders

}

查看stroke and fill

请注意,Polygon实施了contains(double x, double y)方法,可让您检测自己是否在内部

答案 1 :(得分:1)

您可以使用Area例如......

Area

public class TestPane extends JPanel {

    public TestPane() {
    }

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        Area area = new Area(new Rectangle(10, 10, getWidth() - 20, getHeight() - 20));
        area.subtract(new Area(new Rectangle(20, getHeight() / 2, getWidth() / 2, getHeight() - 10)));
        g2d.draw(area);
        g2d.dispose();
    }

}

您可以定义自定义形状...

Path2D

public class TestPane extends JPanel {

    public TestPane() {
    }

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        Path2D path = new Path2D.Float();
        path.moveTo(10, 10);
        path.lineTo(getWidth() - 20, 10);
        path.lineTo(getWidth() - 20, getHeight() - 20);
        path.lineTo(getWidth() / 2, getHeight() - 20);
        path.lineTo(getWidth() / 2, getHeight() / 2);
        path.lineTo(20, getHeight() / 2);
        path.lineTo(20, getHeight() - 20);
        path.lineTo(10, getHeight() - 20);
        path.closePath();
        g2d.draw(path);
        g2d.dispose();
    }

}

实际上编写自定义边框会非常非常困难,因为形状不规则,组件实际上会被包含在哪里?

有可能创建两个或更多边框,然后可以将其布局为显示为一个

有关详细信息,请参阅Working with Geometry

更新了Border示例...

Border实际工作要困难得多,因为期望边界的内部区域是矩形的。

根据您提供的复杂形状,一种解决方案是实际创建两个边框,一个左右镗孔,负责为要在其中布置的组件生成“安全”区域,例如:

public class LeftBorder implements Border {

    private int offset;

    public LeftBorder(int offset) {
        this.offset = offset;
    }

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Path2D path = new Path2D.Float();

        int xOffset = x + offset;
        int yOffset = y + offset;

        width -= offset;
        height -= offset * 2;

        float gap = width * 0.1f;

        path.moveTo(xOffset, yOffset);
        path.lineTo(xOffset + width, yOffset);
        path.moveTo(xOffset, yOffset);

        path.lineTo(xOffset, yOffset + height);
        path.lineTo(xOffset + gap, yOffset + height);
        path.lineTo(xOffset + gap, yOffset + (height - (height / 2)));
        path.lineTo(xOffset + width, yOffset + (height - (height / 2)));

        ((Graphics2D)g).draw(path);
    }

    @Override
    public Insets getBorderInsets(Component c) {

        int height = c.getHeight();
        height -= (height / 2);

        System.out.println(height);
        return new Insets(offset + 4, offset + 4, height + 4, 0);
    }

    @Override
    public boolean isBorderOpaque() {
        return false;
    }

}

public class RightBorder implements Border {

    private int offset;

    public RightBorder(int offset) {
        this.offset = offset;
    }

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Path2D path = new Path2D.Float();

        int xOffset = x;
        int yOffset = y + offset;

        width -= offset;
        height -= offset * 2;

        path.moveTo(xOffset, yOffset);
        path.lineTo(xOffset + width, yOffset);
        path.lineTo(xOffset + width, yOffset + height);
        path.lineTo(xOffset, yOffset + height);

        path.lineTo(xOffset, yOffset + (height - (height / 2)));

        ((Graphics2D)g).draw(path);
    }

    @Override
    public Insets getBorderInsets(Component c) {

        return new Insets(offset + 4, 0, offset + 4, offset + 4);
    }

    @Override
    public boolean isBorderOpaque() {
        return false;
    }

}

这将要求您提供至少两个相等高度的面板,例如:

Example layout

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;

public class Main {

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

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

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

    public class RightPane extends JPanel {

        public RightPane() {
            setBorder(new RightBorder(10));
            setLayout(new GridBagLayout());
            add(new JLabel("Righty"));
        }

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

    }

    public class LeftPane extends JPanel {

        public LeftPane() {
            setBorder(new LeftBorder(10));
            setLayout(new GridBagLayout());
            add(new JLabel("Lefty"));
        }

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

    }

}

这也将使布局管理器能够将两个组件布置在彼此旁边

答案 2 :(得分:1)

看看Java 2D API。它可以帮助您绘制复杂的形状。

E.g。

class IrregularShape extends JComponent {

    private int strokeWidth;

    IrregularShape(int strokeWidth){
        this.strokeWidth = strokeWidth;
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D newGraphics = (Graphics2D) g.create();

        Insets borderInsets = new Insets(0, 0, 0, 0);
        Border border = getBorder();
        if (border != null) {
            borderInsets = border.getBorderInsets(this);
        }

        BasicStroke basicStroke = new BasicStroke(strokeWidth);
        newGraphics.setStroke(basicStroke);

        int x = getX() + borderInsets.left + strokeWidth;
        int y = getY() + borderInsets.top + strokeWidth;
        int width = getWidth() - x - borderInsets.right - strokeWidth;
        int height = getHeight() - y - borderInsets.bottom - strokeWidth;

        Double outterRactangleDouble = new Rectangle2D.Double(x, y, width, height);

        Area outterRectangle = new Area(outterRactangleDouble);

        Area innerRectangle = new Area(outterRactangleDouble);
        AffineTransform affineTransform = new AffineTransform();
        affineTransform.scale(0.5, 0.5);
        affineTransform.translate(x + width * 0.10, y + height * 1.2);

        innerRectangle.transform(affineTransform);
        outterRectangle.subtract(innerRectangle);
        newGraphics.draw(outterRectangle);

    }

}

public class MainFrame {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Irregular Shape");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        Container contentPane = frame.getContentPane();
        contentPane.add(new IrregularShape(3));

        frame.setSize(640, 150);

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

}

结果 enter image description here

并且它也可以调整大小

enter image description here

答案 3 :(得分:0)

除了我的第一个回答https://stackoverflow.com/a/34287251/974186

您也可以将其实现为边框。

class IrregularBorder implements Border {

    private int thickness;

    public IrregularBorder(int thickness) {
        this.thickness = thickness;
    }

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width,
            int height) {
        Graphics2D graphics2d = (Graphics2D) g;

        BasicStroke basicStroke = new BasicStroke(thickness);
        graphics2d.setStroke(basicStroke);

        int halfThickness = thickness / 2;
        Double outterRactangleDouble = new Rectangle2D.Double(
                x + halfThickness, y + halfThickness, width - thickness,
                height - thickness);

        Area outterRectangle = new Area(outterRactangleDouble);

        Area innerRectangle = computeInnerRect(x, y, width, height,
                outterRactangleDouble);
        outterRectangle.subtract(innerRectangle);
        graphics2d.draw(outterRectangle);

    }

    private Area computeInnerRect(int x, int y, int width, int height,
            Double outterRactangleDouble) {
        Area innerRectangle = new Area(outterRactangleDouble);
        AffineTransform affineTransform = new AffineTransform();
        affineTransform.scale(0.5, 0.5);
        affineTransform.translate(x + width * 0.10, y + height * 1.2);

        innerRectangle.transform(affineTransform);
        return innerRectangle;
    }

    @Override
    public Insets getBorderInsets(Component c) {
        int left = (int) (thickness + (c.getWidth() * 0.6));
        return new Insets(thickness, left, thickness, thickness);
    }

    @Override
    public boolean isBorderOpaque() {
        return true;
    }

}

并照常使用

public class MainFrame {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Irregular Shape");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        Container contentPane = frame.getContentPane();

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        contentPane.add(mainPanel);

        JPanel irregularShapeBorderedPanel = new JPanel(new BorderLayout());
        irregularShapeBorderedPanel.add(new JButton("Button"),
                BorderLayout.CENTER);
        irregularShapeBorderedPanel.setBorder(new IrregularBorder(2));

        mainPanel.add(irregularShapeBorderedPanel);

        frame.setSize(640, 150);

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

}

enter image description here