java - 在Java绘图中添加标签

标签 java user-interface

我在 Java 方面的经验很少,但我喜欢编程,并且我希望我所做的一切都尽可能好。学习Java总共最多2天时间,可没那么容易。

我被要求制作一个逻辑门模拟器。除了 GUI 之外,我已经完成了所有的工作。正如我们的老师所给出的那样,这不是必需的,但对我来说是必要的,因为在这样的程序中与用户的沟通很复杂。 GUI 会让事情变得更加清晰。

我想在 Canvas 上创建门,然后能够移动它们。我首先制作了一个“与”门,并让它在单击时随鼠标移动。

然而,我注意到现在我在所有东西之上都有一个 Canvas 。我添加的每个标签、按钮等都位于 Canvas 后面。似乎 Canvas 是移动门所必需的,因为当我移动它时它实际上被重新绘制了。

门AND是在一个带有paintComponent的类中创建的。我是否必须在这个类中制作每个门,以便它们可以在同一个 Canvas 上?如何使每个门、标签、按钮共享同一个 Canvas ?

最后这是我的代码。双击即可移动盖茨。虽然很长。

主要:

                package Pack;
                import java.util.Scanner;
                import javax.swing.*;
                import java.awt.*;
                import java.awt.geom.*;

                public class Main {
                    public static JFrame f;
                    public static void main(String[] args) {

                    ShapeAnd sh=new ShapeAnd();
                    ShapeOr sh2=new ShapeOr();

                    f=new JFrame();
                    f.add(sh);
                    f.add(sh2);
                    f.setVisible(true);
                    f.setSize(700,600);
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.setTitle("LGS");
                    f.getContentPane().setBackground(Color.RED);
                    }
                    }

或:

            package Pack;
            import javax.swing.*;
            import java.awt.*;
            import java.awt.event.*;
            import java.awt.geom.*;

            public class ShapeOr extends JPanel implements MouseListener,MouseMotionListener{

                int preX,preY,preX2,preY2,difX,difY;
                Graphics g2;
                GeneralPath Or;
                int lim1x,lim2x,lim1y,lim2y;
                boolean check;
                public ShapeOr() {
                    preX=15;
                    preY=0;
                    addMouseMotionListener(this);
                    addMouseListener(this);
                  }
                public void paintComponent(Graphics g){
                    super.paintComponent(g);
                     Graphics2D g2 = (Graphics2D) g;
                     lim1x=preX;
                     lim2x=preX+80;
                     lim1y=preY;
                     lim2y=preY+60;
                             int x1Points[] = {preX,preX+50,preX+60,preX+70,preX+80,preX+70,preX+60,preX+50,preX,preX+10,preX+20,preX+30,preX+20,preX+10,preX};
                            int y1Points[] = {preY,preY,preY+5,preY+15,preY+30,preY+45,preY+55,preY+60,preY+60,preY+55,preY+45,preY+30,preY+15,preY+5,preY};
                            GeneralPath Or = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
                                                    x1Points.length);

                            Or.moveTo(preX-15,preY+15);
                            Or.lineTo(preX+20,preY+15);
                            Or.moveTo(preX-15,preY+45);
                            Or.lineTo(preX+20,preY+45);
                            Or.moveTo(preX,preY);

                            for (int index = 1; index < x1Points.length; index++) {
                                    Or.lineTo(x1Points[index], y1Points[index]);
                            };
                            Or.closePath();
                            g2.draw(Or);
                            //check=false;
                }
                public void mousePressed(MouseEvent e) {
                    difX=preX-e.getX();
                    difY=preY-e.getY();

                  }
                public void updateLocation(MouseEvent e){
                    preX=e.getX()+difX;
                    preY=e.getY()+difY;
                    repaint();
                }

                      public void mouseReleased(MouseEvent e) {
                       check=false;
                      }

                      public void mouseMoved(MouseEvent e) {
                      }

                      public void mouseClicked(MouseEvent e) {
                          int mouseX=e.getX();
                          int mouseY=e.getY();
                            if(mouseX>lim1x && mouseX<lim2x && mouseY>lim1y && mouseY<lim2y){
                                check=true;
                            }
                      }

                      public void mouseExited(MouseEvent e) {
                      }

                      public void mouseEntered(MouseEvent e) {
                      }

                      public void mouseDragged(MouseEvent e) {
                          if(check==true){
                              updateLocation(e);
                          }
                      }

            }

并且:

        package Pack;
        import javax.swing.*;
        import java.awt.*;
        import java.awt.event.*;
        import java.awt.geom.*;

        public class ShapeAnd extends JPanel implements MouseListener,MouseMotionListener{

            int preX,preY,preX2,preY2,difX,difY;
            Graphics g2;
            GeneralPath And;
            int lim1x,lim2x,lim1y,lim2y;
            boolean check;
            public ShapeAnd() {
                addMouseMotionListener(this);
                addMouseListener(this);
              }
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                 Graphics2D g2 = (Graphics2D) g;
                 lim1x=preX+15;
                 lim2x=preX+95;
                 lim1y=preY;
                 lim2y=preY+75;
                         int x1Points[] = {preX,preX+ 50, preX+60,preX +70,preX+80,preX+70,preX+60,preX+50,preX+0};
                        int y1Points[] = {preY+0,preY+ 0,preY+5,preY+15,preY+30,preY+45,preY+55,preY+60,preY+60};
                        GeneralPath And = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
                                                x1Points.length);

                        And.moveTo(preX,preY+15);
                        And.lineTo(preX+15,preY+15);
                        And.moveTo(preX,preY+45);
                        And.lineTo(preX+15,preY+45);
                        And.moveTo(preX+15,y1Points[0]);

                        for (int index = 1; index < x1Points.length; index++) {
                                And.lineTo(x1Points[index]+15, y1Points[index]);
                        };
                        And.closePath();
                        g2.draw(And);
                        //check=false;
            }
            public void mousePressed(MouseEvent e) {
                difX=preX-e.getX();
                difY=preY-e.getY();

              }
            public void updateLocation(MouseEvent e){
                preX=e.getX()+difX;
                preY=e.getY()+difY;
                repaint();
            }

                  public void mouseReleased(MouseEvent e) {
                   check=false;
                  }

                  public void mouseMoved(MouseEvent e) {
                  }

                  public void mouseClicked(MouseEvent e) {
                      int mouseX=e.getX();
                      int mouseY=e.getY();
                        if(mouseX>lim1x && mouseX<lim2x && mouseY>lim1y && mouseY<lim2y){
                            check=true;
                        }
                  }

                  public void mouseExited(MouseEvent e) {
                  }

                  public void mouseEntered(MouseEvent e) {
                  }

                  public void mouseDragged(MouseEvent e) {
                      if(check==true){
                          updateLocation(e);
                      }
                  }

        }

PS:我知道需要一个更好的标题。

最佳答案

感谢您发布的代码,因为这有助于澄清一些事情。我的假设是正确的——你让你的门扩展了一个 GUI 组件,给它们添加了很多不必要的“重量”,并使它们难以按照你的意愿移动,或者将其中的多个放置在你的 GUI 上。

解决方案的建议包括:

  • 不让您的大门扩展 JPanel 或任何 GUI 组件,从而使您的大门更加轻量级。
  • 相反,使它们成为“逻辑”(非 GUI 组件),可以由单个绘图组件通过 public void draw(Graphics2d g2) 方法进行绘制。我通常使用单个 JPanel 的 paintComponent(Graphics g) 方法来完成此绘图。
  • 为此绘图 JPanel 提供一个门对象的 ArrayList,然后通过在 JPanel 的单个 PaintComponent 方法中迭代该列表来绘制门。
  • 向同一个 JPanel 添加一个 MouseAdapter 作为鼠标监听器和运动监听器,并允许此监听器更改已单击或拖动的任何门形状的状态。
  • 通过为绘图组件提供可调用的 draw(...) 方法来允许门自行绘制,
  • 为您的门对象提供一个 public boolean contains(Point p) 方法,让您可以判断鼠标是否点击了它们
  • 并为他们的位置提供 getter 和 setter 方法,以便可以检查和更改。
  • 利用从 Shape 接口(interface)派生的功能类(通过组合)来帮助您自己的形状能够自行绘制和移动。我为此使用了 Path2D 对象,因为它们可以通过使用 AffineTransforms 轻松移动。

示例代码即将推出......

所有 Gate 对象可以共享相同的接口(interface),...

interface MyGate {
    void draw(Graphics2D g2);
    void setPoint(Point p);
    Point getPoint();
    boolean contains(Point p);  
}

实现上述接口(interface)的示例门类

class OrGate implements MyGate {
    private Path2D path; 
    private Point point = new Point(0, 0); // initial Point

    public OrGate() {
        // initialize the Path2D and give it a winding rule
        path = new Path2D.Double(Path2D.WIND_EVEN_ODD);

        // lots of "magic" numbers below, a code design "smell"
        // better to not do this. Perhaps have a data file to hold
        // this information, and have it read on program startup
        int preX = 15;
        int preY = 0;
        int x1Points[] = { preX, preX + 50, preX + 60, preX + 70, preX + 80, preX + 70, preX + 60,
                preX + 50, preX, preX + 10, preX + 20, preX + 30, preX + 20, preX + 10, preX };
        int y1Points[] = { preY, preY, preY + 5, preY + 15, preY + 30, preY + 45, preY + 55,
                preY + 60, preY + 60, preY + 55, preY + 45, preY + 30, preY + 15, preY + 5, preY };
        path.moveTo(preX - 15, preY + 15);
        path.lineTo(preX + 20, preY + 15);
        path.moveTo(preX - 15, preY + 45);
        path.lineTo(preX + 20, preY + 45);
        path.moveTo(preX, preY);

        for (int index = 1; index < x1Points.length; index++) {
            path.lineTo(x1Points[index], y1Points[index]);
        }
        path.closePath();
    }

    @Override
    public void draw(Graphics2D g2) {
        // simple method that leverages the Path2D path object
        g2.draw(path);
    }

    @Override
    public boolean contains(Point p) {
        // simple method that leverages the Path2D path object
        return path.contains(p);
    }

    @Override
    public Point getPoint() {
        return point;
    }

    @Override
    public void setPoint(Point p) {
        Point pOld = this.point;
        Point pNew = p;
        this.point = p;

        // create a transform that helps us move our Path2D
        int tx = pNew.x - pOld.x;
        int ty = pNew.y - pOld.y;       
        AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
        path.transform(at);  // and then move it
    }    

}

主 JPanel 显示了 MouseAdapter 的使用以及形状的绘制/拖动:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

@SuppressWarnings("serial")
public class MainGates2 extends JPanel {
    private static final int PREF_W = 700;
    private static final int PREF_H = 600;
    private List<MyGate> gates = new ArrayList<>();

    public MainGates2() {
        // create a few Gates
        MyGate gate1 = new OrGate();
        gate1.setPoint(new Point(200, 300)); // move this guy
        MyGate gate2 = new OrGate();

        // add them to the gates ArrayList
        gates.add(gate1);
        gates.add(gate2);

        // create our mouse listener / adapter and add to JPanel
        MyMouse myMouse = new MyMouse();
        addMouseListener(myMouse);
        addMouseMotionListener(myMouse);        
    }

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

        // rendering hints to smooth graphics
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // iterate through collection and draw
        for (MyGate myGate : gates) {
            myGate.draw(g2);
        }

    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        // give our JPanel some size
        return new Dimension(PREF_W, PREF_H);
    }

    private class MyMouse extends MouseAdapter {
        private MyGate selectedGate = null;
        private Point p0; // initial Gate location
        private Point p1; // first mouse press location

        @Override
        public void mousePressed(MouseEvent e) {
            if (e.getButton() != MouseEvent.BUTTON1) {
                return;
            }
            p1 = e.getPoint();
            for (int i = gates.size() - 1; i >= 0; i--) {
                if (gates.get(i).contains(e.getPoint())) {
                    selectedGate = gates.get(i);
                    p0 = selectedGate.getPoint();
                    return;
                }
            }
            p1 = null;
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (selectedGate != null) {
                dragShape(e);

                // de-select the gate
                selectedGate = null;
                p0 = null;
                p1 = null;
            }
        }

        public void mouseDragged(MouseEvent e) {
            if (selectedGate != null) {
                dragShape(e);
            }
        }

        private void dragShape(MouseEvent e) {
            Point p2 = e.getPoint(); // current mouse location
            int x = p0.x + p2.x - p1.x;
            int y = p0.y + p2.y - p1.y;
            Point p = new Point(x, y);
            selectedGate.setPoint(p);
            repaint();
        };
    }

    private static void createAndShowGui() {
        // main JPanel
        MainGates2 mainPanel = new MainGates2();

        JFrame frame = new JFrame("Main Gates2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

关于java - 在Java绘图中添加标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48252092/

相关文章:

python - 在主任务中显示来自后台任务的计数变量(Tkinter GUI)

Java 编程挑战 : Creating a GUI Calculator-Like Interface

c# - 如何为 WinForms 控件(即面板)设置 GridLayout

java - Jsoup.connect().get() 仅获取 Android 上的部分 html 文件

java - 如何告诉protostuff将属性打包到fixed32而不是int32

java - Cursor$DefaultCursor 无法转换为 java.lang.Boolean?

user-interface - 如何根据 fieldsize 计算 dbEdit 的宽度?

java - 如何使用AsyncTask和回调接口(interface)实现ListView的无限滚动?

java - 在改造中出现 401 未经授权的错误?

java - 在 Windows 7 平板电脑中执行时,我的 GUI 看起来很奇怪