JTextPane / JTextArea append () работает случайным образом - PullRequest
0 голосов
/ 24 апреля 2018

У меня есть JTextPane в очень простом графическом интерфейсе, который я использую в качестве консоли вывода для игры, которую я использую для изучения Java, которую я (пытаюсь) использовать с методом добавления в классе окна, вызывая его из другого класса ( сама программа) или из класса читателя команды. Теоретически он должен вывести набранную мною команду, а в следующих строках вывести ее из указанной программы.

Метод print (который использует append для JTextArea или getText () и setText () для JTextPane) работает нормально, если он вызывается из своего собственного класса (при печати используемой команды и «>», однако при вызове из снаружи он ведет себя случайным образом, иногда добавляя его в самый верх textArea, работая по назначению или даже дублируя весь текст внутри него.

Это код GUI, который используется для этого. Я уверен, что это не идеально или даже близко, но я только начал изучать основы графических интерфейсов

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.DefaultCaret;

import graficos.VisorJugador;

public class test extends JFrame {
      private static final long serialVersionUID = 1L;
      private JPanel contentPane;
      private String comando = "";
      private JTextArea txp_Console;
      private JScrollPane jsp_ConsoleScrollPanel;
      private JLabel lbl_habitacion;
      private VisorJugador[] jugadores;

    /**
     * Create the frame.
     */
    public test() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 640, 480);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        createPanels();
    }

    public static void lanzar(test frame){
        frame.setVisible(true);
    }

    private void createPanels(){
        JPanel panelInferior = new JPanel();
        JPanel panelCentral = new JPanel();

        panelCentral.setLayout(new BorderLayout(0, 0));

        crearInferior(panelInferior);
        crearCentral(panelCentral);

        contentPane.add(panelInferior, BorderLayout.SOUTH);
        contentPane.add(panelCentral, BorderLayout.CENTER);
    }

    private void crearCentral(JPanel panelCentral) {
        JLabel lbl_Consola = new JLabel("Consola");
        txp_Console = new JTextArea();
        jsp_ConsoleScrollPanel = new JScrollPane(txp_Console);

        txp_Console.setEditable(true);

        DefaultCaret caret = (DefaultCaret) txp_Console.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

        panelCentral.add(lbl_Consola, BorderLayout.NORTH);
        panelCentral.add(txp_Console, BorderLayout.CENTER);
    }

    private void crearInferior(JPanel panelInferior) {
        JLabel lbl_QueHacer = new JLabel("Que quieres hacer?");
        JButton btn_Enviar = new JButton("Hacer");
        JTextField txt_consola = new JTextField();

        btn_Enviar.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                comando = txt_consola.getText();
                print("> " + txt_consola.getText());
                txt_consola.setText("");
            }
        });
        txt_consola.setColumns(10);

        panelInferior.add(lbl_QueHacer, BorderLayout.NORTH);
        panelInferior.add(txt_consola);
        panelInferior.add(btn_Enviar);
    }

    public void print(String texto) {
        String anterior = txp_Console.getText();
        txp_Console.setText(anterior + texto);
    }
}

Я вызываю ventana.print (tags.getString (msg)) каждый раз, когда мне нужно вывести что-то из программы, ventana - это новый test экземпляр, созданный в его конструкторе. У меня нет понимания потоков, поэтому я ничего не имею с этим, так что, насколько я знаю, все работает в основном потоке.

Также, вот пример вывода

No entiendo  --From commands 2 and 3
No entiendo  --From commands 2 and 3
Bienvenido al Mundo de Zuul!  --Working output
El Mundo de Zuul es un juego de aventuras muy aburrido, pero interesante!.  --Working output
Escribe 'ayuda' si necesitas ayuda.  --Working output
Estas en el exterior de la entrada principal de la universidad  --Working output
    Salidas: este, sur, oeste  --Working output
> 1           --Works as intended
No entiendo   --Output for command 1
> 2           --Output at the top
> 3           --Output at the top
> 4           --No output, windows error sound

Во время отладки я видел, что создана нить для swing / awt, но я совсем не понимаю нити, поэтому я просто надеюсь, что они мне не нужны для этого. Я также попытался установить перо, переместить полосу прокрутки, убрав "/ n" из команд, но пока 0 удачи

1 Ответ

0 голосов
/ 24 апреля 2018

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

Одно из изменений, которое вы можете внести в метод печати, - это проверить, участвуете ли вы в потоке событий Swing, и, если это так, добавить текст, переданный в JTextArea. Если нет, то создайте код, используя SwingUtilities, чтобы поставить в очередь это изменение в потоке событий, примерно так:

public void print(String texto) {
    // String anterior = txp_Console.getText();
    // txp_Console.setText(anterior + texto);
    if (SwingUtilities.isEventDispatchThread()) {
        // if on the Swing event thread, call directly
        txp_Console.append(texto);  // a simple append call is all that is needed
    } else {
        // else queue it onto the event thread
        SwingUtilities.invokeLater(() -> txp_Console.append(texto));
    }
}

Прочтите Урок: параллелизм в Swing , чтобы узнать больше о многопоточности Swing.

Например, скажем, у меня был такой графический интерфейс:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class JuanjoTestPanel extends JPanel {
    private static final int TA_ROWS = 25;
    private static final int TA_COLS = 60;
    private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
    private JTextField textField = new JTextField(30);
    private Action hacerAction = new HacerAction();

    public JuanjoTestPanel() {
        textArea.setFocusable(false);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        JScrollPane scrollPane = new JScrollPane(textArea);

        textField.setAction(hacerAction);
        JPanel bottomPanel = new JPanel();
        bottomPanel.add(new JLabel("¿Que queres hacer?"));
        bottomPanel.add(Box.createHorizontalStrut(5));
        bottomPanel.add(textField);
        bottomPanel.add(new JButton(hacerAction));

        setLayout(new BorderLayout());
        add(scrollPane);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    public void printToWindow(final String text) {
        if (SwingUtilities.isEventDispatchThread()) {
            textArea.append("Console:" + text + "\n");
        } else {
            SwingUtilities.invokeLater(() -> textArea.append("Console:" + text + "\n"));
        }
    }

    private class HacerAction extends AbstractAction {
        public HacerAction() {
            super("Hacer");
            putValue(MNEMONIC_KEY, KeyEvent.VK_H);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String text = "> " + textField.getText() + "\n";
            textArea.append(text);
            textField.selectAll();
            textField.requestFocusInWindow();
        }
    }
}

Вы также можете писать в него с консоли, вызывая его метод printToWindow(...) следующим образом:

import java.util.Scanner;
import javax.swing.*;

public class TestSwing2 {

    private static final String EXIT = "exit";

    public static void main(String[] args) {
        // create window
        final JuanjoTestPanel testPanel = new JuanjoTestPanel();
        // launch it on the Swing event thread
        SwingUtilities.invokeLater(() -> createAndShowGui(testPanel));
        Scanner scanner = new Scanner(System.in);
        String line = "";
        while (!line.trim().equalsIgnoreCase(EXIT)) {
            System.out.print("Enter text: ");
            line = scanner.nextLine();
            System.out.println("Line entered: " + line);
            testPanel.printToWindow(line); // write to it
        }
        scanner.close();
        System.exit(0);
    }

    private static void createAndShowGui(JuanjoTestPanel testPanel) {
        JFrame frame = new JFrame("Test Swing2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(testPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
...