简体   繁体   English

Java:Paint应用程序,代码不起作用,我在做什么错?

[英]Java: Paint application, the code doesn't work, what am I doing wrong?

I'm new to Java and I'm learning by myself. 我是Java的新手,我自己学习。 I got stuck at this point. 我被困在这一点上。 I created a very basic paint application, but my friend told me that as I put everything in one *.java file that you can tell that I'm a beginning programmer, since I'm not really using object-oriented programming :D So I decided to divide my code into various files. 我创建了一个非常基本的绘画应用程序,但是我的朋友告诉我,当我将所有内容都放在一个* .java文件中时,由于我没有真正使用面向对象的编程,因此您可以说我是一名初学者。我决定将代码分成多个文件。 But now the code is not working (obviously). 但是现在代码不起作用了(显然)。

So I have the Main.java file which creates a window for the program (JFrame) and inside of that JFrame there are 2 panels, one on the BorderLayout.WEST, and secong in the CENTER. 所以我有Main.java文件,它为程序(JFrame)创建一个窗口,并且在JFrame的内部有2个面板,一个位于BorderLayout.WEST上,另一个位于CENTER中。 The one on the .WEST is the SideBar (with buttons etc.) and the one in the .CENTER is the main drawing board: .WEST上的一个是边栏(带有按钮等),. CENTER中的一个是主绘图板:

The Main.java file (public class Main): Main.java文件(公共类Main):

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.*;

public class Main {

    private Paint myPaint;
    private menuSideBar sidePanel;

Main(){

    JFrame ramka = new JFrame("Paint Application");

    sidePanel = new menuSideBar(); //this is the sidebar
    myPaint = new Paint(); // this is the drawing board

    ramka.getContentPane().add(sidePanel, BorderLayout.WEST);
    ramka.getContentPane().add(myPaint, BorderLayout.CENTER);
    ListenForWindow lForWindow = new ListenForWindow();
    ramka.addWindowListener(lForWindow);
    ramka.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    ramka.setSize(1400, 800);
    ramka.setLocationRelativeTo(null);
    ramka.setVisible(true);

}

private class ListenForWindow implements WindowListener{

    public void windowOpened(WindowEvent e) {
    }

    public void windowClosing(WindowEvent e) {
        int closing = JOptionPane.showConfirmDialog(null, "Exit program?", "Exit", JOptionPane.YES_NO_OPTION);
        if (closing == JOptionPane.YES_OPTION){
            System.exit(0);
        }
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

}


public static void main(String[] args){
    new Main();
}

}

Then I have the drawing board, in file Paint.java (public class Paint): 然后,在文件Paint.java(公共类Paint)中有了绘图板:

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class Paint extends JComponent {

private static final long serialVersionUID = 1L;
private BufferedImage bimage;
private Graphics2D g2;
private int whichShape;
private int oldX, oldY, newX, newY;
private int w, h;
private Color cColor;

Paint() {


    ListenForMouse lForMouse = new ListenForMouse();
    this.addMouseListener(lForMouse);
    this.addMouseMotionListener(lForMouse);

}

public void paintComponent(Graphics g){


    if (bimage == null){
        bimage = new BufferedImage(getSize().width, getSize().height, BufferedImage.TYPE_INT_ARGB);
        g2 = (Graphics2D) bimage.getGraphics();
        g2.setBackground(Color.WHITE);
        g2.setColor(Color.BLACK);
        clear();
    }

    g.drawImage(bimage, 0, 0, null);
}

public void clear(){
    g2.clearRect(0, 0, getSize().width, getSize().height);
    repaint();
}


public void draw(){

    w = newX - oldX;
    h = newY - oldY;

    if (w<0){
        w = w * (-1);
    }
    if (h<0){
        h = h * (-1);
    }


    switch (whichShape) {

    case 1:
        check();
        g2.drawRect(oldX, oldY, w, h);
        repaint();
        break;
    case 2:
        check();
        g2.drawRoundRect(oldX, oldY, w, h, 40, 40);
        repaint();
        break;
    case 3:
        check();
        g2.drawOval(oldX, oldY, w, h);
        repaint();
        break;
    case 4:
        check();
        g2.fillRect(oldX, oldY, w, h);
        repaint();
        break;
    case 5:
        check();
        g2.fillRoundRect(oldX, oldY, w, h, 20, 20);
        repaint();
        break;
    case 6:
        check();
        g2.fillOval(oldX, oldY, w, h);
        repaint();
        break;
    }
}



public void rectangle(){

    whichShape = 1;

}

public void roundedrectangle(){
    whichShape = 2;
}

public void oval(){
    whichShape = 3;
}

public void filledrectangle(){
    whichShape = 4;
}

public void filledroundedrectangle(){
    whichShape = 5;
}

public void filledoval(){
    whichShape = 6;
}

public void colorChooser(){
    cColor = JColorChooser.showDialog(null, "Choose color", Color.black);
    g2.setColor(cColor);
}


public void check(){
    if (oldX > newX){
        int z;
        z = oldX;
        oldX = newX;
        newX = z;
    }
    if (oldY > newY){
        int z;
        z = oldY;
        oldY = newY;
        newY = z;
    }
}



public class ListenForMouse implements MouseListener, MouseMotionListener{

    public void mouseDragged(MouseEvent e) {

    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {

        if (whichShape == 1 || whichShape == 2 || whichShape == 3 || whichShape == 4 || whichShape == 5 || whichShape == 6){
            oldX = e.getX();
            oldY = e.getY();    
        }

    }

    public void mouseReleased(MouseEvent e) {

        if (whichShape == 1 || whichShape == 2 || whichShape == 3 || whichShape == 4 || whichShape == 5 || whichShape == 6){
        newX = e.getX();
        newY = e.getY();
        draw();
        }

    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

}

}

Later there is sidebar, which is in the menuSideBar.java file (public class menuSideBar), this class reads in 4 other classes (there are 4 different menus I want to add, here I will just show one example): 稍后有侧边栏,它位于menuSideBar.java文件(公共类menuSideBar)中,该类读取其他4个类(我要添加4个不同的菜单,在这里,我仅显示一个示例):

import javax.swing.*;

public class menuSideBar extends JPanel {

    private static final long serialVersionUID = 1L;
    sideBar1 sb1;
    //sideBar2 sb2;
    //sideBar3 sb3;
    //sideBar4 sb4;

menuSideBar(){


    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

    sb1 = new sideBar1();
    //sb2 = new sideBar2();
    //sb3 = new sideBar3();
    //sb4 = new sideBar4();

    this.add(sb1);
    //this.add(sb2);
    //this.add(sb3);
    //this.add(sb4);


}   
}

And this sideBar1.java file (public class sideBar1) contains JButtons with ActionListeners referring to methods in Paint.java file: 这个sideBar1.java文件(公共类sideBar1)包含带有ActionListener的JButton,这些JButton引用了Paint.java文件中的方法:

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class sideBar1 extends JPanel {

private static final long serialVersionUID = 1L;
Paint myPaint;

JButton pencilBut, brushBtn, bckpaintBtn, eraserBtn, textBtn, rectBtn, roundedrectBtn, ovalBtn, frectBtn, fovalBtn, froundedrectBtn, lineBtn;

sideBar1(){


    Border border = BorderFactory.createTitledBorder("Paint");
    this.setBorder(border);
    this.setLayout(new GridLayout(0,3));
    myPaint = new Paint();

    ListenForButton lForButton = new ListenForButton();

    pencilBut = new JButton("pencil");
    pencilBut.addActionListener(lForButton);
    brushBtn = new JButton("brush");
    brushBtn.addActionListener(lForButton);
    bckpaintBtn = new JButton("background paint");
    bckpaintBtn.addActionListener(lForButton);
    eraserBtn = new JButton("eraser");
    eraserBtn.setIcon(icon_eraser);
    eraserBtn.addActionListener(lForButton);
    textBtn = new JButton("text");
    textBtn.addActionListener(lForButton);
    lineBtn = new JButton("line");
    lineBtn.addActionListener(lForButton);
    rectBtn = new JButton("rectangle");
    rectBtn.addActionListener(lForButton);
    roundedrectBtn = new JButton("rounded rectangle");
    roundedrectBtn.addActionListener(lForButton);
    ovalBtn = new JButton("oval");
    ovalBtn.addActionListener(lForButton);
    frectBtn = new JButton("filled rectangle");
    frectBtn.addActionListener(lForButton);
    froundedrectBtn = new JButton("filled rounded rectangle");
    froundedrectBtn.addActionListener(lForButton);
    fovalBtn = new JButton("filled oval");
    fovalBtn.addActionListener(lForButton);



    this.add(pencilBut);
    this.add(brushBtn);
    this.add(bckpaintBtn);
    this.add(eraserBtn);
    this.add(textBtn);
    this.add(lineBtn);
    this.add(rectBtn);
    this.add(roundedrectBtn);
    this.add(ovalBtn);
    this.add(frectBtn);
    this.add(froundedrectBtn);
    this.add(fovalBtn);





}

public class ListenForButton implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {


        if (e.getSource() == brushBtn){

        } else if (e.getSource() == bckpaintBtn){

        } else if (e.getSource() == eraserBtn){

        } else if (e.getSource() == textBtn){

        } else if (e.getSource() == lineBtn){

        } else if (e.getSource() == rectBtn){
            System.out.println("rectangle");
            myPaint.rectangle();
        } else if (e.getSource() == roundedrectBtn){
            myPaint.roundedrectangle();
        } else if (e.getSource() == ovalBtn){
            myPaint.oval();
        } else if (e.getSource() == frectBtn){
            myPaint.filledrectangle();
        } else if (e.getSource() == froundedrectBtn){
            myPaint.filledroundedrectangle();
        } else if (e.getSource() == fovalBtn){
            myPaint.filledoval();
        } 


    }

}


}

Now, when I execute the code everything loads in smoothly, I can see all the panels and and all the components inside, but when I click the buttons nothing happens. 现在,当我执行代码时,所有内容顺利加载,我可以看到所有面板和其中的所有组件,但是当我单击按钮时,什么也没有发生。 I'm guessing it has to do with the inheritance, or actually I have a few questions: 我猜想它与继承有关,或者实际上我有几个问题:

  1. Did I understand my friend correctly? 我了解我的朋友正确吗? Should I divide my code into various *.java files and have every class in a different file, in the same package? 我是否应该将代码分成多个* .java文件,并将每个类放在同一文件中的不同文件中? Or should I include those various classes in one *.java file? 还是应该将这些各种类包含在一个* .java文件中? (if the latter option is ok, can somebody modify at least a fragment of my code, so I would know how to properly incorporate inheritance?, some of the classes extend JPanels and JComponents, and I've read that you should not mix up extending JPanels etc. (views) with models(?) (如果后一种选择可行,有人可以至少修改我的代码的一部分,以便我知道如何正确地继承吗?某些类扩展了JPanels和JComponents,并且我读到您不应混淆使用模型扩展JPanels等(视图)(?)
  2. Is it ok to read into Main.java file JPanels which are in another file menuSideBar.java and then reading into menuSideBar.java panels that are inside of sideBar1.java? 是否可以将Main.java文件JPanels读入另一个文件menuSideBar.java中,然后再读入sideBar1.java内部的menuSideBar.java面板中? Or should I define which panel goes into which panel in the Main class? 还是应该定义哪个面板进入Main类的哪个面板?
  3. Why is the Paint.java not reading the ActionListener of the JButtons of sideBar1.java? 为什么Paint.java不读取sideBar1.java的JButton的ActionListener? What am I doing wrong? 我究竟做错了什么?

Thank you! 谢谢! Sorry if that seems obvious to you, but all the examples in the books or tutorials have very short examples of inheritance and very simple ones and somehow I cannot transfer those simple examples into my code. 抱歉,如果这对您来说似乎很明显,但是书或教程中的所有示例都有非常短的继承示例和非常简单的继承示例,因此我无法以某种方式将这些简单示例传递到代码中。 Thank you! 谢谢!

Your main problem is that you're creating two Paint objects when you only need and should have one. 您的主要问题是,仅在需要并且应该有一个时才创建两个Paint对象。 To check this for yourself, search this page for how many times you see new Paint() . 要自己检查,请在此页面上搜索您看到new Paint() You should only see it once in the code, and you're seeing it twice. 您应该只在代码中看到一次,而又看到两次。

Why does this matter? 为什么这么重要? Well one Paint object is displayed in the GUI, and the other is not displayed, but its methods are being called when buttons are pressed in the ActionListener. 好吧,一个Paint对象显示在GUI中,而另一个则不显示,但是在ActionListener中按下按钮时会调用其方法。 Calling methods on the non-displayed object will not translate into a visible response in the displayed one. 未显示对象上的调用方法不会在显示对象中转换为可见响应。

An easy solution that is wrong is to make your paint variable static and share it everywhere. 一个简单的错误解决方案是使您的绘画变量为静态变量,并在任何地方共享它。 This is wrong as you lose the benefits of OOP and increase the risk of bugs. 这是错误的,因为您失去了OOP的好处并增加了错误的风险。 Better is to pass a reference from the visualized Paint object into the ActionListener where it is needed, so that only one Paint object is created, and methods are called in the listener on the same Paint object as the one that's displayed. 更好的方法是将可视化的Paint对象中的引用传递到需要它的ActionListener中,以便仅创建一个Paint对象,并在与所显示对象相同的Paint对象上的侦听器中调用方法。

More concrete, change this: 更具体地,更改此:

sidePanel = new menuSideBar(); //this is the sidebar
myPaint = new Paint(); // this is the drawing board

to this: 对此:

myPaint = new Paint(); // call this first
sidePanel = new menuSideBar(myPaint); // and pass it in

In the sideBar constructor (the class should be renamed SideBar), use the parameter: 在sideBar构造函数(类应重命名为SideBar)中,使用参数:

public sideBar(Paint myPaint) {
    this.myPaint = myPaint;
    // .... all other constructor code
}

and get rid of new Paint() from sideBar. 并从sideBar删除new Paint()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM