英文:
Java/Swing: How to pass properties from Boundary to Model and vice versa
问题
我正在构建一个应用程序,用户可以上传图像并在其上绘制矩形进行注释,还可以将评论附加到特定的区域/矩形,就像在Word或Docs中一样。关于如何在类之间建立连接以传递信息,我有些困惑。用户绘制一个矩形并点击它后,他们将能够在提供的JTextField中编写评论,程序将把该矩形与该评论关联起来。我有三个类:Box
、DrawingArea
和ImageAnnotator
。Box(即矩形)的一个字段/属性是bComment
,在ImageAnnotator
类中我有一个JButton,点击它时需要将从ImageAnnotator
类中检索到的字符串设置为Box.bComment
。我知道onClick
方法应该位于ImageAnnotator
类中,因为按钮就在那里,但我对如何将此字符串传递给Box
有些困惑。我应该在ImageAnnotator
内导入Box
,并在onClick
方法内设置它吗?那么现在反过来,当点击矩形时,如何使用从Box.bComment
检索到的字符串设置ImageAnnotator
中的JTextField?也就是说,当用户再次点击相同的矩形时,程序将在文本字段中显示先前添加的评论。所有点击矩形的监听器都在DrawingArea
类中,所以我需要以某种方式从ImageAnnotator
获取文本字段,并用从Box.bComment
检索到的字符串填充文本字段。为了更清楚起见,我提供了以下类的代码:
ImageAnnotator.java:
public class ImageAnnotator extends JFrame {
// ... 其他部分
public ImageAnnotator(Model m) {
super();
// ... 其他部分
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String comment = textField.getText(); // 获取文本框中的评论
Box selectedBox = drawingArea.getSelectedBox(); // 获取选定的矩形
if (selectedBox != null) {
selectedBox.setComment(comment); // 将评论设置到选定的矩形
drawingArea.repaint(); // 重新绘制以显示评论
}
}
});
// ... 其他部分
}
// ... 其他部分
}
对于Box
和DrawingArea
类的更改,请查看以下代码:
Box.java:
public class Box {
// ... 其他部分
public void setComment(String comment) {
bComment = comment;
}
// ... 其他部分
}
DrawingArea.java:
public class DrawingArea extends JPanel implements BoxSelectionListener {
// ... 其他部分
private Box selectedBox; // 添加一个字段来存储选定的矩形
public Box getSelectedBox() {
return selectedBox;
}
// ... 其他部分
class MyMouseListener extends MouseInputAdapter {
// ... 其他部分
public void mouseReleased(MouseEvent e) {
if (shape != null) {
// ... 其他部分
} else {
for (Box b : rectangles) {
if (b.getRectangle().contains(e.getPoint())) {
didSelect(b);
selectedBox = b; // 选定这个矩形
break;
} else {
b.setForeground(Color.black);
}
}
}
startPoint = null;
shape = null;
}
}
// ... 其他部分
}
请注意,上面提供的代码片段是根据你的描述进行的修改,以便在点击按钮时将评论关联到选定的矩形,并在点击矩形时从矩形中检索评论并显示在文本框中。你可能需要根据实际情况对代码进行调整和完善。
英文:
I'm building an app where user can upload an image and draw rectangles on top of it for annotation and also attach comments to that certain region/rectangle, like in Word or Docs. I'm a bit confused on how to make the connection between the classes to pass information around. Once user draws a rectangle and clicks on it, they will be able to write comments in the JTextField provided, and the program will associate that rectangle with that comment. I have three classes Box
, DrawingArea
, and ImageAnnotator
. One of the fields/properties of Box (which is the rectangle) is bComment
, and inside the ImageAnnotator
class I have a JButton which upon click, will need to set the String retrieved from the JTextField in the ImageAnnotator
class to Box.bComment
. I know the onClick method should be inside the ImageAnnotator
class since that's where the button is but I'm a bit confused to how to pass this String over to Box
. Should I import Box
inside the ImageAnnotator
and set it within an onClick
method? So now the reverse way, upon clicking the rectangle, how do I set the JTextField in ImageAnnotator
with the String retrieved from Box.bComment
, that is, when the user clicks on the same rectangle again, the program will display the previously added comment in the text field. All the listeners for clicking on rectangle is inside the DrawingArea
class so I would need to somehow get the Text field from ImageAnnotator
and fill the text field with String retrieved from Box.bComment
. For more clarity, I have provided the classes below.
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;
}
}
}
答案1
得分: -1
我通过将一些字段设置为静态字段(例如 TextField),使其在另一个类中可以引用,从而使这些内容正常工作。我的错误在于我在 DrawingArea 类中创建了 ImageAnnotator 类的实例,所以当我尝试在 DrawingArea 中引用 ImageAnnotator 中的 TextField 时,它是空的。因此,我的解决方案是直接调用 ImageAnnotator 而不是创建一个实例,并将 TextField 设置为静态字段。
英文:
I was able to get those working by making some fields static (the TextField) so that I can reference it from another class, and my mistake was that I was creating instances of the ImageAnnotator class in my DrawingArea class so when I try to reference the TextField from ImageAnnotator inside DrawingArea, it was null. So my solution was instead I called ImageAnnotator directly without creating an instance and I set the TextField to static.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论