java绘图问题
我是java新手,我需要实现一个绘画应用程序,我有点陷入困境,我设法将线条绘制到添加到JFrame的JPanel,但绘制的每条线都会重置整个绘图,并且在绘图区域中仅保留最后绘制的线。我希望我能让自己理解,这是代码:
class Shapes extends JFrame {
public JFrame mf = new JFrame("Paint");
DrawArea da = new DrawArea();
JToggleButton lineButton = new JToggleButton(new ImageIcon("line.gif"));
JToggleButton brushButton = new JToggleButton();
JToggleButton pencilButton = new JToggleButton();
JToggleButton eraserButton = new JToggleButton(new ImageIcon("eraser_icon.png"));
JToggleButton rectangleButton = new JToggleButton();
JToggleButton ovalButton = new JToggleButton();
Shapes() {
da.setBounds(120, 50, 500, 350);
da.setBackground(Color.YELLOW);
mf.setSize(700, 500);
mf.setLayout(null);
lineButton.setBounds(0, 50, 40, 40);
brushButton.setBounds(40, 50, 40, 40);
eraserButton.setBounds(0, 90, 40, 40);
pencilButton.setBounds(40, 90, 40, 40);
rectangleButton.setBounds(0, 130, 40, 40);
ovalButton.setBounds(40, 130, 40, 40);
mf.setBackground(Color.red);
mf.add(lineButton);
mf.add(brushButton);
mf.add(pencilButton);
mf.add(eraserButton);
mf.add(rectangleButton);
mf.add(ovalButton);
mf.add(da);
mf.show();
mf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
mf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("x:" + e.getX() + "y:" + e.getY() + "\n" + "x2:" + e.getXOnScreen() + "y2:" + e.getYOnScreen());
}
});
eraserButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
eraserButton.setSelectedIcon(new ImageIcon("eraser_icon_selected.png"));
}
});
lineButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
lineButton.setSelectedIcon(new ImageIcon("line_selected.png"));
}
});
da.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
da.setXvalue(e.getX());
da.setYvalue(e.getY());
}
public void mouseReleased(MouseEvent e) {
da.setX2value(e.getX());
da.setY2value(e.getY());
da.repaint();
}
});
da.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
da.repaint();
da.setX2value(e.getX());
da.setY2value(e.getY());
}
});
}
}
public class DrawArea extends JPanel {
int x1value,y1value,x2value,y2value;
public int getX2value() {
return x2value;
}
public void setX2value(int x2value) {
this.x2value = x2value;
}
public int getY2value() {
return y2value;
}
public void setY2value(int y2value) {
this.y2value = y2value;
}
public JPanel dra=new JPanel();
public int getXvalue() {
return x1value;
}
public void setXvalue(int xvalue) {
this.x1value = xvalue;
}
public int getYvalue() {
return y1value;
}
public void setYvalue(int yvalue) {
this.y1value = yvalue;
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
g.drawLine(getXvalue(),getYvalue(),getX2value(),getY2value());
}
}
class Paint extends JPanel
{
public static void main(String args[])
{
Shapes s=new Shapes();
}
}
I am a new in java, and I need to implement a paint application, and I'm kinda stuck at the beggining, I managed to draw lines to a JPanel which I added to a JFrame, but each line drawn resets the entire drawing, and in the draw area remains only the last line drawn. I hope I made myself understood, here his the code:
class Shapes extends JFrame {
public JFrame mf = new JFrame("Paint");
DrawArea da = new DrawArea();
JToggleButton lineButton = new JToggleButton(new ImageIcon("line.gif"));
JToggleButton brushButton = new JToggleButton();
JToggleButton pencilButton = new JToggleButton();
JToggleButton eraserButton = new JToggleButton(new ImageIcon("eraser_icon.png"));
JToggleButton rectangleButton = new JToggleButton();
JToggleButton ovalButton = new JToggleButton();
Shapes() {
da.setBounds(120, 50, 500, 350);
da.setBackground(Color.YELLOW);
mf.setSize(700, 500);
mf.setLayout(null);
lineButton.setBounds(0, 50, 40, 40);
brushButton.setBounds(40, 50, 40, 40);
eraserButton.setBounds(0, 90, 40, 40);
pencilButton.setBounds(40, 90, 40, 40);
rectangleButton.setBounds(0, 130, 40, 40);
ovalButton.setBounds(40, 130, 40, 40);
mf.setBackground(Color.red);
mf.add(lineButton);
mf.add(brushButton);
mf.add(pencilButton);
mf.add(eraserButton);
mf.add(rectangleButton);
mf.add(ovalButton);
mf.add(da);
mf.show();
mf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
mf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("x:" + e.getX() + "y:" + e.getY() + "\n" + "x2:" + e.getXOnScreen() + "y2:" + e.getYOnScreen());
}
});
eraserButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
eraserButton.setSelectedIcon(new ImageIcon("eraser_icon_selected.png"));
}
});
lineButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
lineButton.setSelectedIcon(new ImageIcon("line_selected.png"));
}
});
da.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
da.setXvalue(e.getX());
da.setYvalue(e.getY());
}
public void mouseReleased(MouseEvent e) {
da.setX2value(e.getX());
da.setY2value(e.getY());
da.repaint();
}
});
da.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
da.repaint();
da.setX2value(e.getX());
da.setY2value(e.getY());
}
});
}
}
public class DrawArea extends JPanel {
int x1value,y1value,x2value,y2value;
public int getX2value() {
return x2value;
}
public void setX2value(int x2value) {
this.x2value = x2value;
}
public int getY2value() {
return y2value;
}
public void setY2value(int y2value) {
this.y2value = y2value;
}
public JPanel dra=new JPanel();
public int getXvalue() {
return x1value;
}
public void setXvalue(int xvalue) {
this.x1value = xvalue;
}
public int getYvalue() {
return y1value;
}
public void setYvalue(int yvalue) {
this.y1value = yvalue;
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
g.drawLine(getXvalue(),getYvalue(),getX2value(),getY2value());
}
}
class Paint extends JPanel
{
public static void main(String args[])
{
Shapes s=new Shapes();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
请参阅自定义绘画方法了解两种解决方案。这些示例绘制了矩形,但线条的概念是相同的。
See Custom Painting Approaches for two solutions. The examples draw rectangles, but the concept is the same for lines.
覆盖 PaintComponent(),而不是 paint()。阅读此教程。当需要重新绘制面板时,您可以调用该面板repaint() 方法。
Override paintComponent(), not paint(). Read this tutorial. When a panel needs to be redrawn, you call that panels repaint() method.
只要窗口管理器认为该区域“不新鲜”,就会调用 Paint。如果你按照现在的方式做,你每次都会画最后一条线。
正确的方法是在内存中创建一个 BufferedImage 并在其上进行绘制。然后,在 Paint 方法中,将 BufferedImage 位图传输到表面上。这也使得滚动和缩放变得非常容易。
每当您执行此类操作时,都会使表面无效,以便窗口管理器将为您调用绘制方法。
Paint is called by the window manager any time it considers that area 'unfresh'. If you do it the way you're doing it right now, you will draw the last line drawn every time.
The proper way to do this would be to make a
BufferedImage
in memory and draw on that. Then, in the paint method, blit theBufferedImage
onto the surface. This also makes scrolling and zooming quite easy to do.Whenever you perform such an action, invalidate the surface so that the window manager will call the paint method for you.
您只存储一行,并且每次都会覆盖它,因此当重新绘制组件时,旧的一行将被删除,新的一行将被重新绘制。
paintComponent
等的期望是您的实现将在每次调用时绘制您想要显示的每个图形元素。您应该创建一个
LineSegmentx1
、y1
、x2
、y2
> 存储这些值的类或类似类。然后,当您绘制时,您可以为您存储的每个LineSegment
对象调用g.drawLine()
(大概在ArrayList
或类似的中) )。然后,当重新绘制组件时,所有线段都应该出现在屏幕上。You are only storing one line, and overwriting it each time, so when the component is repainted, the old one is erased and the new one is redrawn.
The expectation of
paintComponent
and the like is that your implementation will draw EVERY graphical element that you want to appear, each time it is called.Instead of storing
x1
,y1
,x2
,y2
, you should make aLineSegment
class or similar that stores those values. Then, when you paint, you callg.drawLine()
for eachLineSegment
object that you've stored (presumably in anArrayList
or similar). Then, when the component is redrawn, all of your line segments should appear on the screen.有点偏离主题,但我有几分钟不舒服,因为我使用了 update() 而不是 repaint()。我建议每个使用 SWING 的人花一些时间检查哪些方法应作为线程安全处理,哪些方法必须位于 EDT(事件调度程序线程)上,以确保不会出现一些意外错误。
这是一篇关于此的好文章。
此外,在开始时请考虑一下是否想要一个您的应用程序中的撤消/重做系统...
如果是这样,那么您希望允许撤回多少步。如果您想允许此功能,那么您不能只绘制并忘记上次绘制的内容。
此外,存储到目前为止绘制的所有图像也不会节省内存。我不是专家,我并不是说这是最佳实践,但我会这样做:
我会列出两个列表。
绘图操作将是一个接口,并且某个类将为每种特定类型的绘图操作(LineDrawAction、CirceDrawAction...)实现它。
当您绘制新线或进行任何操作时,您将清空撤回操作列表并将其添加到已应用操作列表中。当有人撤消最后一个操作时,我只会从应用列表中删除最后一个绘图操作,并将其添加到撤回列表中(等等......)。根据您是否只想在列表达到此 x 限制时撤消最后一个 x 操作,我将从列表或队列中删除第一个绘图操作,并最终绘制到图片 - 这意味着永久绘图,这不能是撤消。
我希望它是清晰且有用的,即使不是对您问题的直接答案。
A little bit off topic, but I had a few uncomfortable minutes cause I used update() instead of repaint(). I advice to everyone working with SWING to spend some time checking which methods should handled as thread safe and which ones has to be on EDT (Event Dispatcher Thread) to make sure you won't get some unexpected errors.
This is a good article about this.
Also, at the beginning think through if you want to have an undo/redo system in your app...
If so, than how many steps you want to allow being withdrawn. If you want to allow this feature than you cannot just draw and forget about what you draw last time.
Also it would be not memory efficient to store all the images you draw so far. I'm not an expert and I'm not saying this is the best practice but I would go this way:
I would make two lists.
Drawing action would be an interface and some class would implement it for each specific kind of drawing action (LineDrawAction, CirceDrawAction...).
When you draw a new line or whatever you would empty the withdrawn actions list and add it to the applied action list. When someone undo the last action, than I would just remove the last drawing actions from the applied list and would add to the withdrawn list (etc...). Depending on if you want to allow only the last x action to be undone when a list reaches this x limit I would remove the first drawing action from the list or queue and would finally draw to the picture - this means permanent drawing and this cannot be undone.
I hope it's clear and useful even if not a direct answer to your question.