Разница между Конструктором и ngOnInit

Да, свинг-таймер и привязки клавиш будут работать хорошо. Вот еще один пример (мой):)

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class AnimationWithKeyBinding {
   private static void createAndShowUI() {
      AnimationPanel panel = new AnimationPanel(); // the drawing JPanel

      JFrame frame = new JFrame("Animation With Key Binding");
      frame.getContentPane().add(panel);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

@SuppressWarnings("serial")
class AnimationPanel extends JPanel {
   public static final int SPRITE_WIDTH = 20;
   public static final int PANEL_WIDTH = 400;
   public static final int PANEL_HEIGHT = 400;
   private static final int MAX_MSTATE = 25;
   private static final int SPIN_TIMER_PERIOD = 16;
   private static final int SPRITE_STEP = 3;

   private int mState = 0;
   private int mX = (PANEL_WIDTH - SPRITE_WIDTH) / 2;
   private int mY = (PANEL_HEIGHT - SPRITE_WIDTH) / 2;
   private int oldMX = mX;
   private int oldMY = mY;
   private boolean moved = false;

   // an array of sprite images that are drawn sequentially
   private BufferedImage[] spriteImages = new BufferedImage[MAX_MSTATE];

   public AnimationPanel() {
      // create and start the main animation timer
      new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener()).start();
      setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
      setBackground(Color.white);
      createSprites(); // create the images
      setupKeyBinding();
   }

   private void setupKeyBinding() {
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inMap = getInputMap(condition);
      ActionMap actMap = getActionMap();

      // this uses an enum of Direction that holds ints for the arrow keys
      for (Direction direction : Direction.values()) {
         int key = direction.getKey();
         String name = direction.name();

         // add the key bindings for arrow key and shift-arrow key
         inMap.put(KeyStroke.getKeyStroke(key, 0), name);
         inMap.put(KeyStroke.getKeyStroke(key, InputEvent.SHIFT_DOWN_MASK), name);
         actMap.put(name, new MyKeyAction(this, direction));
      }
   }

   // create a bunch of buffered images and place into an array,
   // to be displayed sequentially
   private void createSprites() {
      for (int i = 0; i < spriteImages.length; i++) {
         spriteImages[i] = new BufferedImage(SPRITE_WIDTH, SPRITE_WIDTH,
                  BufferedImage.TYPE_INT_ARGB);
         Graphics2D g2 = spriteImages[i].createGraphics();
         g2.setColor(Color.red);
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         double theta = i * Math.PI / (2 * spriteImages.length);
         double x = SPRITE_WIDTH * Math.abs(Math.cos(theta)) / 2.0;
         double y = SPRITE_WIDTH * Math.abs(Math.sin(theta)) / 2.0;
         int x1 = (int) ((SPRITE_WIDTH / 2.0) - x);
         int y1 = (int) ((SPRITE_WIDTH / 2.0) - y);
         int x2 = (int) ((SPRITE_WIDTH / 2.0) + x);
         int y2 = (int) ((SPRITE_WIDTH / 2.0) + y);
         g2.drawLine(x1, y1, x2, y2);
         g2.drawLine(y1, x2, y2, x1);
         g2.dispose();
      }
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawImage(spriteImages[mState], mX, mY, null);
   }

   public void incrementX(boolean right) {
      oldMX = mX;
      if (right) {
         mX = Math.min(getWidth() - SPRITE_WIDTH, mX + SPRITE_STEP);
      } else {
         mX = Math.max(0, mX - SPRITE_STEP);
      }
      moved = true;
   }

   public void incrementY(boolean down) {
      oldMY = mY;
      if (down) {
         mY = Math.min(getHeight() - SPRITE_WIDTH, mY + SPRITE_STEP);
      } else {
         mY = Math.max(0, mY - SPRITE_STEP);
      }
      moved = true;
   }

   public void tick() {
      mState = (mState + 1) % MAX_MSTATE;
   }

   private class SpinTimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         tick();

         int delta = 20;
         int width = SPRITE_WIDTH + 2 * delta;
         int height = width;

         // make sure to erase the old image
         if (moved) {
            int x = oldMX - delta;
            int y = oldMY - delta;
            repaint(x, y, width, height);
         }

         int x = mX - delta;
         int y = mY - delta;

         // draw the new image
         repaint(x, y, width, height);
         moved = false;
      }
   }
}

enum Direction {
   UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);

   private int key;

   private Direction(int key) {
      this.key = key;
   }

   public int getKey() {
      return key;
   }
}

// Actions for the key binding
@SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
   private AnimationPanel draw;
   private Direction direction;

   public MyKeyAction(AnimationPanel draw, Direction direction) {
      this.draw = draw;
      this.direction = direction;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      switch (direction) {
      case UP:
         draw.incrementY(false);
         break;
      case DOWN:
         draw.incrementY(true);
         break;
      case LEFT:
         draw.incrementX(false);
         break;
      case RIGHT:
         draw.incrementX(true);
         break;

      default:
         break;
      }
   }
}



Вот еще один пример, который использует этот лист спрайтов:

, полученный из этого сайта .

Опять же, это пример рисования в методе paintComponent JPanel и использование привязок клавиш, чтобы указать, в каком направлении для перемещения.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class Mcve3 extends JPanel {
    private static final int PREF_W = 800;
    private static final int PREF_H = 640;
    private static final int TIMER_DELAY = 50;

    private int spriteX = 400;
    private int spriteY = 320;
    private SpriteDirection spriteDirection = SpriteDirection.RIGHT;
    private MySprite sprite = null;
    private Timer timer = null;

    public Mcve3() {
        try {
            sprite = new MySprite(spriteDirection, spriteX, spriteY);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        setBackground(Color.WHITE);

        setKeyBindings(SpriteDirection.LEFT, KeyEvent.VK_LEFT);
        setKeyBindings(SpriteDirection.RIGHT, KeyEvent.VK_RIGHT);
        setKeyBindings(SpriteDirection.FORWARD, KeyEvent.VK_DOWN);
        setKeyBindings(SpriteDirection.AWAY, KeyEvent.VK_UP);

        timer = new Timer(TIMER_DELAY, new TimerListener());
        timer.start();
    }

    private void setKeyBindings(SpriteDirection dir, int keyCode) {
        int condition = WHEN_IN_FOCUSED_WINDOW;
        InputMap inputMap = getInputMap(condition);
        ActionMap actionMap = getActionMap();

        KeyStroke keyPressed = KeyStroke.getKeyStroke(keyCode, 0, false);
        KeyStroke keyReleased = KeyStroke.getKeyStroke(keyCode, 0, true);

        inputMap.put(keyPressed, keyPressed.toString());
        inputMap.put(keyReleased, keyReleased.toString());

        actionMap.put(keyPressed.toString(), new MoveAction(dir, false));
        actionMap.put(keyReleased.toString(), new MoveAction(dir, true));
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        sprite.draw(g);
    }

    private class MoveAction extends AbstractAction {
        private SpriteDirection dir;
        private boolean released;

        public MoveAction(SpriteDirection dir, boolean released) {
            this.dir = dir;
            this.released = released;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (released) {
                sprite.setMoving(false);
            } else {
                sprite.setMoving(true);
                sprite.setDirection(dir);
            }
        }
    }

    private class TimerListener implements ActionListener {
        @Override
            public void actionPerformed(ActionEvent e) {
                if (sprite.isMoving()) {
                    sprite.tick();
                }
                repaint();
            }
    }

    private static void createAndShowGui() {
        Mcve3 mainPanel = new Mcve3();

        JFrame frame = new JFrame("MCVE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

class MySprite {
    private static final String SPRITE_SHEET_PATH = "http://"
            + "orig12.deviantart.net/7db3/f/2010/338/3/3/"
            + "animated_sprite_sheet_32x32_by_digibody-d3479l2.gif";
    private static final int MAX_MOVING_INDEX = 4;
    private static final int DELTA = 4;
    private SpriteDirection direction;
    private Map standingImgMap = new EnumMap<>(SpriteDirection.class);
    private Map> movingImgMap = new EnumMap<>(SpriteDirection.class);
    private int x;
    private int y;
    private boolean moving = false;
    private int movingIndex = 0;

    public MySprite(SpriteDirection direction, int x, int y) throws IOException {
        this.direction = direction;
        this.x = x;
        this.y = y;
        createSprites();
    }

    public void draw(Graphics g) {
        Image img = null;
        if (!moving) {
            img = standingImgMap.get(direction);
        } else {
            img = movingImgMap.get(direction).get(movingIndex);
        }
        g.drawImage(img, x, y, null);
    }

    private void createSprites() throws IOException {
        URL spriteSheetUrl = new URL(SPRITE_SHEET_PATH);
        BufferedImage img = ImageIO.read(spriteSheetUrl);

        // get sub-images (sprites) from the sprite sheet
        // magic numbers for getting sprites from sheet, all obtained by trial and error
        int x0 = 0;
        int y0 = 64;
        int rW = 32;
        int rH = 32;
        for (int row = 0; row < 4; row++) {
            SpriteDirection dir = SpriteDirection.values()[row];
            List imgList = new ArrayList<>();
            movingImgMap.put(dir, imgList);
            int rY = y0 + row * rH;
            for (int col = 0; col < 5; col++) {
                int rX = x0 + col * rW;
                BufferedImage subImg = img.getSubimage(rX, rY, rW, rH);
                if (col == 0) {
                    // first image is standing
                    standingImgMap.put(dir, subImg);
                } else {
                    // all others are moving
                    imgList.add(subImg);
                }
            }
        }
    }

    public SpriteDirection getDirection() {
        return direction;
    }

    public void setDirection(SpriteDirection direction) {
        if (this.direction != direction) {
            setMoving(false);
        }
        this.direction = direction;

    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public boolean isMoving() {
        return moving;
    }

    public void setMoving(boolean moving) {
        this.moving = moving;
        if (!moving) {
            movingIndex = 0;
        }
    }

    public void tick() {
        if (moving) {
            switch (direction) {
            case RIGHT:
                x += DELTA;
                break;
            case LEFT:
                x -= DELTA;
                break;
            case FORWARD:
                y += DELTA;
                break;
            case AWAY:
                y -= DELTA;
            }
            movingIndex++;
            movingIndex %= MAX_MOVING_INDEX;
        }
    }

    public int getMovingIndex() {
        return movingIndex;
    }

    public void setMovingIndex(int movingIndex) {
        this.movingIndex = movingIndex;
    }

}

enum SpriteDirection {
    FORWARD, LEFT, AWAY, RIGHT
}

851
задан Andres Gardiol 29 May 2019 в 01:17
поделиться

8 ответов

constructor() используется для внедрения зависимости.

ngOnInit(), ngOnChanges() и ngOnDestroy() и т. Д. Являются методами жизненного цикла. ngOnChanges() будет вызываться первым до ngOnInit(), когда значение связанного свойства изменяется, оно НЕ будет вызываться, если нет изменений. ngOnDestroy() вызывается при удалении компонента. Чтобы использовать его, OnDestroy должно быть implement издано классом.

0
ответ дан student 29 May 2019 в 01:17
поделиться

constructor вызывается, когда Angular «создает / конструирует» компонент. Метод ngOnInit представляет собой ловушку, которая представляет часть инициализации жизненного цикла компонента. Хорошей практикой является использование его только для сервисного внедрения :

constructor(private 
    service1: Service1,
    service2: Service2
){};

Даже если это возможно, вам не следует выполнять какую-то «работу» внутри. Если вы хотите запустить какое-то действие, которое должно произойти при «инициализации» компонента, используйте ngOnInit:

ngOnInit(){
    service1.someWork();
};

Более того, действия, которые включают входные свойства , поступающие из родительского компонента , не может быть сделано в конструкторе. Они должны быть размещены в методе ngOnInit или другом крючке. То же самое относится к элементу, связанному с представлением (DOM), например, элементы viewchild :

@Input itemFromParent: string;
@ViewChild('childView') childView;

constructor(){
    console.log(itemFromParent); // KO
    // childView is undefined here
};

ngOnInit(){
    console.log(itemFromParent); // OK
    // childView is undefined here, you can manipulate here
};
1
ответ дан veben 29 May 2019 в 01:17
поделиться

Конструктор является первым, и это иногда случается, когда @input data имеет значение null! поэтому мы используем Constructor для объявления сервисов, и ngOnInit происходит после. Пример для contrutor:

 constructor(translate: TranslateService, private oauthService: OAuthService) {
    translate.setDefaultLang('En');
        translate.use('En');}

Пример для onInit:

ngOnInit() {
    this.items = [
      { label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
      { label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}

Я думаю, что onInit похож на InitialComponents () в winForm.

2
ответ дан user1012506 29 May 2019 в 01:17
поделиться

Оба метода имеют разные цели / обязанности. Задача конструктора (который поддерживается языком) состоит в том, чтобы убедиться, что инвариант представления выполняется. В противном случае указывается, чтобы убедиться, что экземпляр действителен, давая правильные значения членам. Разработчик должен решить, что означает «правильный».

Задача метода onInit () (который является угловым понятием) состоит в том, чтобы разрешить вызовы метода для правильного объекта (инвариант представления). Каждый метод должен, в свою очередь, убедиться, что инвариант представления сохраняется, когда метод завершается.

Конструктор должен использоваться для создания «правильных» объектов, метод onInit дает вам возможность вызывать вызовы методов в четко определенном экземпляре.

4
ответ дан Bruno Ranschaert 29 May 2019 в 01:17
поделиться

Чтобы проверить это, я написал этот код, позаимствованный из NativeScript Tutorial :

user.ts

export class User {
    email: string;
    password: string;
    lastLogin: Date;

    constructor(msg:string) {        
        this.email = "";
        this.password = "";
        this.lastLogin = new Date();
        console.log("*** User class constructor " + msg + " ***");
    }

    Login() {
    }
}

login.component.ts

import {Component} from "@angular/core";
import {User} from "./../../shared/user/user"

@Component({
  selector: "login-component",
  templateUrl: "pages/login/login.html",
  styleUrls: ["pages/login/login-common.css", "pages/login/login.css"]
})
export class LoginComponent {

  user: User = new User("property");  // ONE
  isLoggingIn:boolean;

  constructor() {    
    this.user = new User("constructor");   // TWO
    console.log("*** Login Component Constructor ***");
  }

  ngOnInit() {
    this.user = new User("ngOnInit");   // THREE
    this.user.Login();
    this.isLoggingIn = true;
    console.log("*** Login Component ngOnInit ***");
  }

  submit() {
    alert("You’re using: " + this.user.email + " " + this.user.lastLogin);
  }

  toggleDisplay() {
    this.isLoggingIn = !this.isLoggingIn;
  }

}

Выход консоли

JS: *** User class constructor property ***  
JS: *** User class constructor constructor ***  
JS: *** Login Component Constructor ***  
JS: *** User class constructor ngOnInit ***  
JS: *** Login Component ngOnInit ***  
17
ответ дан abbaf33f 29 May 2019 в 01:17
поделиться

Я просто добавлю одну важную вещь, которая была пропущена в объяснениях выше и объясняет, когда вы ДОЛЖНЫ использовать ngOnInit.

Если вы делаете какие-либо манипуляции с DOM компонента через, например, ViewChildren , ContentChildren или ElementRef , ваши собственные элементы не будут доступны на этапе конструктора.

Однако, поскольку ngOnInit происходит после того, как компонент был создан и вызваны проверки (ngOnChanges), вы можете получить доступ к DOM на этом этапе.

export class App implements OnInit, AfterViewInit, AfterContentInit {
  @Input() myInput: string;
  @ViewChild() myTemplate: TemplateRef<any>;
  @ContentChild(ChildComponent) myComponent: ChildComponent; 

  constructor(private elementRef: ElementRef) {
     // this.elementRef.nativeElement is undefined here
     // this.myInput is undefined here
     // this.myTemplate is undefined here
     // this.myComponent is undefine here
  }

  ngOnInit() {
     // this.elementRef.nativeElement can be used from here on
     // value of this.myInput is passed from parent scope
     // this.myTemplate and this.myComponent are still undefined
  }
  ngAfterContentInit() {
     // this.myComponent now gets projected in and can be accessed
     // this.myTemplate is still undefined
  }

  ngAfterViewInit() {
     // this.myTemplate can be used now as well
  }
}
33
ответ дан Miroslav Jonas 29 May 2019 в 01:17
поделиться

Механизм связи TheВ

@Input

В обрабатывается, поскольку часть followingВ изменяет detectionВ фазу, таким образом, входная привязка не доступна в конструкторе.

1
ответ дан Mojtaba Nava 4 November 2019 в 06:35
поделиться

Конструктор

функция конструктора идет с каждым классом, конструкторы не характерны для Углового, но являются понятиями, полученными из Объектно-ориентированного проектирования. Конструктор создает экземпляр класса компонента.

OnInit

Эти ngOnInit функция является одним из Углового component’s жизненного цикла методы. Методы жизненного цикла (или рычаги) в Угловых компонентах позволяют Вам выполнять часть кода на различных этапах жизни компонента. В отличие от метода конструктора, ngOnInit метод прибывает из интерфейса Angular (OnInit), который компонент должен реализовать для использования этого метода. ngOnInit метод называют вскоре после того, как компонент создается.

0
ответ дан 19 December 2019 в 20:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: