3
\$\begingroup\$

I am beginner in programming and recently I wrote an editor, inspired by the Notepad program, with all basic features any editor should have, like finding, undoing, copying, etc.

The problem is I do not "feel" OOP completely yet. I wrote the whole program in a single class with few inner classes for actions, a frame for finding and replacing etc. I only wrote one separate class for style settings, like textArea Color etc, yet implementation of this class was poor in my belief.

In the result I was happy with the fact I managed to create fully working notepad; however I cannot stop thinking how messy is the code underneath it. So I decided to rewrite it just for exercise and make it more structured.

I read about MVC pattern and I tried to apply it to my code. I wrote 2 view classes - Main View (with textArea and menuBar) and FindAndReplace frame in separate class. Then I created model and controller.

Can you tell me if this makes any sense? Is this good implementation of MVC or I misunderstood it completely?

MainGUI.java

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

public class MainGUI extends JFrame{

    public MainGUI(){
        initMainFrame();
        initMenuBar();
        initToolBar();
    }

    private JTextArea textArea = new JTextArea();

    void initMainFrame(){
        setBounds(300,300,300,300);
        add(textArea);
        setDefaultCloseOperation(3);

    }

   public JMenuBar menuBar;
   public JMenu menuEdit;
   public JMenuItem findAndReplace = new JMenuItem("Find and replace");

    void initMenuBar(){

        this.add(menuBar=new JMenuBar(),BorderLayout.NORTH);
        menuBar.add(menuEdit = new JMenu("Edit"));

        menuEdit.add(findAndReplace);             

    }

    void initToolBar()
    {
     /**
      *  toolbar
      */
    }

    public void setText(String text){  
        textArea.setText(text);    
    }

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

    public void selectText(int selectionStart, int selectionEnd){
      textArea.select(selectionStart, selectionEnd);

    }

}

FindAndReplaceGUI.Java

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

public class FindAndReplaceGUI extends JFrame{


    private JTextField findTextField = new JTextField(10);
    private JTextField replaceTextField = new JTextField(10);
    private JButton findTextBtn = new JButton("  Find Text  ");
    private JButton replaceTextBtn = new JButton("Replace Text");

    public FindAndReplaceGUI(){
        initComponents();
    }

    void initComponents(){

        setBounds(300,300,300,100);
        setResizable(false);
        setDefaultCloseOperation(3);

        JPanel TopPanel = new JPanel();
        add(TopPanel,BorderLayout.NORTH);
        TopPanel.add(findTextField);
        TopPanel.add(findTextBtn);

        JPanel bottomPanel = new JPanel();
        add(bottomPanel,BorderLayout.CENTER);
        bottomPanel.add(replaceTextField);
        bottomPanel.add(replaceTextBtn);


    }

    public String getTextFieldText(){  
        return findTextField.getText(); 
    }

    public JButton getFindButton(){
        return findTextBtn;
    }

    public String getReplaceFieldText(){  
        return replaceTextField.getText(); 
    }

    public JButton getReplaceButton(){
        return replaceTextBtn;
    }


}

Model.Java

public class Model {



    private int selectionStart=-1;
    private int selectionEnd=0;

    void findText(String textToFind, String textArea)
    {
            selectionStart=textArea.indexOf(textToFind, selectionStart+1);

            if (selectionStart == -1)
            {                     
              selectionStart = textArea.indexOf(textToFind);            
            }
            if (selectionStart >= 0)
            { 
                selectionEnd=selectionStart+textToFind.length();
            }

            if(!textArea.contains(textToFind))
                selectionEnd=0;

             System.out.println(selectionStart);
             System.out.println(selectionEnd);
    }


    void replaceText(String textForReplacement, String textArea)
    {
    /**
     *  replace text method
     */ 

    }

    int getSelectionStart(){
        return selectionStart;
    }
    int getSelectionEnd(){
        return selectionEnd;
    }

}

Controler.Java

public class Controler {


    MainGUI mainGui=new MainGUI();
    FindAndReplaceGUI finder = new FindAndReplaceGUI();
    Model model = new Model();    

    Controler()       
    {
        mainGui.setVisible(true);

    }
    public void control()
    {


       mainGui.findAndReplace.addActionListener(new ActionListener() {
           @Override
           public void actionPerformed(ActionEvent e) {
             finder.setLocationRelativeTo(mainGui);
             finder.setVisible(true);  
           }
       });


       /**
        * Find and Replace control 
        */ 
       finder.getFindButton().addActionListener(new ActionListener() {
           @Override
           public void actionPerformed(ActionEvent ae) {
              model.findText(finder.getTextFieldText(), mainGui.getText());
              mainGui.selectText(model.getSelectionStart(), model.getSelectionEnd());
           }
       });

       finder.getReplaceButton().addActionListener(new ActionListener() {
           @Override
           public void actionPerformed(ActionEvent e) {
               model.replaceText(finder.getReplaceFieldText(), mainGui.getText());
           }
       });

    }

    public static void main(String[] args) {
       new Controler().control();

    }

}

Does it make sense to put all ActionListeners to controller?

And I am wondering how should I access menu items from controller class? Does it make sense to set them on public (MainGUI and FindAndReplace are in different package) and calling them from in Controler class from the object mainGUI directly.

I am still learning to code simple and clean yet I feel I am still complicating things..

\$\endgroup\$
2
\$\begingroup\$

as picture overview does looks like a beginner nice job, you miss something in MODEL part (a good model does not performs business logic: if you implement a find() method in Controller, you'll can modularize it to find between more files, just as example).

However there are some points you can focus on:

  • access modificatiors of almost all variables and methods
    • when you need a constructor that always "inits", why don't simply create some objects and assign them inside the constructor ?
    • lack of "final" instance variables

After that, your Controller it's a "single tier" one. Listeners can perform many actions but mainly can do themself look&Feel modifications (as example: background color while performing some actions) but for complex cases a listener it's usefull if can call a Controller (or a static method) to make decisions.

Responsability to addListener can be moved to the GUI part, and GUI can link (instance variable) a reference of the Controller they wants to use.

Split classes in packages it's a standard business approach but, even if it's an underrated advantage, can let you manage the class visiblities better.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.