GUI在重写到MVC之后不能工作

时间:2022-05-26 11:20:53

I'm practicing MVC style programming. I have a Mastermind game in a single file, working fine (maybe apart of the fact that "Check" button is invisible at start).

我正在练习MVC风格的编程。我在一个文件中有一个master - mind游戏,运行良好(除了“Check”按钮在开始时不可见之外)。

http://paste.pocoo.org/show/226726/

http://paste.pocoo.org/show/226726/

But when I've rewritten it to model, view, controller files - and when I click on empty Pin (that should be updated, and repainted with new color) - noting happens. Can anybody see any problems here ? I've tried placing repaint() in different places, but it simply does not work at all :/

但是,当我将它重写为模型、视图、控制器文件时——以及当我单击空大头针(应该对其进行更新,并重新绘制新颜色)时——注意到发生了什么。有人能看出什么问题吗?我试过把repaint()放在不同的地方,但是它根本不起作用

Main :

主要:

public class Main { 
    public static void main(String[] args){
        Model model = new Model();
        View view = new View("Mastermind", 400, 590, model);
        Controller controller = new Controller(model, view); 
        view.setVisible(true);
    }
}

Model :

模型:

import java.util.Random;

public class Model{
    static final int
    LINE = 5,
    SCORE = 10, OPTIONS = 20;
    Pin pins[][] = new Pin[21][LINE];
    int combination[] = new int[LINE];
    int curPin = 0;
    int turn = 1;
    Random generator = new Random();
    int repaintPin;
    boolean pinsRepaint=false;
    int pinsToRepaint;
    boolean isUpdate = true, isPlaying = true, isRowFull = false;
    static final int HIT_X[] = {270,290,310,290,310}, HIT_Y[] = {506,496,496,516,516};

    public Model(){

        for ( int i=0; i < SCORE; i++ ){
            for ( int j = 0; j < LINE; j++ ){
                pins[i][j] = new Pin(20,0);
                pins[i][j].setPosition(j*50+30,510-i*50);
                pins[i+SCORE][j] = new Pin(8,0);
                pins[i+SCORE][j].setPosition(HIT_X[j],HIT_Y[j]-i*50);
            }
        }
        for ( int i=0; i < LINE; i++ ){
            pins[OPTIONS][i] = new Pin( 20, i+2 );
            pins[OPTIONS][i].setPosition( 370,i * 50 + 56);
        }

    }

    void fillHole(int color) {
        pins[turn-1][curPin].setColor(color+1);
        pinsRepaint = true;
        pinsToRepaint = turn;
        curPin = (curPin+1) % LINE;
        if (curPin == 0){
            isRowFull = true;
        }
        pinsRepaint = false;
        pinsToRepaint = 0;
    }

    void check() {
        int junkPins[] = new int[LINE], junkCode[] = new int[LINE];
        int pinCount = 0, pico = 0;

        for ( int i = 0; i < LINE; i++ ) {
            junkPins[i] = pins[turn-1][i].getColor();
            junkCode[i] = combination[i];
        }
        for ( int i = 0; i < LINE; i++ ){
            if (junkPins[i]==junkCode[i]) {
                pins[turn+SCORE][pinCount].setColor(1);
                pinCount++;
                pico++;
                junkPins[i] = 98;
                junkCode[i] = 99;
            }
        }
        for ( int i = 0; i < LINE; i++ ){
            for ( int j = 0; j < LINE; j++ )
                if (junkPins[i]==junkCode[j]) {
                    pins[turn+SCORE][pinCount].setColor(2);
                    pinCount++;
                    junkPins[i] = 98;
                    junkCode[j] = 99;
                    j = LINE;
            }
        }
        pinsRepaint = true;
        pinsToRepaint = turn + SCORE;
        pinsRepaint = false;
        pinsToRepaint=0;

        if ( pico == LINE ){
            isPlaying = false;
        }
        else if ( turn >= 10 ){
                isPlaying = false;
        }
        else{
            curPin = 0;
            isRowFull = false;
            turn++;
        }
    }

    void combination() {
        for ( int i = 0; i < LINE; i++ ){
          combination[i] = generator.nextInt(6) + 1;
        }
    }
}

class Pin{
    private int color, X, Y, radius;

    public Pin(){
        X = 0; Y = 0; radius = 0; color = 0;
    }

    public Pin( int r,int c ){
        X = 0; Y = 0; radius = r; color = c;
    }

    public int getX(){
        return X;
    }

    public int getY(){
        return Y;
    }

    public int getRadius(){
        return radius;
    }

    public void setRadius(int r){
        radius = r;
    }

    public void setPosition( int x,int y ){
        this.X = x ;
        this.Y = y ;
    }
    public void setColor( int c ){
        color = c;
    }
    public int getColor() {
        return color;
    }
}

View:

观点:

import java.awt.*;
import javax.swing.*;

public class View extends Frame{  
    Model model;
    JButton checkAnswer;
    private JPanel button;
    private static final Color COLORS[] = {Color.black, Color.white, Color.red, Color.yellow, Color.green, Color.blue, new Color(7, 254, 250)};

    public View(String name, int w, int h, Model m){
        model = m;
        setTitle( name );
        setSize( w,h );
        setResizable( false );
        this.setLayout(new BorderLayout());

        button = new JPanel();
        button.setSize( new Dimension(400, 100));
        button.setVisible(true);
        checkAnswer = new JButton("Check");
        checkAnswer.setSize( new Dimension(200, 30));
        button.add( checkAnswer );
        this.add( button, BorderLayout.SOUTH);
        button.setVisible(true);
    }

    @Override
    public void paint( Graphics g ) {
        g.setColor( new Color(238, 238, 238));
        g.fillRect( 0,0,400,590);

        for ( int i=0; i < model.pins.length; i++ ) {
            paintPins(model.pins[i][0],g);
            paintPins(model.pins[i][1],g);
            paintPins(model.pins[i][2],g);
            paintPins(model.pins[i][3],g);
            paintPins(model.pins[i][4],g);
        }
    }

    @Override
    public void update( Graphics g ) {
        if ( model.isUpdate ) {
            paint(g);
        }
        else {
            model.isUpdate = true;
            paintPins(model.pins[model.repaintPin-1][0],g);
            paintPins(model.pins[model.repaintPin-1][1],g);
            paintPins(model.pins[model.repaintPin-1][2],g);
            paintPins(model.pins[model.repaintPin-1][3],g);
            paintPins(model.pins[model.repaintPin-1][4],g);
        }
    }

    void repaintPins( int pin ) {
        model.repaintPin = pin;
        model.isUpdate = false;
        repaint();
    }

    public void paintPins(Pin p, Graphics g ){
        int X = p.getX();
        int Y = p.getY();
        int color = p.getColor();
        int radius = p.getRadius();
        int x = X-radius;
        int y = Y-radius;

        if (color > 0){
            g.setColor( COLORS[color]);
            g.fillOval( x,y,2*radius,2*radius );
        }
        else{
            g.setColor( new Color(238, 238, 238) );
            g.drawOval( x,y,2*radius-1,2*radius-1 );
        }
        g.setColor( Color.black );
        g.drawOval( x,y,2*radius,2*radius );
    }
}

Controller:

控制器:

import java.awt.*;
import java.awt.event.*;

public class Controller implements MouseListener, ActionListener { 
    private Model model;
    private View view;

    public Controller(Model m, View v){ 
        model = m;
        view = v;

        view.addWindowListener( new WindowAdapter(){
            public void windowClosing(WindowEvent e){
            System.exit(0);
        } });
        view.addMouseListener(this);
        view.checkAnswer.addActionListener(this);
        model.combination();
    }

    public void actionPerformed( ActionEvent e ) {
        if(e.getSource() == view.checkAnswer){
            if(model.isRowFull){
                model.check();
            }
        }
    }

    public void mousePressed(MouseEvent e) {
        Point mouse = new Point();

        mouse = e.getPoint();
        if (model.isPlaying){
            if (mouse.x > 350) {
                int button = 1 + (int)((mouse.y - 32) / 50);
                if ((button >= 1) && (button <= 5)){
                    model.fillHole(button);
                    if(model.pinsRepaint){
                        view.repaintPins( model.pinsToRepaint );
                    }
                }
            }
        }
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseReleased(MouseEvent e){}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e)  {}
}

2 个解决方案

#1


144  

As you've discovered, the Model–View–Controller pattern is no panacea, but it offers some advantages. Rooted in MVC, the Swing separable model architecture is discussed in A Swing Architecture Overview. Based on this outline, the following example shows an MVC implementation of a much simpler game that illustrates similar principles. Note that the Model manages a single Piece, chosen at random. In response to a user's selection, the View invokes the check() method, while listening for a response from the Model via update(). The View then updates itself using information obtained from the Model. Similarly, the Controller may reset() the Model. In particular, there is no drawing in the Model and no game logic in the View. This somewhat more complex game was designed to illustrate the same concepts.

正如您所发现的,模型-视图-控制器模式不是万灵药,但它提供了一些优势。基于MVC, Swing可分离模型体系结构在Swing体系结构概述中进行了讨论。基于这个大纲,下面的示例展示了一个更简单的游戏的MVC实现,它演示了类似的原理。注意,该模型管理单个块,随机选择。在响应用户的选择时,视图调用check()方法,同时通过update()侦听模型的响应。然后视图使用从模型中获得的信息更新自己。类似地,控制器可以重置()模型。特别是,模型中没有绘图,视图中没有游戏逻辑。这个稍微复杂一点的游戏是为了说明同样的概念而设计的。

Addendum: I've modified the original example to show how MVC allows one to enhance the View without changing the nature of the Model.

附录:我已经修改了原始示例,以显示MVC允许在不改变模型性质的情况下增强视图。

Addendum: As @akf observes, MVC hinges on the observer pattern. Your Model needs a way to notify the View of changes. Several approaches are widely used:

附录:正如@akf所观察到的,MVC依赖于观察者模式。您的模型需要一种方法来通知更改视图。有几种方法被广泛使用:

  • In the example below, Model extends Observable for simplicity.

    在下面的例子中,为了简单起见,模型扩展了Observable。

  • A more common approach uses an EventListenerList, as shown in the Converter application and suggested by the large number of EventListener subinterfaces and implementing classes.

    更常见的方法是使用EventListenerList,如转换器应用程序所示,并由大量EventListener子接口和实现类建议。

  • A third option is to use a PropertyChangeListener, as shown here and here.

    第三种选择是使用PropertyChangeListener,如图所示。

Addendum: Some common questions about Swing controllers are addressed here and here.

附录:这里和这里都讨论了关于Swing控制器的一些常见问题。

GUI在重写到MVC之后不能工作

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * @see https://*.com/q/3066590/230513
 * 15-Mar-2011 r8 https://*.com/questions/5274962
 * 26-Mar-2013 r17 per comment
 */
public class MVCGame implements Runnable {

    public static void main(String[] args) {
        EventQueue.invokeLater(new MVCGame());
    }

    @Override
    public void run() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new MainPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class MainPanel extends JPanel {

    public MainPanel() {
        super(new BorderLayout());
        Model model = new Model();
        View view = new View(model);
        Control control = new Control(model, view);
        JLabel label = new JLabel("Guess what color!", JLabel.CENTER);
        this.add(label, BorderLayout.NORTH);
        this.add(view, BorderLayout.CENTER);
        this.add(control, BorderLayout.SOUTH);
    }
}

/**
 * Control panel
 */
class Control extends JPanel {

    private Model model;
    private View view;
    private JButton reset = new JButton("Reset");

    public Control(Model model, View view) {
        this.model = model;
        this.view = view;
        this.add(reset);
        reset.addActionListener(new ButtonHandler());
    }

    private class ButtonHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            String cmd = e.getActionCommand();
            if ("Reset".equals(cmd)) {
                model.reset();
            }
        }
    }
}

/**
 * View
 */
class View extends JPanel {

    private static final String s = "Click a button.";
    private Model model;
    private ColorIcon icon = new ColorIcon(80, Color.gray);
    private JLabel label = new JLabel(s, icon, JLabel.CENTER);

    public View(Model model) {
        super(new BorderLayout());
        this.model = model;
        label.setVerticalTextPosition(JLabel.BOTTOM);
        label.setHorizontalTextPosition(JLabel.CENTER);
        this.add(label, BorderLayout.CENTER);
        this.add(genButtonPanel(), BorderLayout.SOUTH);
        model.addObserver(new ModelObserver());
    }

    private JPanel genButtonPanel() {
        JPanel panel = new JPanel();
        for (Piece p : Piece.values()) {
            PieceButton pb = new PieceButton(p);
            pb.addActionListener(new ButtonHandler());
            panel.add(pb);
        }
        return panel;
    }

    private class ModelObserver implements Observer {

        @Override
        public void update(Observable o, Object arg) {
            if (arg == null) {
                label.setText(s);
                icon.color = Color.gray;
            } else {
                if ((Boolean) arg) {
                    label.setText("Win!");
                } else {
                    label.setText("Keep trying.");
                }
            }
        }
    }

    private class ButtonHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            PieceButton pb = (PieceButton) e.getSource();
            icon.color = pb.piece.color;
            label.repaint();
            model.check(pb.piece);
        }
    }

    private static class PieceButton extends JButton {

        Piece piece;

        public PieceButton(Piece piece) {
            this.piece = piece;
            this.setIcon(new ColorIcon(16, piece.color));
        }
    }

    private static class ColorIcon implements Icon {

        private int size;
        private Color color;

        public ColorIcon(int size, Color color) {
            this.size = size;
            this.color = color;
        }

        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(color);
            g2d.fillOval(x, y, size, size);
        }

        @Override
        public int getIconWidth() {
            return size;
        }

        @Override
        public int getIconHeight() {
            return size;
        }
    }
}

/**
 * Model
 */
class Model extends Observable {

    private static final Random rnd = new Random();
    private static final Piece[] pieces = Piece.values();
    private Piece hidden = init();

    private Piece init() {
        return pieces[rnd.nextInt(pieces.length)];
    }

    public void reset() {
        hidden = init();
        setChanged();
        notifyObservers();
    }

    public void check(Piece guess) {
        setChanged();
        notifyObservers(guess.equals(hidden));
    }
}

enum Piece {

    Red(Color.red), Green(Color.green), Blue(Color.blue);
    public Color color;

    private Piece(Color color) {
        this.color = color;
    }
}

#2


20  

When looking through Swing, one way that the designers consistently employ updating of View components in its MVC implementation is through Observer/Observable callbacks. An example can be seen in the AbstractTableModel, which has a variety of fireTable*Changed/Updated/etc methods that will alert all of its TableModelListener observers of mods to the model.

在查看Swing时,设计者在MVC实现中始终采用更新视图组件的一种方法是通过观察者/可观察回调。可以在AbstractTableModel中看到一个示例,它有各种各样的防火表*更改/更新/等等方法,这些方法将向模型发出所有mods的TableModelListener观察者的警报。

One option you have is to add a listener type to your Model class, and then notify your registered observers of any mods to the state of your model. Your View should be a listener, and it should repaint itself upon receipt of an update.

一个选项是向模型类添加侦听器类型,然后将任何mods的注册观察者通知模型的状态。您的视图应该是一个侦听器,并且它应该在收到更新后重新绘制自己。

EDIT: +1 to trashgod. consider this an alternate wording to his explanation.

编辑:+ 1 trashgod。把这当作他解释的另一种措辞。

#1


144  

As you've discovered, the Model–View–Controller pattern is no panacea, but it offers some advantages. Rooted in MVC, the Swing separable model architecture is discussed in A Swing Architecture Overview. Based on this outline, the following example shows an MVC implementation of a much simpler game that illustrates similar principles. Note that the Model manages a single Piece, chosen at random. In response to a user's selection, the View invokes the check() method, while listening for a response from the Model via update(). The View then updates itself using information obtained from the Model. Similarly, the Controller may reset() the Model. In particular, there is no drawing in the Model and no game logic in the View. This somewhat more complex game was designed to illustrate the same concepts.

正如您所发现的,模型-视图-控制器模式不是万灵药,但它提供了一些优势。基于MVC, Swing可分离模型体系结构在Swing体系结构概述中进行了讨论。基于这个大纲,下面的示例展示了一个更简单的游戏的MVC实现,它演示了类似的原理。注意,该模型管理单个块,随机选择。在响应用户的选择时,视图调用check()方法,同时通过update()侦听模型的响应。然后视图使用从模型中获得的信息更新自己。类似地,控制器可以重置()模型。特别是,模型中没有绘图,视图中没有游戏逻辑。这个稍微复杂一点的游戏是为了说明同样的概念而设计的。

Addendum: I've modified the original example to show how MVC allows one to enhance the View without changing the nature of the Model.

附录:我已经修改了原始示例,以显示MVC允许在不改变模型性质的情况下增强视图。

Addendum: As @akf observes, MVC hinges on the observer pattern. Your Model needs a way to notify the View of changes. Several approaches are widely used:

附录:正如@akf所观察到的,MVC依赖于观察者模式。您的模型需要一种方法来通知更改视图。有几种方法被广泛使用:

  • In the example below, Model extends Observable for simplicity.

    在下面的例子中,为了简单起见,模型扩展了Observable。

  • A more common approach uses an EventListenerList, as shown in the Converter application and suggested by the large number of EventListener subinterfaces and implementing classes.

    更常见的方法是使用EventListenerList,如转换器应用程序所示,并由大量EventListener子接口和实现类建议。

  • A third option is to use a PropertyChangeListener, as shown here and here.

    第三种选择是使用PropertyChangeListener,如图所示。

Addendum: Some common questions about Swing controllers are addressed here and here.

附录:这里和这里都讨论了关于Swing控制器的一些常见问题。

GUI在重写到MVC之后不能工作

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * @see https://*.com/q/3066590/230513
 * 15-Mar-2011 r8 https://*.com/questions/5274962
 * 26-Mar-2013 r17 per comment
 */
public class MVCGame implements Runnable {

    public static void main(String[] args) {
        EventQueue.invokeLater(new MVCGame());
    }

    @Override
    public void run() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new MainPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class MainPanel extends JPanel {

    public MainPanel() {
        super(new BorderLayout());
        Model model = new Model();
        View view = new View(model);
        Control control = new Control(model, view);
        JLabel label = new JLabel("Guess what color!", JLabel.CENTER);
        this.add(label, BorderLayout.NORTH);
        this.add(view, BorderLayout.CENTER);
        this.add(control, BorderLayout.SOUTH);
    }
}

/**
 * Control panel
 */
class Control extends JPanel {

    private Model model;
    private View view;
    private JButton reset = new JButton("Reset");

    public Control(Model model, View view) {
        this.model = model;
        this.view = view;
        this.add(reset);
        reset.addActionListener(new ButtonHandler());
    }

    private class ButtonHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            String cmd = e.getActionCommand();
            if ("Reset".equals(cmd)) {
                model.reset();
            }
        }
    }
}

/**
 * View
 */
class View extends JPanel {

    private static final String s = "Click a button.";
    private Model model;
    private ColorIcon icon = new ColorIcon(80, Color.gray);
    private JLabel label = new JLabel(s, icon, JLabel.CENTER);

    public View(Model model) {
        super(new BorderLayout());
        this.model = model;
        label.setVerticalTextPosition(JLabel.BOTTOM);
        label.setHorizontalTextPosition(JLabel.CENTER);
        this.add(label, BorderLayout.CENTER);
        this.add(genButtonPanel(), BorderLayout.SOUTH);
        model.addObserver(new ModelObserver());
    }

    private JPanel genButtonPanel() {
        JPanel panel = new JPanel();
        for (Piece p : Piece.values()) {
            PieceButton pb = new PieceButton(p);
            pb.addActionListener(new ButtonHandler());
            panel.add(pb);
        }
        return panel;
    }

    private class ModelObserver implements Observer {

        @Override
        public void update(Observable o, Object arg) {
            if (arg == null) {
                label.setText(s);
                icon.color = Color.gray;
            } else {
                if ((Boolean) arg) {
                    label.setText("Win!");
                } else {
                    label.setText("Keep trying.");
                }
            }
        }
    }

    private class ButtonHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            PieceButton pb = (PieceButton) e.getSource();
            icon.color = pb.piece.color;
            label.repaint();
            model.check(pb.piece);
        }
    }

    private static class PieceButton extends JButton {

        Piece piece;

        public PieceButton(Piece piece) {
            this.piece = piece;
            this.setIcon(new ColorIcon(16, piece.color));
        }
    }

    private static class ColorIcon implements Icon {

        private int size;
        private Color color;

        public ColorIcon(int size, Color color) {
            this.size = size;
            this.color = color;
        }

        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(color);
            g2d.fillOval(x, y, size, size);
        }

        @Override
        public int getIconWidth() {
            return size;
        }

        @Override
        public int getIconHeight() {
            return size;
        }
    }
}

/**
 * Model
 */
class Model extends Observable {

    private static final Random rnd = new Random();
    private static final Piece[] pieces = Piece.values();
    private Piece hidden = init();

    private Piece init() {
        return pieces[rnd.nextInt(pieces.length)];
    }

    public void reset() {
        hidden = init();
        setChanged();
        notifyObservers();
    }

    public void check(Piece guess) {
        setChanged();
        notifyObservers(guess.equals(hidden));
    }
}

enum Piece {

    Red(Color.red), Green(Color.green), Blue(Color.blue);
    public Color color;

    private Piece(Color color) {
        this.color = color;
    }
}

#2


20  

When looking through Swing, one way that the designers consistently employ updating of View components in its MVC implementation is through Observer/Observable callbacks. An example can be seen in the AbstractTableModel, which has a variety of fireTable*Changed/Updated/etc methods that will alert all of its TableModelListener observers of mods to the model.

在查看Swing时,设计者在MVC实现中始终采用更新视图组件的一种方法是通过观察者/可观察回调。可以在AbstractTableModel中看到一个示例,它有各种各样的防火表*更改/更新/等等方法,这些方法将向模型发出所有mods的TableModelListener观察者的警报。

One option you have is to add a listener type to your Model class, and then notify your registered observers of any mods to the state of your model. Your View should be a listener, and it should repaint itself upon receipt of an update.

一个选项是向模型类添加侦听器类型,然后将任何mods的注册观察者通知模型的状态。您的视图应该是一个侦听器,并且它应该在收到更新后重新绘制自己。

EDIT: +1 to trashgod. consider this an alternate wording to his explanation.

编辑:+ 1 trashgod。把这当作他解释的另一种措辞。