Работа с таймером Swing: создание беспорядка

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

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

Код:

import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import java.awt.Toolkit;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;

public class Reminder 
{
    static   JFrame frame;
    Toolkit toolkit;
    Timer timer;
    int point=0,temp=0,hil=0,point2=0;long time1=0,time2=0;
    static   StyledDocument doc;
    static   JTextPane textpane;
    String[] arr={"Tes"," hiiii"," what"," happpn"};
    int i=0;
    int[] a=new int[5];

    public Reminder() 
    {
        a[0]=1000;
        a[1]=900;
        a[2]=300;
        a[3]=1500;
        a[4]=1700;

        ActionListener actionListener = new ActionListener() 
        {
            public void actionPerformed(ActionEvent actionEvent) 
            {
                point =arr[i].length();
                temp=point+1;
                time1=System.currentTimeMillis();
                new Thread(new t1()).start();
            }
        };

        timer = new Timer(a[i], actionListener);
        timer.setInitialDelay(0);
        timer.start();
    }

    public  class t1 implements Runnable
    {     /* true idea to use current time is beacuse i want to check and make 
sure that the time taken since the timer started, and the present time should
not  exceed the time given in the array in any case*/   
        public void run() 
        {
            try
            {
                time2=System.currentTimeMillis();
                while(time2-time1<=a[i]-200){Thread.sleep((long) (a[i] / (arr[i].length() * 4)));
                if(hil<=temp-1)
                {
                    doc.setCharacterAttributes(point2,hil, textpane.getStyle("Red"), true);}
                    hil++;
                    time2=System.currentTimeMillis();
                }
                doc.setCharacterAttributes(point2,point+1, textpane.getStyle("Red"), true);
                point2+=point;hil=0;i++;
                timer.setDelay(a[i]);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void newcompo()
    {
        JPanel panel = new JPanel();
        doc = (StyledDocument) new DefaultStyledDocument();
        textpane = new JTextPane(doc);
        textpane.setText("Test hiiii what happpn");
        javax.swing.text.Style style = textpane.addStyle("Red", null);
        StyleConstants.setForeground(style, Color.RED);
        panel.add(textpane);
        frame.add(panel);
        frame.pack();
    }

    public static void main(String args[]) throws InterruptedException
                                                                ,    InvocationTargetException 
    {
          SwingUtilities.invokeAndWait(new Runnable() 
          {
            @Override
            public void run() 
            {
                frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.setVisible(true);

                newcompo();
                Reminder aa=  new Reminder();
            }
        });
    }
}

Любые предложения? Как я могу упростить?

ОБНОВЛЕНИЕ ДЛЯ ОШИБКИ

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class KaraokeTest {

private int[] timingsArray = {1000, 900, 300, 1500};//word/letters timings
private String[] individualWordsToHighlight = {"Tes", " hiiii", " what", " happpn"};//each individual word/letters to highlight
private int count = 0;
private final JTextPane jtp = new JTextPane();
private final JButton startButton = new JButton("Start");
private final JFrame frame = new JFrame();

public KaraokeTest() {
    initComponents();
}

private void initComponents() {
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);

    for (String s : individualWordsToHighlight) {
        String tmp = jtp.getText();
        jtp.setText(tmp + s);
    }
    jtp.setEditable(false);

    startButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            startButton.setEnabled(false);
            count = 0;

            //create Arrays of individual letters and their timings
            final ArrayList<String> chars = new ArrayList<>();
            final ArrayList<Integer> charsTiming = new ArrayList<>();

            for (String s : individualWordsToHighlight) {
                for (int i = 0; i < s.length(); i++) {
                    chars.add(String.valueOf(s.charAt(i)));
                    System.out.println(String.valueOf(s.charAt(i)));
                }
            }

            for (int x = 0; x < timingsArray.length; x++) {
                for (int i = 0; i < individualWordsToHighlight[x].length(); i++) {
                    charsTiming.add(timingsArray[x] / individualWordsToHighlight[x].length());
                    System.out.println(timingsArray[x] / individualWordsToHighlight[x].length());
                }
            }

            new Timer(1, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (count < charsTiming.size()) {
                        highlightNextWord();
                        //restart timer with new timings
                        ((Timer) ae.getSource()).setInitialDelay(charsTiming.get(count));
                        ((Timer) ae.getSource()).restart();
                    } else {//we are at the end of the array
                        reset();
                        ((Timer) ae.getSource()).stop();//stop the timer
                    }
                    count++;//increment counter
                }
            }).start();
        }
    });

    frame.add(jtp, BorderLayout.CENTER);
    frame.add(startButton, BorderLayout.SOUTH);

    frame.pack();
    frame.setVisible(true);
}

private void reset() {
    startButton.setEnabled(true);
    jtp.setText("");
    for (String s : individualWordsToHighlight) {
        String tmp = jtp.getText();
        jtp.setText(tmp + s);
    }
    JOptionPane.showMessageDialog(frame, "Done");
}

private void highlightNextWord() {
    //we still have words to highlight
    int sp = 0;
    for (int i = 0; i < count + 1; i++) {//get count for number of letters in words (we add 1 because counter is only incrementd after this method is called)
        sp += 1;
    }
    //highlight words
    Style style = jtp.addStyle("RED", null);
    StyleConstants.setForeground(style, Color.RED);
    ((StyledDocument) jtp.getDocument()).setCharacterAttributes(0, sp, style, true);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new KaraokeTest();
        }
    });
}
}

Дает мне исключение:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Uncompilable source code - illegal start of type
    at KaraokeTest$1.actionPerformed(KaraokeTest.java:47)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
    at java.awt.Component.processMouseEvent(Component.java:6263)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
    at java.awt.Component.processEvent(Component.java:6028)
    at java.awt.Container.processEvent(Container.java:2041)
    at java.awt.Component.dispatchEventImpl(Component.java:4630)
    at java.awt.Container.dispatchEventImpl(Container.java:2099)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
    at java.awt.Container.dispatchEventImpl(Container.java:2085)
    at java.awt.Window.dispatchEventImpl(Window.java:2475)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

3 ответа

Решение

Хорошо, вот очищенная версия вашего кода, которая должна приблизительно выполнить то же самое:

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class Reminder {
    private static final String TEXT = "Test hiiii what happpn";
    private static final String[] WORDS = TEXT.split(" ");
    private JFrame frame;
    private Timer timer;
    private StyledDocument doc;
    private JTextPane textpane;
    private List<Integer> times = Arrays.asList(1000, 900, 300, 1500);

    private int stringIndex = 0;
    private int index = 0;

    public void startColoring() {
        ActionListener actionListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                doc.setCharacterAttributes(stringIndex, 1, textpane.getStyle("Red"), true);
                stringIndex++;
                try {
                    if (stringIndex >= doc.getLength() || doc.getText(stringIndex, 1).equals(" ")) {
                        index++;
                    }
                    if (index < times.size()) {
                        double delay = times.get(index).doubleValue();
                        timer.setDelay((int) (delay / WORDS[index].length()));
                    } else {
                        timer.stop();
                        System.err.println("Timer stopped");
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        };
        timer = new Timer(times.get(index), actionListener);
        timer.setInitialDelay(0);
        timer.start();
    }

    public void initUI() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        doc = new DefaultStyledDocument();
        textpane = new JTextPane(doc);
        textpane.setText(TEXT);
        javax.swing.text.Style style = textpane.addStyle("Red", null);
        StyleConstants.setForeground(style, Color.RED);
        panel.add(textpane);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String args[]) throws InterruptedException, InvocationTargetException {
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                Reminder reminder = new Reminder();
                reminder.initUI();
                reminder.startColoring();
            }
        });
    }
}

Несколько трюков, чтобы помочь другим прочитать и понять ваш код:

  • Используйте последовательные и подходящие отступы (я лично стараюсь придерживаться соглашений Sun Java по умолчанию)
  • Следуйте соглашениям Java-кодирования (константы в верхнем регистре, имя класса начинается в верхнем регистре, переменные и методы начинаются в нижнем регистре, используйте регистр верблюда)
  • Используйте значимые имена переменных и методов
  • член класса должен быть объявлен один за другим (не используйте int i, j, k;)
  • Используйте одну инструкцию на строку (избегайте таких вещей, как if(something) doSomething(); else {doSomethingElse1(); doSomethingElse2();} на одной строке)
  • Избегайте ненужного использования static ключевое слово (за исключением констант)
  • Старайтесь не связывать свой код так много (постарайтесь сделать минимальные предположения о том, как работает остальная часть кода)
  • Добавьте в свой код javadoc и комментарии, это всегда хорошая практика, и она очень поможет вам и другим.

Ваша основная причина для беспокойства заключается в том, что вы не делаете обновления, связанные с JTextPane на Event Dispatch Thread,

В такой ситуации, когда вы действительно хотите обновить определенную вещь из другого потока, всегда используйте EventQueue.invokeLater(...) или EvenQueue.invokeAndWait (), которые могут asynchronously (former)/synchronously (latter) обновите свой запрос на EDT, хотя необходимо соблюдать осторожность, так как invokeAndWait() может привести к deadlocks/run conditions если не используется в правильном смысле.

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

import javax.swing.*;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;

/**
 * Created with IntelliJ IDEA.
 * User: Gagandeep Bali
 * Date: 1/12/13
 * Time: 5:55 PM
 * To change this template use File | Settings | File Templates.
 */
public class ColouringText
{
    private StyledDocument document;
    private JTextPane textPane;

    private String message;
    private String[] parts;

    private Timer timer;
    private int counter;
    private int start, end;
    private Thread thread = new Thread()
    {
        @Override
        public void run()
        {
            while (counter < parts.length)
            {
                final int len = parts[counter++].length();
                try
                {
                    EventQueue.invokeAndWait(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            document.setCharacterAttributes(
                                    start, len, textPane.getStyle("RED"), true);
                        }
                    });
                    Thread.sleep(len * 1000);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                catch (InvocationTargetException e)
                {
                    e.printStackTrace();
                }
                start += (len + 1);
            }
        }
    };

    public ColouringText()
    {
        document = (StyledDocument) new DefaultStyledDocument();
        message = "Hello there... Joey Rohan. Had you ever thought about putting indentations before pasting your code.";
        parts = message.split(" ");
        counter = 0;
        start = 0;
        end = 6;
        System.out.println("Message Length : " + message.length());
    }

    private void displayGUI()
    {
        JFrame frame = new JFrame("Colouring Text Example");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        textPane = new JTextPane(document);
        textPane.setText(message);
        Style style = textPane.addStyle("RED", null);
        StyleConstants.setForeground(style, Color.RED);

        contentPane.add(textPane);
        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        thread.start();
    }

    public static void main(String... args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new ColouringText().displayGUI();
            }
        });
    }
}

COLOURINGTEXTEXAMPLE

Будучи тем, кто ответил на ваши 2 предыдущих вопроса на похожую задачу:

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

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

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

В приведенном ниже примере используется массив integer s, которые содержат время для слов, которые будут выделены. Он также содержит массив для каждого отдельного слова / букв, которые мы хотели бы выделить:

private int[] timingsArray = {1000, 900, 300, 1500};//word/letters timings
private String[] individualWordsToHighlight = {"Tes", " hiiii", " what", " happpn"};//each individual word/letters to highlight

В нашей кнопке "Пуск" у нас есть метод преобразования вышеуказанных значений в отдельные значения времени / буквы для каждой отдельной буквы для выделения буквы за буквой:

//create Arrays of individual letters and their timings
final ArrayList<String> chars = new ArrayList<>();
final ArrayList<Integer> charsTiming = new ArrayList<>();
for (String s : individualWordsToHighlight) {
    for (int i = 0; i < s.length(); i++) {
        chars.add(String.valueOf(s.charAt(i)));
        System.out.println(String.valueOf(s.charAt(i)));
    }
}

for (int x = 0; x < timingsArray.length; x++) {
    for (int i = 0; i < individualWordsToHighlight[x].length(); i++) {
        charsTiming.add(timingsArray[x] / individualWordsToHighlight[x].length());
        System.out.println(timingsArray[x] / individualWordsToHighlight[x].length());
    }
}

Далее идет сингл Timer которая будет запускаться при нажатии кнопки запуска, которая будет выделять слова / буквы и перезапускаться с новой задержкой каждый раз, пока все слова / буквы не будут выделены:

new Timer(1, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (count < charsTiming.size()) {
                        highlightNextWord();
                        //restart timer with new timings
                        ((Timer) ae.getSource()).setInitialDelay(charsTiming.get(count));
                        ((Timer) ae.getSource()).restart();
                    } else {//we are at the end of the array
                        reset();
                        ((Timer) ae.getSource()).stop();//stop the timer
                    }
                    count++;//increment counter
                }
            }).start();

Надеюсь это поможет.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class KaraokeTest {

    private int[] timingsArray = {1000, 900, 300, 1500};//word/letters timings
    private String[] individualWordsToHighlight = {"Tes", " hiiii", " what", " happpn"};//each individual word/letters to highlight
    private int count = 0;
    private final JTextPane jtp = new JTextPane();
    private final JButton startButton = new JButton("Start");
    private final JFrame frame = new JFrame();

    public KaraokeTest() {
        initComponents();
    }

    private void initComponents() {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        for (String s : individualWordsToHighlight) {
            String tmp = jtp.getText();
            jtp.setText(tmp + s);
        }
        jtp.setEditable(false);

        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                startButton.setEnabled(false);
                count = 0;

                //create Arrays of individual letters and their timings
                final ArrayList<String> chars = new ArrayList<>();
                final ArrayList<Integer> charsTiming = new ArrayList<>();

                for (String s : individualWordsToHighlight) {
                    for (int i = 0; i < s.length(); i++) {
                        chars.add(String.valueOf(s.charAt(i)));
                        System.out.println(String.valueOf(s.charAt(i)));
                    }
                }

                for (int x = 0; x < timingsArray.length; x++) {
                    for (int i = 0; i < individualWordsToHighlight[x].length(); i++) {
                        charsTiming.add(timingsArray[x] / individualWordsToHighlight[x].length());
                        System.out.println(timingsArray[x] / individualWordsToHighlight[x].length());
                    }
                }

                new Timer(1, new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        if (count < charsTiming.size()) {
                            highlightNextWord();
                            //restart timer with new timings
                            ((Timer) ae.getSource()).setInitialDelay(charsTiming.get(count));
                            ((Timer) ae.getSource()).restart();
                        } else {//we are at the end of the array
                            reset();
                            ((Timer) ae.getSource()).stop();//stop the timer
                        }
                        count++;//increment counter
                    }
                }).start();
            }
        });

        frame.add(jtp, BorderLayout.CENTER);
        frame.add(startButton, BorderLayout.SOUTH);

        frame.pack();
        frame.setVisible(true);
    }

    private void reset() {
        startButton.setEnabled(true);
        jtp.setText("");
        for (String s : individualWordsToHighlight) {
            String tmp = jtp.getText();
            jtp.setText(tmp + s);
        }
        JOptionPane.showMessageDialog(frame, "Done");
    }

    private void highlightNextWord() {
        //we still have words to highlight
        int sp = 0;
        for (int i = 0; i < count + 1; i++) {//get count for number of letters in words (we add 1 because counter is only incrementd after this method is called)
            sp += 1;
        }
        //highlight words
        Style style = jtp.addStyle("RED", null);
        StyleConstants.setForeground(style, Color.RED);
        ((StyledDocument) jtp.getDocument()).setCharacterAttributes(0, sp, style, true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new KaraokeTest();
            }
        });
    }
}

ОБНОВИТЬ

В ответ на ваш отредактированный вопрос.

Опять же, код соответствует для меня, что приводит меня к выводу, что наши Java-среды выполнения отличаются и могут вызывать проблемы. Мой это:

Java-версия "1.7.0_10" Java(TM) SE Runtime Environment (сборка 1.7.0_10-b18) 64-разрядная серверная виртуальная машина Java HotSpot(TM) (сборка 23.6-b04, смешанный режим)

ОБНОВЛЕНИЕ 2:

Согласно вашему комментарию к вашей версии Java:

JDK 6, NetBeans 6.5.1

Ты пытался:

final ArrayList<String> chars = new ArrayList<String>(); 
final ArrayList<Integer> charsTiming = new ArrayList<Integer>(); 

обратите внимание, я не использую <> больше, так как Java 6 не поддерживает оператор Diamond, он должен включать тип данных, т.е. <Integer>,

Другие вопросы по тегам