Перекрытие краски GUI - PullRequest
0 голосов
/ 16 мая 2018

Так что в основном я пытаюсь создать обратный отсчет, когда мой код запускается, и это нормально, и работает единственная проблема, с которой я сталкиваюсь, - вместо того, чтобы числа исчезали и заменялись новым значением i, они оставляли новое значениеперекрывает существующий номер.Я пытался использовать repaint (), чтобы это исправить, но это не работает.Мне интересно, есть ли что-то, что я пропускаю или я должен попробовать другой способ.

вот код для таймера:

public void timer (Graphics g,int x){
    x=550;

    for (int i = time;i>0;i--){
        g.setColor(deepPlum);
        g.setFont(new Font("Monospaced", Font.PLAIN, 25));
        g.drawString("time: "+i, x, 650);
        repaint();

    } 
}

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

На "догадку"

Мне не нравится угадывать, но, похоже, мы не получим работающий пример, который бы дал четкое представление о том, как возникла проблема.

Данные ...

Я вызываю метод super paint, но в методе paint. Я знаю, что это хорошо, потому что все мои другие графики работают нормально.

Это "предполагает", что timer был назван как часть обычного цикла "рисования" Swing. Если это правда, это объясняет причину проблемы.

Этот ...

public void timer (Graphics g,int x){
    x=550;

    for (int i = time;i>0;i--){
        g.setColor(deepPlum);
        g.setFont(new Font("Monospaced", Font.PLAIN, 25));
        g.drawString("time: "+i, x, 650);
        repaint();

    } 
}

просто рисует все числа друг над другом, каждый раз, когда происходит цикл рисования, что на самом деле не так, как следует рисовать таймер обратного отсчета.

Вместо этого следует просто рисовать оставшееся время как единое значение, а не пытаться рисовать их все.

Вы можете думать о «цикле рисования» как о «кадре», он рисует моментальный снимок текущего состояния компонента. Вам нужно нарисовать несколько таких «кадров», чтобы оживить изменения от одного момента времени к другому.

Я бы настоятельно рекомендовал вам уделить время прочтению Выполнение пользовательской рисования и Рисование в AWT и Swing , чтобы лучше понять, как на самом деле работает рисование.

Без дополнительных доказательств я бы предположил, что Swing Timer будет лучшим решением. Это можно использовать для расчета оставшегося времени и составления графика repaint на регулярной основе.

Поскольку мне кажется, что я много такого рода делаю, я обернул основные функциональные возможности в простой класс Counter, который имеет "продолжительность" (или время выполнения) и может вычислить duration, в котором он работает, remaining время и progress в процентах от duration и runTime, вероятно, больше, чем вам нужно, но это дает вам основы для начала.

Поскольку рисование является неточным искусством (время между циклами рисования является переменным, даже при использовании Timer), я использовал подход, основанный на времени, а не простой «счетчик». Это дает вам гораздо более высокий уровень точности при работе со сценариями такого типа

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                // The following two lines just set up the
                // "default" size of the frame
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JComponent {

        private Counter counter;

        public TestPane() {
            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (counter == null) {
                        counter = new Counter(Duration.of(10, ChronoUnit.SECONDS));
                        counter.start();
                    }
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (counter != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                FontMetrics fm = g2d.getFontMetrics();

                long time = counter.getRemaining().getSeconds();

                int x = (getWidth() - fm.stringWidth(Long.toString(time))) / 2;
                int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
                g2d.drawString(Long.toString(time), x, y);
                g2d.dispose();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public static class Counter {

        private Duration length;
        private LocalDateTime startedAt;

        public Counter(Duration length) {
            this.length = length;
        }

        public Duration getLength() {
            return length;
        }

        public void start() {
            startedAt = LocalDateTime.now();
        }

        public void stop() {
            startedAt = null;
        }

        public Duration getDuration() {
            if (startedAt == null) {
                return null;
            }
            Duration duration = Duration.between(startedAt, LocalDateTime.now());
            if (duration.compareTo(getLength()) > 0) {
                duration = getLength();
            }
            return duration;
        }

        public Double getProgress() {
            if (startedAt == null) {
                return null;
            }
            Duration duration = getDuration();
            return Math.min(1.0, (double) duration.toMillis() / length.toMillis());
        }

        public Duration getRemaining() {
            if (startedAt == null) {
                return null;
            }
            Duration length = getLength();
            Duration time = getDuration();

            LocalDateTime endTime = startedAt.plus(length);
            LocalDateTime runTime = startedAt.plus(time);

            Duration duration = Duration.between(runTime, endTime);
            if (duration.isNegative()) {
                duration = Duration.ZERO;
            }

            return duration;
        }
    }

}

Прежде чем кто-то скажет мне, как clearRect решит проблему, важно отметить, что clearRect сделает две вещи. Во-первых, он будет отображать только «последнее» значение цикла, которое явно не то, что хочет OP, и заполнит указанную область текущим фоновым цветом контекста Graphics, который «может» не быть ОП хочет (так как он закрасит красивый прямоугольник поверх того, что когда-либо было нарисовано до него).

При правильном использовании система рисования Swing подготовит контекст Graphics ДО вызова метода paint компонента, что делает необходимость использования clearRect mute

0 голосов
/ 16 мая 2018

Вызовите clearRect, чтобы восстановить фон для прямоугольной области перед повторным рисованием

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...