diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c995aa5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.debug.settings.onBuildFailureProceed": true +} \ No newline at end of file diff --git a/CarAnimation.java b/CarAnimation.java new file mode 100644 index 0000000..d20dbbb --- /dev/null +++ b/CarAnimation.java @@ -0,0 +1,269 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; + +public class CarAnimation extends JFrame { + + public CarAnimation() { + setTitle("Анимация с машинкой"); + setSize(300, 200); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setLocationRelativeTo(null); + + // панель анимации + AnimationPanel panel = new AnimationPanel(); + JMenuBar menuBar = new JMenuBar(); + + // меню файл + JMenu fileMenu = new JMenu("Файл"); + JMenuItem useFolderItem = new JMenuItem("Использовать картинки из папки"); + JMenuItem exitItem = new JMenuItem("Выход"); + + useFolderItem.addActionListener(e -> { + JFileChooser chooser = new JFileChooser(); + // только папки + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogTitle("Выберите папку с изображениями машинок"); + + int returnVal = chooser.showOpenDialog(CarAnimation.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + // выбранная папка в панель + panel.loadImagesFromFolder(chooser.getSelectedFile()); + } + }); + exitItem.addActionListener(e -> System.exit(0)); + + fileMenu.add(useFolderItem); + fileMenu.add(exitItem); + + // меню скорость + JMenu speedMenu = new JMenu("Скорость машинки"); + JMenuItem slowSpeed = new JMenuItem("Медленно"); + JMenuItem normalSpeed = new JMenuItem("Нормально"); + JMenuItem fastSpeed = new JMenuItem("Быстро"); + + slowSpeed.addActionListener(e -> panel.setSpeed(300)); + normalSpeed.addActionListener(e -> panel.setSpeed(100)); + fastSpeed.addActionListener(e -> panel.setSpeed(30)); + + speedMenu.add(slowSpeed); + speedMenu.add(normalSpeed); + speedMenu.add(fastSpeed); + + // меню справка + JMenu helpMenu = new JMenu("Справка"); + JMenuItem aboutItem = new JMenuItem("О программе"); + aboutItem.addActionListener(e -> JOptionPane.showMessageDialog(this, "Анимация машинки\nУправление: наведите мышь на окно.")); + helpMenu.add(aboutItem); + + // сборка менюбара + menuBar.add(fileMenu); + menuBar.add(speedMenu); + menuBar.add(helpMenu); + setJMenuBar(menuBar); + + add(panel); + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + CarAnimation app = new CarAnimation(); + app.setVisible(true); + }); + } +} + +class AnimationPanel extends JPanel implements MouseListener, java.awt.event.MouseMotionListener { + private final BufferedImage[] frames; + private int currentFrameIndex = 0; + private volatile boolean isMouseInside = false; // флаг для управления потоком + private final Thread animationThread; + private volatile int speedDelay = 100; // переменная для скорости + private BufferedImage[] currentFrames; // чтобы можно было менять массив картинок + private volatile boolean isFolderMode = false; // true, если загружены файлы из папки + + // метод для изменения скорости + public void setSpeed(int newSpeed) { + this.speedDelay = newSpeed; + } + + // метод для загрузки картинок из папки + public void loadImagesFromFolder(File folder) { + // список всех файлов в папке + File[] files = folder.listFiles(); + + if (files == null || files.length == 0) { + JOptionPane.showMessageDialog(this, "Папка пуста!"); + return; + } + + // только картинки (png, jpg, gif) + File[] imageFiles = Arrays.stream(files) + .filter(f -> f.getName().toLowerCase().endsWith(".png") || + f.getName().toLowerCase().endsWith(".jpg") || + f.getName().toLowerCase().endsWith(".jpeg") || + f.getName().toLowerCase().endsWith(".gif")) + .sorted(Comparator.comparing(File::getName)) // сортировка по имени + .toArray(File[]::new); + + if (imageFiles.length == 0) { + JOptionPane.showMessageDialog(this, "В выбранной папке нет подходящих изображений!"); + return; + } + + // найденные файлы в массив BufferedImage + BufferedImage[] newFrames = new BufferedImage[imageFiles.length]; + try { + for (int i = 0; i < imageFiles.length; i++) { + newFrames[i] = ImageIO.read(imageFiles[i]); + } + + // обновляем массив в панели + this.currentFrames = newFrames; + this.isFolderMode = true; + this.currentFrameIndex = 0; // Сбрасываем кадр на первый + this.repaint(); + + JOptionPane.showMessageDialog(this, "Загружено кадров: " + newFrames.length); + + } catch (IOException e) { + JOptionPane.showMessageDialog(this, "Ошибка при чтении файлов: " + e.getMessage()); + e.printStackTrace(); + } + } + + // private BufferedImage[] createDummyCarArray(Color color) { + // BufferedImage[] newFrames = new BufferedImage[5]; + // for (int i = 0; i < 5; i++) { + // newFrames[i] = createDummyCar(i, 5, color); // цвет в метод отрисовки + // } + // return newFrames; + // } + + private BufferedImage createDummyCar(int frame, int total, Color color) { + BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = img.createGraphics(); + int offset = frame * 10; + g.setColor(color); // Используем переданный цвет + g.fillRect(20 + offset, 40, 100, 40); + g.setColor(Color.BLACK); + g.fillOval(30 + offset, 70, 20, 20); + g.fillOval(90 + offset, 70, 20, 20); + g.dispose(); + return img; + } + + public AnimationPanel() { + // подготовка изображений + frames = prepareImages(); + this.currentFrames = prepareImages(); + + // создание и запуск потока анимации + animationThread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + // условие только если мышь внутри окна + if (isMouseInside) { + currentFrameIndex = (currentFrameIndex + 1) % frames.length; + repaint(); + Thread.sleep(speedDelay); + } else { + Thread.sleep(50); + } + } catch (InterruptedException e) { + break; // выход + } + } + } + }); + animationThread.start(); + addMouseListener(this); + addMouseMotionListener(this); + } + + private BufferedImage[] prepareImages() { + int frameCount = 5; // количество кадров + this.isFolderMode = false; + BufferedImage[] imgArray = new BufferedImage[frameCount]; + + // создание болванок + for (int i = 0; i < frameCount; i++) { + imgArray[i] = createDummyCar(i, frameCount); + } + + return imgArray; + } + + // рисование на BufferedImage + private BufferedImage createDummyCar(int frame, int total) { + BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = img.createGraphics(); + + // корпус + int offset = frame * 10; + g.setColor(Color.RED); + g.fillRect(20 + offset, 40, 100, 40); + + // крыша + g.setColor(Color.RED); + g.fillRect(40 + offset, 20, 50, 25); + + // колеса + g.setColor(Color.BLACK); + g.fillOval(30 + offset, 70, 20, 20); + g.fillOval(90 + offset, 70, 20, 20); + + g.dispose(); + return img; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + // очистка фона + g.setColor(Color.WHITE); + g.fillRect(0, 0, getWidth(), getHeight()); + + // отрисовка в центре экрана + if (frames.length > 0) { + int x = (getWidth() - frames[0].getWidth()) / 2; + int y = (getHeight() - frames[0].getHeight()) / 2; + g.drawImage(currentFrames[currentFrameIndex], x, y, this); + } + + if (isFolderMode) { + g.setColor(Color.BLUE); + g.drawString("Кадров в папке: " + currentFrames.length, 10, 40); + } + + // подсказка + g.setColor(Color.GRAY); + g.drawString(isMouseInside ? "Статус: Анимация работает" : "Статус: Пауза (мышь снаружи)", 10, 20); + } + + // Реализация методов MouseListener + @Override + public void mouseEntered(MouseEvent e) { + isMouseInside = true; // запуск + } + + @Override + public void mouseExited(MouseEvent e) { + isMouseInside = false; // остановка + } + + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) {} + @Override public void mouseReleased(MouseEvent e) {} + @Override public void mouseMoved(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) {} +} \ No newline at end of file diff --git a/example/frame_001.png b/example/frame_001.png new file mode 100644 index 0000000..13ee260 Binary files /dev/null and b/example/frame_001.png differ diff --git a/example/frame_002.png b/example/frame_002.png new file mode 100644 index 0000000..6cb8683 Binary files /dev/null and b/example/frame_002.png differ diff --git a/example/frame_003.png b/example/frame_003.png new file mode 100644 index 0000000..a1327bd Binary files /dev/null and b/example/frame_003.png differ diff --git a/example/frame_004.png b/example/frame_004.png new file mode 100644 index 0000000..6001256 Binary files /dev/null and b/example/frame_004.png differ diff --git a/example/frame_005.png b/example/frame_005.png new file mode 100644 index 0000000..c5c55be Binary files /dev/null and b/example/frame_005.png differ diff --git a/manifest.txt b/manifest.txt new file mode 100644 index 0000000..6227fd1 --- /dev/null +++ b/manifest.txt @@ -0,0 +1 @@ +Main-Class: CarAnimation