我在 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/