Возможная гонка между ActionListener и DocumentListener - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть фрейм, в котором есть пара JEditorPanes компонентов. Один из них редактируемый, и пользователи могут ввести его. DocumentListener, прикрепленный к этой панели редактора, синхронизирует содержимое этого с другим при изменении текста. Это, казалось, работало хорошо.

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

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

public class EditorFrame extends JFrame {

    private static final long serialVersionUID = 7119768788946124936L;

    private JFrame _parentframe;

    private JEditorPane _inputpane;
    private JScrollPane _inputscrollpane;
    private JButton _inputloadbutton;
    private JPanel _inputbuttonpanel;
    private JPanel _inputpanel;

    private JEditorPane _outputpane;
    private JScrollPane _outputscrollpane;    
    private JPanel _outputpanel;

    private JPanel _editorpanel;

    private JButton _savebutton;
    private JButton _discardbutton;

    private JPanel _buttonpanel;

    private JPanel _contentpanel;

    public EditorFrame(JFrame pframe) {
        super("Editor");

        this._parentframe = pframe;

        this.init();
    }

    public EditorFrame(JFrame pframe) {
        super("Editor");

        this._parentframe = pframe;

        this.init();
    }

    private boolean init() {
        Dimension editorsize = new Dimension(750,500);

        this._inputpane = new JEditorPane();
        this._inputpane.setContentType("text/plain");
        this._inputpane.setPreferredSize(editorsize);
        this._inputpane.setBorder(BorderFactory.createLineBorder(Color.black));
        this._inputpane.setEditable(true);
        this._inputpane.setVisible(true);
        this._inputscrollpane = new JScrollPane(this._inputpane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        this._inputloadbutton = new JButton("Load Content");
        EditorFrameLoadButtonActionListener loadbutton_actionlistener = new EditorFrameLoadButtonActionListener(this);
        this._inputloadbutton.addActionListener(loadbutton_actionlistener);

        this._inputbuttonpanel = new JPanel();
        this._inputbuttonpanel.add(this._inputloadbutton);

        this._inputpanel = new JPanel();
        this._inputpanel.setLayout(new BoxLayout(this._inputpanel, BoxLayout.PAGE_AXIS));        
        this._inputpanel.add(this._inputscrollpane);
        this._inputpanel.add(this._inputbuttonpanel);

        this._outputpane = new JEditorPane();
        this._outputpane.setContentType("text/html");
        this._outputpane.setPreferredSize(editorsize);
        this._outputpane.setBorder(BorderFactory.createLineBorder(Color.black));
        this._outputpane.setEditable(false);
        this._outputpane.setVisible(true);
        HTMLEditorKit output_htmleditorkit = new HTMLEditorKit();
        this._outputpane.setEditorKit(output_htmleditorkit);
        this._outputscrollpane = new JScrollPane(this._outputpane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        this._outputpanel = new JPanel();
        this._outputpanel.add(this._outputscrollpane);

        this._editorpanel = new JPanel();
        this._editorpanel.add(this._inputpanel);
        this._editorpanel.add(this._outputpanel);

        this._savebutton = new JButton("Save");
        this._savebutton.setEnabled(false);

        this._discardbutton = new JButton("Discard");
        CloseButtonActionListener discardbuttonlistener = new CloseButtonActionListener(this);
        this._discardbutton.addActionListener(discardbuttonlistener);

        this._buttonpanel = new JPanel();
        this._buttonpanel.add(this._savebutton);
        this._buttonpanel.add(this._discardbutton);

        this._contentpanel = new JPanel();
        this._contentpanel.setLayout(new BorderLayout());
        this._contentpanel.add(this._titlepanel, BorderLayout.PAGE_START);
        this._contentpanel.add(this._editorpanel, BorderLayout.CENTER);
        this._contentpanel.add(this._buttonpanel, BorderLayout.PAGE_END);

        this.setContentPane(this._contentpanel);

        EditorFrameInputPaneDocumetListener doclistener = new EditorFrameInputPaneDocumetListener(this);
        this._inputpane.getDocument().addDocumentListener(doclistener);

        EditorFrameWindowListener windowlistener = new EditorFrameWindowListener(this._parentframe);
        this.addWindowListener(windowlistener);

        this.pack();
        this.setVisible(true);

        return true;
    }

    public void setInputPane(String instr) {
        this._inputpane.setText(instr);
    }

    public void setOutputPane(String outstr) {
        this._outputpane.setText(outstr);
    }

    public String getInputPane() {
        return this._inputpane.getText();
    }

    public String getOutputPane() {
        return this._outputpane.getText();
    }

    public void syncPanes() {
        String data = this._inputpane.getText();
        this._outputpane.setText(data);
    }

    public void enableSaveButton() {
        this._savebutton.setEnabled(true);
    }

}

public class EditorFrameInputPaneDocumetListener implements DocumentListener{

    private EditorFrame _frame;

    public EditorFrameInputPaneDocumetListener(EditorFrame f) {
        this._frame = f;
    }

    @Override
    public void changedUpdate(DocumentEvent arg0) {
        this.synchAction();
    }

    @Override
    public void insertUpdate(DocumentEvent arg0) {
        this.synchAction();
    }

    @Override
    public void removeUpdate(DocumentEvent arg0) {
        this.synchAction();
    }

    private void synchAction() {
        this._frame.syncPanes();
        this._frame.enableSaveButton();
    }
}

public class EditorFrameLoadButtonActionListener implements ActionListener{

    private EditorFrame _frame;

    public EditorFrameLoadButtonActionListener(EditorFrame frame) {
        this._frame = frame;
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        JFileChooser fc;
        String path;
        String ext;
        fc = new JFileChooser();
        fc.setAcceptAllFileFilterUsed(false);
        if (fc.showOpenDialog(this._frame) == JFileChooser.APPROVE_OPTION) {
            path = fc.getSelectedFile().getPath();
            ext = AbsConverter.getExtension(path);
            switch(ext) {
                case "png" :    
                    this.loadImage(path);
                    break;
                default :
                    String msg = String.format("File *.%s cannot be loaded", ext);
                    JOptionPane.showMessageDialog(this._frame, msg, "Load Error", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void loadImage(String file) {
        String imageStr;
        String inputStr;
        imageStr = AbsConverter.imageString(file);
        if (imageStr.equals("")) {
            String msg = String.format("Could not load image");
            JOptionPane.showMessageDialog(this._frame, msg, "Load Error", JOptionPane.ERROR_MESSAGE);           
        }
        else {
            inputStr = "";
            inputStr = inputStr + "<html>\n";
            inputStr = inputStr + "<body>\n";
            inputStr = inputStr + "<img src=\"";
            inputStr = inputStr + imageStr;
            inputStr = inputStr + "\" >\n";
            inputStr = inputStr + "</body>\n";
            inputStr = inputStr + "</html>\n";
            this._frame.setInputPane(inputStr);
            //this._frame.setOutputPane(inputStr);
        }
    }
}
...