Создание многопоточного приложения с элементами вывода графической информации - Java
Формулировка задачи:
В общем кодил тут програмку
Суть заключается в том, что по экрану летают ромбы
В меню управления есть три пункта
1. Приостановка выборочных фигур
2. Приостановка всех фигур
3. И возобновление движения
суть вопроса заключается в том
никак не могу понять как прописать что при нажатии кнопки приостановка выборочных фигур остонавливаются только те фигуры которые находят в диапазоне (угол скорости фигуры находится между 180 и 270 градусов (3-я четверть))
Прикрепил архив с кодом
программирую в Eclipse
Помогите разобраться)
Решение задачи: «Создание многопоточного приложения с элементами вывода графической информации»
textual
Листинг программы
MainFrame package mainPackage; import java.awt.BorderLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; @SuppressWarnings("serial") public class MainFrame extends JFrame { // Константы, задающие размер окна приложения, если оно // не распахнуто на весь экран private static final int WIDTH = 700; private static final int HEIGHT = 500; private JMenuItem pauseMenuItem; private JMenuItem resumeMenuItem; // Поле, по которому движутся фигуры private Field field = new Field(); // Конструктор главного окна приложения public MainFrame() { super("Программирование и синхронизация потоков"); setSize(WIDTH, HEIGHT); Toolkit kit = Toolkit.getDefaultToolkit(); // Отцентрировать окно приложения на экране setLocation((kit.getScreenSize().width - WIDTH)/2, (kit.getScreenSize().height - HEIGHT)/2); // Установить начальное состояние окна развернутым на весь экран setExtendedState(MAXIMIZED_BOTH); // Создать меню JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu figuresMenu = new JMenu("Фигуры"); Action addFigureAction = new AbstractAction("Добавить фигуру") { public void actionPerformed(ActionEvent event) { field.addFigure(); if (!pauseMenuItem.isEnabled() && !resumeMenuItem.isEnabled()) { // Ни один из пунктов меню не является // доступным - сделать доступным "Паузу" pauseMenuItem.setEnabled(true); } } }; menuBar.add(figuresMenu); figuresMenu.add(addFigureAction); JMenu controlMenu = new JMenu("Управление"); menuBar.add(controlMenu); pauseMenuItem = controlMenu.add(pauseAction); pauseMenuItem.setEnabled(false); Action resumeAction2 = new AbstractAction("Остановка рандомных фигурок"){ public void actionPerformed(ActionEvent event) { field.paused2(); pauseMenuItem.setEnabled(true); resumeMenuItem.setEnabled(true); pauseSelect.setEnabled(false); } }; Action pauseAction = new AbstractAction("Приостановить движение"){ public void actionPerformed(ActionEvent event) { field.pause(); pauseMenuItem.setEnabled(false); resumeMenuItem.setEnabled(true); } }; pauseMenuItem = controlMenu.add(pauseAction); pauseMenuItem.setEnabled(false); Action resumeAction = new AbstractAction("Возобновить движение") { public void actionPerformed(ActionEvent event) { field.resume(); pauseMenuItem.setEnabled(true); resumeMenuItem.setEnabled(false); } }; resumeMenuItem = controlMenu.add(resumeAction); resumeMenuItem.setEnabled(false); // Добавить в центр граничной компоновки поле Field getContentPane().add(field, BorderLayout.CENTER); } // Главный метод приложения public static void main(String[] args) { // Создать и сделать видимым главное окно приложения MainFrame frame = new MainFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } MovingFigure package mainPackage; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; public class MovingFigure implements Runnable { // Максимальный размер половины стороны квадрата, описывающего фигуру private static final int maxFramingSquareHalfSize = 60; // Минимальный размер половины стороны квадрата, описывающего фигуру private static final int minFramingSquareHalfSize = 10; // Минимальное время, на которое может засыпать поток после каждого смещения private static final int minSleepTime = 1; private Field field; // Характеристики фигуры // Половина стороны квадрата, описывающего фигуру private int framingSquareHalfSize; // Цвет для заливки внутреннего простанства фигуры private Color color; // Штриховка для рисования границы фигуры float [] dash = {8,2,8,2,2,2,2,2,4,2,4,2}; private Stroke stroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10.0f, dash, 0.0f); // Текущие координаты центра фигуры private double x; private double y; // Время сна потока между двумя пересчетами координат private int sleepTime; // Вертикальная и горизонтальная компоненты смещения private double shiftX; private double shiftY; //Конструктор класса MovingFigure public MovingFigure(Field field) { //Необходимо иметь ссылку на поле, по которому передвигается фигура, //чтобы отслеживать выход за его пределы через getWidth(), getHeight() this.field = field; //Случайно выбираем размер половины стороны квадрата, описывающего фигуру framingSquareHalfSize = minFramingSquareHalfSize + new Double( Math.random()*(maxFramingSquareHalfSize - minFramingSquareHalfSize)).intValue(); //Абсолютное значение времени сна потока зависит от размера фигуры, //чем он больше, тем больше sleepTime = 16 - new Double(Math.round(210 / framingSquareHalfSize)).intValue(); if (sleepTime < minSleepTime) sleepTime = minSleepTime; //Начальное направление движения случайно, угол в пределах от 0 до 2PI double angle = Math.random()*2*Math.PI; //Вычисляются горизонтальная и вертикальная компоненты смещения shiftX = 3*Math.cos(angle); shiftY = 3*Math.sin(angle); //Цвет фигуры выбирается случайно color = new Color((float)Math.random(), (float)Math.random(), (float)Math.random()); //Начальное положение фигуры случайно x = framingSquareHalfSize + Math.random()* (field.getSize().getWidth()-2*framingSquareHalfSize); y = framingSquareHalfSize + Math.random()* (field.getSize().getHeight()-2*framingSquareHalfSize); //Создаем новый экземпляр потока, передавая аргументом //ссылку на объект класса, реализующего Runnable (т.е. на себя) Thread thisThread = new Thread(this); //Запускаем поток thisThread.start(); } //Метод run() исполняется внутри потока. Когда он завершает работу, //то завершается и поток public void run() { try { //Крутим бесконечный цикл, т.е. пока нас не прервут, //мы не намерены завершаться while(true) { //Синхронизация потоков выполняется на объекте field. //Если движение разрешено - управление будет возвращено в метод. //В противном случае - активный поток заснет field.canMove(this); if (x + shiftX <= framingSquareHalfSize) { //Достигли левой стенки, отскакиваем право shiftX = -shiftX; x = framingSquareHalfSize; } else if (x + shiftX >= field.getWidth()- framingSquareHalfSize) { // Достигли правой стенки, отскок влево shiftX = -shiftX; x=new Double(field.getWidth()- framingSquareHalfSize).intValue(); } else if (y + shiftY <= framingSquareHalfSize) { // Достигли верхней стенки shiftY = -shiftY; y = framingSquareHalfSize; } else if (y + shiftY >= field.getHeight()- framingSquareHalfSize) { // Достигли нижней стенки shiftY = -shiftY; y=new Double(field.getHeight()- framingSquareHalfSize).intValue(); } else { // Просто смещаемся x += shiftX; y += shiftY; } // Засыпаем на sleepTime миллисекунд Thread.sleep(sleepTime); } } catch (InterruptedException ex) { // Если нас прервали, то ничего не делаем // и просто выходим (завершаемся) } } // Метод прорисовки самой себя public void paint (Graphics2D canvas) { Rectangle2D.Double rect1 = new Rectangle2D.Double(x-framingSquareHalfSize, y-framingSquareHalfSize, 2*framingSquareHalfSize, 2*framingSquareHalfSize); Rectangle2D.Double rect2 = new Rectangle2D.Double(x-framingSquareHalfSize, y-framingSquareHalfSize, 2*framingSquareHalfSize, 2*framingSquareHalfSize); Area figure = new Area(rect1); AffineTransform at = AffineTransform.getRotateInstance( Math.PI/3, rect1.getCenterX(), rect2.getCenterY()); figure.transform(at); //figure.add(new Area(rect2)); canvas.setPaint(color); canvas.fill(figure); canvas.setStroke(stroke); canvas.setPaint(Color.black); canvas.draw(figure); //canvas.draw(line); } } Field package mainPackage; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.JPanel; import javax.swing.Timer; @SuppressWarnings("serial") public class Field extends JPanel { // Флаг приостановки движения private boolean paused; // Динамический список движущихся фигур private ArrayList<MovingFigure> figures = new ArrayList<MovingFigure>(10); // Класс таймер отвечает за регулярную генерацию событий ActionEvent // При создании его экземпляра используется анонимный класс, // реализующий интерфейс ActionListener private Timer repaintTimer = new Timer(10, new ActionListener() { public void actionPerformed(ActionEvent ev) { // Задача обработчика события ActionEvent - перерисовка окна repaint(); } }); // Конструктор класса Field public Field() { // Установить цвет заднего фона белым setBackground(Color.WHITE); // Запустить таймер repaintTimer.start(); } // Унаследованный от JPanel метод перерисовки компонента public void paintComponent(Graphics g) { // Вызвать версию метода, унаследованную от предка super.paintComponent(g); Graphics2D canvas = (Graphics2D) g; // Последовательно запросить прорисовку от всех фигур из списка for (MovingFigure figure: figures) figure.paint(canvas); } // Метод добавления новой фигуры в список public void addFigure() { // Заключается в добавлении в список нового экземпляра MovingFigure // Всю инициализацию положения, скорости, размера, цвета // MovingFigure выполняет в своем конструкторе figures.add(new MovingFigure(this)); } // Cинхронизированный метод приостановки движения фигур // (только один поток может одновременно быть внутри) public synchronized void pause() { // Включить режим паузы paused = true; } // Cинхронизированный метод возобновления движения фигур // (только один поток может одновременно быть внутри) public synchronized void resume() { // Выключить режим паузы paused = false; // Будим все ожидающие продолжения потоки notifyAll(); } // Синхронизированный метод проверки, может ли фигура двигаться // (не включен ли режим паузы?) public synchronized void canMove(MovingFigure figure) throws InterruptedException { // Если режим паузы включен, то поток, зашедший // внутрь данного метода, засыпает if (paused) wait(); } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д