@snave
Front-end developer

Как спроектировать структуру классов текстового редактора?

Добрый день.
Только начал изучать программирование и написал маленький редактор на 600 строк. Захотел переписать в ООП стиле и получил кучу ... которая не работает.
В IDE я создал класс Environment в котором инициализируются основные компоненты (Фрейм, текстовая область, вызывается класс меню и класс сервис (строка состояния процессов("файл открыт", "файл закрыт" и т.д.))). Существует еще один класс - Document (хранит название файла, количество его символов и т.д.(потом буду отсылать это в класс Sevice).
Мои проблемы: я не могу нормально открыть из класса меню файл и создать документ открыв файл (был момент когда создавался еще один редактор, но текстовая область все равно оставалась пустой).
Но даже, если у меня получается создать документ и передать в него контент, я не могу передать этот же текст в Environment.
Класс сервис - это метка внизу редактора которая должна постоянно обновлять свое содержимое (источник события документ и сама среда).

Вопросы
1. У кого нибудь есть схема проектирования такого приложения или кто может подсказать основные этапы реализации?
2. Скачал книги: Совершенный код и книга "Банды четырех". Они помогут на этом этапе?
Третий день вожусь с этой задачей. В Google был.

Update:
1. Как я понял мне нужно изучить UML
2. Далее книги по архитектуре программного обеспечения
---- Только после этого я должен уже уметь проектировать приложение - верно?

Неработающая куча ниже:

КЛАСС ЗАПУСКА
import javax.swing.*;

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


КЛАСС СРЕДЫ
import javax.swing.*;
import java.awt.*;


public class Environment {
    public static JTextArea textArea;
    private JFrame frame;
    private MainMenu mainMenu;
    private Container container;
    private JScrollPane jScrollPane;
    private Service statusMessage;

    Environment()
    {
        frame = new JFrame("Text Editor");
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.getContentPane().setLayout(new FlowLayout());
            frame.setSize(270, 420);

        textArea = new JTextArea();
            jScrollPane = new JScrollPane(textArea);
            jScrollPane.setPreferredSize(new Dimension(250, 200));
            jScrollPane.getViewport().add(textArea);

        mainMenu = new MainMenu();

        frame.setJMenuBar(mainMenu.getMenuBar());
        container = frame.getContentPane();
            container.add(jScrollPane);
        statusMessage = new Service();
            container.add(statusMessage.getStatusMessage());
        frame.setVisible(true);
    }

    public static JTextArea getTextArea()
    {
        return textArea;
    }
}


КЛАСС ДОКУМЕНТ
public class Document {

    private String fileName;
    private String content;
    private int caretPosition;

    Document(String fn, int cp, String ct)
    {
        fileName = fn;
        caretPosition = cp;
        content = ct;
    }

    public void setCaretPosition(int x)
    {
        caretPosition = x;
    }
}


КЛАСС МЕНЮБАР
import javax.swing.*;

public class MainMenu {
    private JMenuBar menuBar;
    private FileMenu fileMenu;

    MainMenu()
    {
        menuBar = new JMenuBar();
        fileMenu = new FileMenu();
            menuBar.add(fileMenu.getFileMenu());
    }

    public JMenuBar getMenuBar()
    {
        return menuBar;
    }
}


КЛАСС МЕНЮ-ФАЙЛ
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class FileMenu {
    private JMenu menuFile;
    private JMenuItem loadFile;
    private JMenuItem saveFile;
    private JFileChooser fileChooser;
    private Service service;

    FileMenu()
    {
        menuFile = new JMenu("File");
        loadFile = new JMenuItem("Load");
            loadFile.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String fileName = "";
                    fileChooser = new JFileChooser();
                    service = new Service();
                    int result = fileChooser.showOpenDialog(null);

                    if (result == JFileChooser.APPROVE_OPTION){
                        fileName = fileChooser.getSelectedFile().getName();
                    } else {
                        service = new Service("No file selected.");
                    }
                    LoadFile loadFile = new LoadFile(fileName);
                    Environment.textArea.setText(loadFile.getContent());
                }
            });
        saveFile = new JMenuItem("Save");
            menuFile.add(loadFile);
            menuFile.add(saveFile);
    }

    public JMenu getFileMenu()
    {
        return menuFile;
    }
}


КЛАСС ЗАГРУЗКИ ФАЙЛА
import javax.swing.*;
import java.io.FileReader;
import java.io.IOException;

public class LoadFile{

    private String fileName;
    private static JTextArea textArea;

    LoadFile(String name)
    {
        FileReader fw;
        fileName = name;
        Service statusMsg;
        Document document;
        textArea = new JTextArea();

        if(name.length() == 0)
        {
            statusMsg = new Service("No filename present");
            return;
        }

        try{
            fw = new FileReader(fileName);
            textArea.read(fw, null);
            document = new Document(fileName, 0, textArea.getText());
            fw.close();
        }catch (IOException exc){
            statusMsg = new Service("Error opening or reading file.");
            return;
        }
    }

    public static String getContent()
    {
        return textArea.getText();
    }
}


КЛАСС СЕРВИС
import javax.swing.*;
import java.awt.*;
public class Service {
    private JLabel statusMessage;


    Service()
    {
        statusMessage = new JLabel("Test");
        statusMessage.setPreferredSize(new Dimension(200, 30));
        statusMessage.setHorizontalAlignment(SwingConstants.CENTER);
    }

    Service(String message)
    {
        statusMessage = new JLabel(message);
        statusMessage.setPreferredSize(new Dimension(200, 30));
        statusMessage.setHorizontalAlignment(SwingConstants.CENTER);
    }

    public JLabel getStatusMessage()
    {
        return statusMessage;
    }
}
  • Вопрос задан
  • 931 просмотр
Решения вопроса 1
timych
@timych
На swing писал только в колледже, но от нечего делать немного переписал ваш код.
Сильно заморачиваться не стал - вариантов архитектуры много..
Но я бы посоветовал не увлекаться обьявлением переменных как членов класса, если не планируется их использовать. Также по возможности не включайте много логики в конструктор (ИМХО)
Ну и названия классов не очень правильные как мне кажется.
Также различные размеры элементов и текстовые сообщения желательно обьявлять как константы.
И не помешало бы добавить проверку -действительно ли выбранный файл - текстовый.

package wordpad;

public class RunTextEditor {

	public static void main(String args[]) {	
		
		new Environment().run();

	}
}


package wordpad;


import javax.swing.*;
import java.awt.*;

// Название класса не правильное!
public class Service extends JLabel {

	private static final long serialVersionUID = 1L;

	public Service() {
		super();
		setPreferredSize(new Dimension(200, 30));
		setHorizontalAlignment(SwingConstants.CENTER);
	}

	public Service(String message) {
		this();
		setMessage(message);
	}

	public void setMessage(String message) {
		setText(message);
	}
}


package wordpad;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;


//  Я бы переименовал в  FileManager или что-то подобное 
public class LoadFile {

	private FileHandler handler;

	// интерфейс обработчика можно вынести и в  отдельный класс
	public interface FileHandler {
		
		void onLoad(Document document);

		void onSave(Document document);

		void onError(String message);
	}

	// конструктор приватный чтобы не проверять обработчик на null
	private LoadFile() {
	}

	public LoadFile(FileHandler handler) {
		this();
		setHAndler(handler);
	}
	
	
	public FileHandler getHandler() {
		return handler;
	}
	
	public void setHAndler(FileHandler handler) {
		this.handler =  handler;
	}

	public void processLoad(File file) {

		if ( file == null || !file.exists()) {
			handler.onError("No filename present");
			return;
		}

		try {
			FileReader fileReader = new FileReader(file);
			String text = new String(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
			Document document = new Document(file.getName(), 0, text);
			fileReader.close();
			handler.onLoad(document);
		} catch (IOException exc) {
			handler.onError("Error opening or reading file.");
		}
	}
}


package wordpad;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import wordpad.LoadFile.FileHandler;


public class FileMenu extends JMenuBar {

	private static final long serialVersionUID = 1L;

	private FileMenu() {
		super();
	}

	public FileMenu(FileHandler handler) {
		this();
		JMenu menu = new JMenu("File");
		JMenuItem loadItem = new JMenuItem("Load");
		JMenuItem saveItem = new JMenuItem("Save");
		JFileChooser fileChooser = new JFileChooser();
		LoadFile fileManager = new LoadFile(handler);


		menu.add(loadItem);
		menu.add(saveItem);
		add(menu);
		loadItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				int result = fileChooser.showOpenDialog(null);

				if (result == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					fileManager.processLoad(file);
				} else {
					fileManager.getHandler().onError("No file selected.");
				}
			}
		});
		
		//TODO добавьте сохранение сами :)

	}
}


package wordpad;

import javax.swing.*;

import wordpad.LoadFile.FileHandler;

import java.awt.*;

// Не очень красивое название класса на мой взгляд
public class Environment {

	private JTextArea textArea;
	private JFrame mainFrame;
	private Service statusMessage;

	private FileHandler handler = new FileHandler() {

		@Override
		public void onSave(Document document) {
			statusMessage.setText(document.getFileName() + " saved!");
		}

		@Override
		public void onLoad(Document document) {
			textArea.setText(document.getContent());
			statusMessage.setText(document.getFileName() + " loaded");
		}

		@Override
		public void onError(String message) {
			statusMessage.setText(message);
		}
	};

	public Environment() {

		mainFrame = new JFrame("Text Editor");
		mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		mainFrame.getContentPane().setLayout(new FlowLayout());
		mainFrame.setSize(270, 420);

		textArea = new JTextArea();
		JScrollPane jScrollPane = new JScrollPane(textArea);
		jScrollPane.setPreferredSize(new Dimension(250, 200));
		jScrollPane.getViewport().add(textArea);

		FileMenu fileMenu = new FileMenu(handler);

		mainFrame.setJMenuBar(fileMenu);
		Container container = mainFrame.getContentPane();
		container.add(jScrollPane);
		statusMessage = new Service();
		container.add(statusMessage);

	}

	public void run() {
		mainFrame.setVisible(true);
	}
}


package wordpad;

/**
 * @author Timur Nikiforov
 */
public class Document {

	private String fileName;
	private String content;
	// Для чего нужна позиция каретки?
	private int caretPosition;

	public Document(String fileName, int caretPosition, String content) {
		this.setFileName(fileName);
		this.setCaretPosition(caretPosition);
		this.setContent(content);
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public int getCaretPosition() {
		return caretPosition;
	}

	public void setCaretPosition(int caretPosition) {
		this.caretPosition = caretPosition;
	}
}


ЗЫ: B как сказали выше - испульзуйте лучше JavaFX
По поводу книги: вот неплохая и читается легко.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы