简体   繁体   English

摆动 - 不规则形状的边框

[英]Swing - irregular shaped border

I'm newbie in the swing and have a question how better to draw this shape: 我是秋千上的新手,有一个问题,如何更好地绘制这个形状:

形状复杂

I thought in two ways 我想到了两个方面

  1. to draw regular rectangle and to write custom border to it? 绘制常规矩形并为其编写自定义边框?
  2. to draw regular rectangle + compound border(which contains 2 or 3 borders). 绘制常规矩形+复合边框(包含2或3个边框)。 But here i do not succeed to draw border inside the shape, is is possible at all? 但是在这里我没有成功地在形状内画出边框,是否有可能呢? Something like this : 像这样的东西: 两个边界 figure.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBor‌​der(outside top,left,bottom, right, Color.WHITE), createMatteBorder(inside top,left,bottom, right, Color.WHITE)), where the inside border is small rectangle, and outside is big rectangle - not sure if it is possible??? figure.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBor der(在top,left,bottom,right,Color.WHITE之外),createMatteBorder(在top,left,bottom,right,Color.WHITE里面)),其中内边框是小矩形,外面是大矩形 - 不确定是否可能???

Please advise and an examples will be highly appreciated! 请指教,我们将非常感谢您的示例!

you can use the polygon class ( java.awt.Polygon ) 你可以使用polygon类( 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); 

if you want to use certain borders you can use Graphics2D 如果你想使用某些边框,你可以使用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

}

have a look at stroke and fill 看看中风和填充

note that Polygon implements the contains(double x, double y) method which lets you detect if you're inside or not 请注意, Polygon实现了contains(double x, double y)方法,该方法可以让您检测是否在内部

You could use a Area for example... 例如,您可以使用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();
    }

}

You define a custom shape... 您定义自定义形状...

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();
    }

}

Actually writing a custom border would be very, very difficult, because of the irregular style of shape, where would the components actually be contained? 实际上写一个自定义边框会非常非常困难,因为形状不规则,组件实际上会被包含在哪里?

It might be possible to create two or more borders, which could then be laid out so that the appeared as one 有可能创建两个或更多边框,然后可以将其布局为使其显示为一个边框

See Working with Geometry for more details 有关详细信息,请参阅使用几何

Updated with Border example... 更新了Border示例...

Getting a Border to actually work is far more difficult, as the expectation is that the internal area of the border will be rectangular. Border实际工作要困难得多,因为期望边界的内部区域是矩形的。

Based on the complex shape you've provided, one solution would be to actually create two borders, a left and right borer, which take care of generating a "safe" area for components to be laid out within, for example: 基于您提供的复杂形状,一种解决方案是实际创建两个边框,一个左右镗孔,它们负责为要在其中布置的组件生成“安全”区域,例如:

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;
    }

}

This would then require you to provide at least two panels of equal height, for example: 这将要求您提供至少两个高度相等的面板,例如:

示例布局

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);
        }

    }

}

This will also be relient on the layout manager been able to layout the two components next to each other 这也将使布局管理器能够将两个组件布置在彼此旁边

Take a look at the Java 2D API . 看一下Java 2D API It helps you to draw complex shapes. 它可以帮助您绘制复杂的形状。

Eg 例如

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);
    }

}

Result 结果 在此输入图像描述

and it's also resizeable 它也可以调整大小

在此输入图像描述

In addition to my first answer https://stackoverflow.com/a/34287251/974186 除了我的第一个答案https://stackoverflow.com/a/34287251/974186

You can also implement it as a Border. 您也可以将其实现为边框。

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;
    }

}

and use it as usual 像往常一样使用它

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);
    }

}

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM