MVC-Architektur

Ljonja2107

Mitglied
Moin ich bins wieder,
ich bin an einem Chatprogramm am basteln und stehe vor einem Problem.
Und zwar möchte ich das Projekt in eine MVC Architektur realisieren und habe das ganze in kleinen Schritten angefangen.
Erst einmal eine Konsolen Applikation, dann das ganze mit Threads verbunden und nun möchte ich das in eine GUI packen.
Jetzt stehe ich vor dem Problem, dass ich eine View erstellt habe und nicht genau weiß wie ich es schaffe, dass wenn ich Strings in ein TextField eingebe, dann möchte ich die ja auch an jemanden senden können.
Ich habe 2 Modells -> ein Servermodell mit ServerSocket und ein Clientmodell mit einem Socket.
Ich habe in diesen Klassen "senden" und "empfangen" Methoden mit DatainputStreams und DataInputStreams.
Ebenfalls habe ich einen Controller, welcher für die Erzeugung der Server und des Clients zuständig ist und in welchem Threads erstellt werden, damit Nachrichten gleichzeitig gesendet und empfangen werden können.
Im Controller werden die Sende und Empfangen Methoden aus den Server und Client genutzt.
Java:
package MVC;

import java.io.IOException;
import java.util.Scanner;

public class Controller implements Runnable {
    private static ModellClient modellClient;
    private static ModellServer modellServer;
     static View view;
    static String nachrichtServer;
    static String nachrichtClient;
    static boolean isServer = false;
    static String msg;
    static Scanner scanner = new Scanner(System.in);
    

    public static void main(String[] args) throws IOException {
        Controller c1 = new Controller();
        Thread thread = new Thread(c1);
        if (isServer) {
            modellServer = new ModellServer();
            view = new View();
            view.setVisible(true);
            thread.start();

            sendenVonNachrichten(msg);
        } else {
            modellClient = new ModellClient();
            view = new View();
            view.setVisible(true);
            thread.start();
            sendenVonNachrichten(msg);
        }

    }

    public static void sendenVonNachrichten(String msg) throws IOException {
        while (true) {
            if (modellServer != null) {
//               
                msg = scanner.nextLine();
                
                modellServer.nachrichtenSenden(msg);
            } else if (modellClient != null) {
//               
                msg = scanner.nextLine();
                modellClient.nachrichtenSenden(msg);
            }

        }

    }

    @Override
    public void run() {
        while (true) {

            if (modellClient != null) {
                try {

                    nachrichtClient = modellClient.nachrichtEmpfangen();
                } catch (IOException e) {

                    e.printStackTrace();
                }

                System.out.print(nachrichtClient);
            } else if (modellServer != null) {

                try {

                    nachrichtServer = modellServer.nachrichtEmpfangen();
                } catch (IOException e) {

                    e.printStackTrace();
                }

                System.out.print(nachrichtServer);
            }

        }
    }
}

Dennoch finde ich keine Lösung, wie ich den Scanner ersetzen kann durch eine View und den Inhalt eines Textfields soweit nutzen kann, dass ich die Streams befüllen und ablesen kann.
 

Jw456

Top Contributor
Hallo du schreibst du hast eine GUI.

Wennn Swing wo ist dein JFrame ....?
In der Klasse View denke ich. Wenn du da zb ein Label hast in demm du was ausgeben willst brauchst du die ref auf das Objekt das dürfte view sein in deinen Fall.
Mehr kann ich hier nicht sagen. Da ich nichts von deiner GUI sehe.
 
Zuletzt bearbeitet:

Ljonja2107

Mitglied
Hallo du schreibst du hast eine GUI.

Wennn Swing wo ist dein JFrame ....?
In der Klasse View denke ich. Wenn du da zb ein Label hast in demm du was ausgeben willst brauchst du die ref auf das Objekt das dürfte view sein in deinen Fall.
Mehr kann ich hier nicht sagen. Da ich nichts von deiner GUI sehe.
Java:
package MVC;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.SystemColor;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import java.awt.Toolkit;
import java.awt.Font;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import java.awt.Component;
import javax.swing.border.BevelBorder;

public class View extends JFrame {
    static JFrame jFrame = new JFrame();
    private JPanel contentPane;
    static JLabel textVonEingabe;
    static JButton testButton;
    static JPanel nachrichtenPanel;
    static JPanel bannerPanel;
    static JLabel usernameLabel;
    static JScrollPane scrollPane;
    static JTextArea textArea;
    ActionListener al;
    private JButton Settings;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    View frame = new View();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public View() {
        setIconImage(Toolkit.getDefaultToolkit()
                .getImage("C:\\Users\\T0244695\\Desktop\\Dokumente und Diagramme\\101Logo.jpg"));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 739, 451);
        contentPane = new JPanel();
        contentPane.setBackground(SystemColor.text);
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        nachrichtenPanel = new JPanel();
        nachrichtenPanel.setBorder(null);
        nachrichtenPanel.setForeground(Color.BLACK);
        nachrichtenPanel.setBackground(Color.WHITE);
        nachrichtenPanel.setLayout(new BoxLayout(nachrichtenPanel, BoxLayout.Y_AXIS));
        nachrichtenPanel.setBounds(10, 85, 689, 234);
        contentPane.add(nachrichtenPanel);

        textVonEingabe = new JLabel("");
        textVonEingabe.setAlignmentY(30.0f);
        textVonEingabe.setAlignmentX(224.0f);
        textVonEingabe.setFont(new Font("Tahoma", Font.BOLD, 13));
        textVonEingabe.setForeground(Color.WHITE);
        textVonEingabe.setBackground(Color.BLUE);
        textVonEingabe.setOpaque(true);
        nachrichtenPanel.add(textVonEingabe);

        bannerPanel = new JPanel();
        bannerPanel.setForeground(Color.WHITE);
        bannerPanel.setBackground(Color.decode("#0096C1"));
        bannerPanel.setBounds(0, 0, 723, 49);
        contentPane.add(bannerPanel);
        bannerPanel.setLayout(null);

        usernameLabel = new JLabel("");
        usernameLabel.setFont(new Font("SansSerif", Font.BOLD, 14));
        usernameLabel.setHorizontalAlignment(SwingConstants.CENTER);
        usernameLabel.setBounds(242, 11, 205, 20);
        bannerPanel.add(usernameLabel);

        scrollPane = new JScrollPane();
        scrollPane.setBounds(10, 352, 538, 49);
        contentPane.add(scrollPane);

        textArea = new JTextArea();
        scrollPane.setViewportView(textArea);

        testButton = new JButton("Test");
        testButton.setBounds(595, 367, 89, 23);
        contentPane.add(testButton);

        Settings = new JButton("Settings");
        Settings.setBounds(10, 51, 89, 23);
        contentPane.add(Settings);

        al = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Object knopfHorcher = e.getSource();
                if (knopfHorcher == testButton) {
                    
                    String text = textArea.getText();
                    if (text.equals("")) {
                        textVonEingabe.setText("Keine Eingabe");
                    }else {
                        textVonEingabe.setText(text);
                    }
                    
                
                } else if (knopfHorcher == Settings) {
                    
                }

            }
        };
        testButton.addActionListener(al);
        Settings.addActionListener(al);
    }

}
bis jetzt ist das auch nur eine Oberfläche, welche einen eingegebenen Text nur bei sich ausgibt.
 

Jw456

Top Contributor
Du hast in beiden Klassen eine main Methode das geht nicht. Es gib in einem Projekt nur eine. Das ist die erste die nach dem Programmstart aufgrufen wird.
 

Jw456

Top Contributor
Was soll das deine gui in einem eigenen Thread zu starten.? Da tust du ja in der zweiten main. Das was in deiser Methode steht bruchst du eigentlich nicht.
 

KonradN

Super-Moderator
Mitarbeiter
Bei dem MVC Konzept sollte die View dann ja bei einer entsprechenden Interaktion im Controller entsprechend etwas aufrufen. Sprich: Der Controller hört auf ein Event um dann aktiv zu werden.
Der Controller hält ja das Model und kann daher im Model den Aufruf machen, damit die Nachricht gesendet wird.

Statt einem scanner.nextLine() hast Du also das Auslesen eines Textfeldes oder so um die Nachricht zu bekommen.
 

Ljonja2107

Mitglied
Bei dem MVC Konzept sollte die View dann ja bei einer entsprechenden Interaktion im Controller entsprechend etwas aufrufen. Sprich: Der Controller hört auf ein Event um dann aktiv zu werden.
Der Controller hält ja das Model und kann daher im Model den Aufruf machen, damit die Nachricht gesendet wird.

Statt einem scanner.nextLine() hast Du also das Auslesen eines Textfeldes oder so um die Nachricht zu bekommen.
Und das ist der Knackpunkt, wie kann ich ein ActionEvent abfragen in der Controller Klasse ?
 

Jw456

Top Contributor
Du extendst von JFrame.
Was soll dann nochmal das erzeugen eines JFame?

Du willst zb den text deines Labels
usernameLabel seten. Im Thread.
Also brauchst du die ref des view Objektes.usernameLabel.setText(xxx)

Das mit den static Variablen ist auch nicht gut.
 

KonradN

Super-Moderator
Mitarbeiter
Und das ist der Knackpunkt, wie kann ich ein ActionEvent abfragen in der Controller Klasse ?
Indem Du das Verbindest. Dabei ist egal, wie rum die Verbindung ist.

Die View kann also Methoden haben:
  • String getMessage() (Ist dann einfach ein return textfeld.getText() oder so.)
  • Eine Methode mit der sich der Controller für ein Event registrieren kann. (Kann das dann auch 1:1 an den Button weitergeben.)

Das ist ein erster Ansatz. Noch nicht ganz sauber, aber das wäre eine Möglichkeit der Verknüpfung.
 

Ljonja2107

Mitglied
Indem Du das Verbindest. Dabei ist egal, wie rum die Verbindung ist.

Die View kann also Methoden haben:
  • String getMessage() (Ist dann einfach ein return textfeld.getText() oder so.)
  • Eine Methode mit der sich der Controller für ein Event registrieren kann. (Kann das dann auch 1:1 an den Button weitergeben.)

Das ist ein erster Ansatz. Noch nicht ganz sauber, aber das wäre eine Möglichkeit der Verknüpfung.
Das mit dem Registrieren für ein Event verstehe ich noch nicht ganz, können Sie das erläutern?
 

KonradN

Super-Moderator
Mitarbeiter
Das mit dem Registrieren für ein Event verstehe ich noch nicht ganz, können Sie das erläutern?
Das ist ja, was Du mit dem testButton.addActionListener(al); machst. Der ActionListener kann aber in dem Controller sein. Du hast dann lediglich eine Methode wie:
Java:
public void addMessageSentListener(ActionListener listener) {
    myButton.addActionListener(listener);
}

Und da kann dann der Controller sich bei der View eintragen.

Bezüglich Impelmentation:
Code:
        al = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Object knopfHorcher = e.getSource();
                if (knopfHorcher == testButton) {
                    
                    String text = textArea.getText();
                    if (text.equals("")) {
                        textVonEingabe.setText("Keine Eingabe");
                    }else {
                        textVonEingabe.setText(text);
                    }
                    
                
                } else if (knopfHorcher == Settings) {
                    
                }

            }
        };
Das ist eine alte und schlechte Variante. Schreibeinfach eine Methode, die ein ActionEvent entgegen nimmt und die etwas macht. Also in deinem Beispiel z.B.:
Java:
    public void copyTextEventHandler(ActionEvent e) {
        Object knopfHorcher = e.getSource();
        if (knopfHorcher == testButton) {

            String text = textArea.getText();
            if (text.equals("")) {
                textVonEingabe.setText("Keine Eingabe");
            }else {
                textVonEingabe.setText(text);
            }


        } else if (knopfHorcher == Settings) {

        }

    };

Eintragen kannst Du sowas über eine Methodenreferenz:
testButton.addActionListener(this::copyTextEventhandler);

Das ist die bevorzugte Variante, die deutlich besser lesbar ist und die auch keine anonyme Klassen erzeugt.
 

Ljonja2107

Mitglied
Das ist ja, was Du mit dem testButton.addActionListener(al); machst. Der ActionListener kann aber in dem Controller sein. Du hast dann lediglich eine Methode wie:
Java:
public void addMessageSentListener(ActionListener listener) {
    myButton.addActionListener(listener);
}

Und da kann dann der Controller sich bei der View eintragen.

Bezüglich Impelmentation:
Code:
        al = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Object knopfHorcher = e.getSource();
                if (knopfHorcher == testButton) {
                   
                    String text = textArea.getText();
                    if (text.equals("")) {
                        textVonEingabe.setText("Keine Eingabe");
                    }else {
                        textVonEingabe.setText(text);
                    }
                   
               
                } else if (knopfHorcher == Settings) {
                   
                }

            }
        };
Das ist eine alte und schlechte Variante. Schreibeinfach eine Methode, die ein ActionEvent entgegen nimmt und die etwas macht. Also in deinem Beispiel z.B.:
Java:
    public void copyTextEventHandler(ActionEvent e) {
        Object knopfHorcher = e.getSource();
        if (knopfHorcher == testButton) {

            String text = textArea.getText();
            if (text.equals("")) {
                textVonEingabe.setText("Keine Eingabe");
            }else {
                textVonEingabe.setText(text);
            }


        } else if (knopfHorcher == Settings) {

        }

    };

Eintragen kannst Du sowas über eine Methodenreferenz:
testButton.addActionListener(this::copyTextEventhandler);

Das ist die bevorzugte Variante, die deutlich besser lesbar ist und die auch keine anonyme Klassen erzeugt.
ist für mich noch nicht zu 100% schlüssig, aber ich werde versuchen da mal durchzusteigen, danke :)
 

Ähnliche Java Themen

Neue Themen


Oben