【发布时间】:2020-09-29 07:27:25
【问题描述】:
我正在构建一个应用程序,用户可以在其中上传图像并在其上绘制矩形以进行注释,并将 cmets 附加到该特定区域/矩形,例如在 Word 或 Docs 中。我对如何在类之间建立联系以传递信息有点困惑。一旦用户绘制了一个矩形并单击它,他们将能够在提供的 JTextField 中编写 cmets,并且程序会将那个矩形与该注释相关联。我有三个班级Box、DrawingArea 和ImageAnnotator。 Box(矩形)的字段/属性之一是bComment,在ImageAnnotator 类中我有一个JButton,单击它时,需要设置从ImageAnnotator 类中的JTextField 检索的字符串到Box.bComment。我知道 onClick 方法应该在ImageAnnotator 类中,因为那是按钮所在的位置,但我对如何将此字符串传递给Box 有点困惑。我应该在ImageAnnotator 中导入Box 并将其设置在onClick 方法中吗?那么现在反过来,在点击矩形时,我如何设置ImageAnnotator中的JTextField和从Box.bComment检索的String,即当用户再次点击同一个矩形时,程序将显示之前添加的在文本字段中发表评论。单击矩形的所有侦听器都在DrawingArea 类内,因此我需要以某种方式从ImageAnnotator 获取文本字段,并用从Box.bComment 检索的字符串填充文本字段。为了更清楚起见,我提供了以下类。
ImageAnnotator.java:
public class ImageAnnotator extends JFrame {
private JPanel contentPane;
Model model;
DrawingArea drawingArea;
GroupLayout gl_contentPane;
private JTextField textField;
private JButton btnNewButton;
/**
* Create the frame.
*/
public ImageAnnotator(Model m) {
super();
this.model = m;
setTitle("Image Annotator");
...
setContentPane(contentPane);
drawingArea = new DrawingArea();
//ImageName = new JLabel(drawingArea.imageName);
buttonPanel = new ButtonPanel( drawingArea );
textField = new JTextField(); // this is the text field which will be later set to Box.bComment
btnNewButton = new JButton("Add this comment");//this is the button which needs onClick listener
gl_contentPane = new GroupLayout(contentPane);
gl_contentPane.setHorizontalGroup(...);
gl_contentPane.setVerticalGroup(...);
contentPane.add(drawingArea);
contentPane.setLayout(gl_contentPane);
}
// onClick listener should be here for JButton
}
Box.java:
public class Box {
int bWidth, bHeight, bX, bY;
String bImageName, bComment;
Color foreground;
Rectangle rectangle;
public Box(int width, int height) {
bWidth = width;
bHeight = height;
}
public Box(Color foreground, Rectangle rectangle) {
this.foreground = foreground;
this.rectangle = rectangle;
}
public void setComment(String comment) { bComment = comment; }
public String getComment() { return bComment; }
public void setX(int x) { bX = x; }
public int getX() { return bX; }
public void setY(int y) { bY = y; }
public int getY() { return bY; }
public Rectangle getRectangle()
{
return rectangle;
}
}
DrawingArea.java:
public class DrawingArea extends JPanel implements BoxSelectionListener
{
private final static int AREA_SIZE = 490;
private BufferedImage image =
new BufferedImage(AREA_SIZE, AREA_SIZE, BufferedImage.TYPE_INT_ARGB);
private Rectangle shape;
private ArrayList<Box> rectangles = new ArrayList<Box>();
//public String imageName = ""; // this will store the image/file name
public DrawingArea()
{
setBackground(Color.WHITE);
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);
}
public void addBoxSelectionListener(BoxSelectionListener listener) {
listenerList.add(BoxSelectionListener.class, listener);
}
public void removeBoxSelectionListener(BoxSelectionListener listener) {
listenerList.remove(BoxSelectionListener.class, listener);
}
protected void fireBoxSelected(Box box) {
BoxSelectionListener[] listeners = listenerList.getListeners(BoxSelectionListener.class);
// Normally, I'd create a event object, which would wrap the source (this) and
// the Box together, but if there are no listeners, it's a bit of
// a waste to do so, so I return early in those cases
if (listeners.length == 0) {
return;
}
for (BoxSelectionListener listener : listeners) {
listener.didSelect(box);
}
}
public void didSelect(Box box) {
// Probably assign this to a "assigned" or "selected" property
// so it can painted differently
// And now we want to notify some kind of listener so that
// it can update the UI as required
box.setForeground(Color.red);
box.getComment();
repaint();
fireBoxSelected(box);
}
class MyMouseListener extends MouseInputAdapter
{
private Point startPoint;
public void mousePressed(MouseEvent e) {
// Mark the clip point
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
// Only create the shape when dragging starts
if (shape == null) {
shape = new Rectangle();
}
int x = Math.min(startPoint.x, e.getX());
int y = Math.min(startPoint.y, e.getY());
int width = Math.abs(startPoint.x - e.getX());
int height = Math.abs(startPoint.y - e.getY());
shape.setBounds(x, y, width, height);
repaint();
}
public void mouseReleased(MouseEvent e) {
if (shape != null) {
if (shape.width != 0 || shape.height != 0) {
addRectangle(shape, e.getComponent().getForeground());
}
} else {
for (Box b : rectangles) {
if (b.getRectangle().contains(e.getPoint())) {
didSelect(b);
break;
}
else
b.setForeground(Color.black);
}
}
startPoint = null;
shape = null;
}
}
}
【问题讨论】:
-
您真的,真的,需要一些时间来了解MVC 是什么,因为这是您的问题/问题的基础。我还建议熟悉 observer pattern,在 Swing 中,它表示为“听众”
-
1) 正如我在最后几个问题中建议的那样,所有属性都属于一个类。您创建了一个新的“球”对象,因此您需要矩形、颜色和注释作为该类的属性。然后,“球”类将成为您自定义绘画的基础。您已经拥有动态创建 Ball 实例的逻辑。 2)要向 Ball 类添加评论,我会使用双击。我不喜欢单击具有多种功能的想法。所以双击我会显示一个 JOptionPane 来提示输入“评论”。
-
因此,当您双击矩形时,您会找到相关的“球”对象。然后在 JOptionPane 中显示“注释”。这将允许您添加/更改评论。所以基本上所有的逻辑都是“DrawingArea”中的容器。