Design-Frage: bin unzufrieden

Status
Nicht offen für weitere Antworten.

hdi

Top Contributor
Hallo,

also es geht hier nicht darum, dass ich etwas konkretes über Java wissen will etc.
Es ist nur so, dass ich schon seit Tagen unzufrieden bin mit einem gewissen Teil meines
Programms. Es geht hier lediglich um das Design, nicht die Funktionalität etc.

Ich weiss nicht so recht, wie ich die Abhängigkeiten am besten löse, oder ob ich nun
für das und das ne eigene Klasse machen soll oder nicht, etc...

Alles in allem empfinde ich diesen Teil meines Programms als "hässlich", d.h. der code ist
nicht besonders intuitiv, und...ja kA wie ich sagen soll, ich will auf jeden fall ein Refactoring,
hab jetzt es mal so gemacht, mal so, und nie war ich so richtig zufrieden...

Natürlich gibt's jetzt Code, weil es geht ja konkret darum, wie ich es coden soll.
Wer also Lust hat und mehr Erfahrung in Java (generell OO-Programmierung) als ich hat,
und das sollte keinem schwer fallen (zumindest letzteres), der kann sich ja bitte
den folgenden Code bzw. Klassen ankucken, und mir Ratschläge geben wie ich das ganze
vllt besser aufziehen könnte, also so Dinge wie:

Welche Methode ist vllt überflüssig und sollte direkt im Konstruktor gemacht werden, oder andersrum,
welche Instanzvariablen sind unsinnig, und vorallem die Frage ob diese Klassen so Sinn machen,
oder man das weiter trennen oder zusammenziehen sollte, etc etc. Design halt :p

Ich würde mich sehr darüber freuen, hier ein paar gute Ratschläge zu diesem Thema an meinem
praktischen Beispiel einsammeln zu können :cool:

Bevor ich euch die 3 Klassen jetzt hinklatsch, um die es geht, schildere ich kurz den Sinn des Programms,
um euch Zeit zu sparen: Man hat ein Fenster, das ist die Klasse Console. Es wird im Programm genutzt
um ein ListModel grafisch darzustellen. Das ist quasi auch das, was "von aussen" hier reinkommt
(wird der Console übergeben, hier ist also quasi der "Start" dieses Teilprogramms), und dieses
ListModel wird hier nicht vorgestellt, weil es darum nicht geht. Zurück zur Darstellung: In meinem Fall wird
dieses ListModel als JList angezeigt und in ein JScrollPane gepackt, damit man das halt eben scrollen kann.
Abgesehen von dieser scrollbaren Liste gibts im Fenster nur noch paar kleine Labels und eine Checkbox,
mit denen man ein paar Dinge einstellen kann bzw. die bestimmte Infos anzeigen.

Nochmal: Es geht um die Frage: Wie abstrahiere ich hier richtig? Natürlich kann ich alles in eine einzige Klasse
hauen und hätte dort direkten Zugriff auf alles. Wäre das aber so gut? Kann ich es nicht in mehrere Klassen
trennen, sodass es übersichtlicher wird? Das habe ich ja jetzt getan, aber ich finde es liest sich eben
unintuitiv, nicht so klar halt....

Okay here we go:

(Eine Sache noch: die Klassen sind nur insofern inhaltlich unvollständig, als dass ich für die Komponenten
wie eben ScrollPane, Labels etc keine Grösse oder sonst was festgelegt hab. Aber das ist hier ja nich wichtig, nur
dass ihr euch nicht wundert :p)

Code:
public class Console extends JFrame {

	private ConsoleScrollList sList;
	private ConsolePanel panel;

	public Console(ListModel listmodel) {

		setWindowProperties();
		panel = new ConsolePanel();
		sList = new ConsoleScrollList(listmodel, panel);
		getContentPane().add(sList, BorderLayout.NORTH);
		getContentPane().add(panel, BorderLayout.SOUTH);
		pack();
		setLocationOverTray();
	}

	private void setWindowProperties() {
		setTitle("LogConsole");
		setAlwaysOnTop(true);
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		setLayout(new BorderLayout());
	}

	private void setLocationOverTray() {
		int width, height;
		Rectangle visibleDesktop = GraphicsEnvironment
				.getLocalGraphicsEnvironment().getMaximumWindowBounds();
		width = (int) visibleDesktop.getWidth();
		height = (int) visibleDesktop.getHeight();
		Dimension window = getPreferredSize();
		this.setLocation(width - window.width, height - window.height);
	}
}

Code:
public class ConsolePanel extends JPanel{
	
	private JCheckBox auto;
	private JLabel time,caller;
	
	public ConsolePanel() {
		setBackground(Color.green);
		auto = new JCheckBox();
		auto.setSelected(true);
		time = new JLabel("time");
		caller = new JLabel("caller");
	}
	
	public boolean isAutoEnabled() {
		return auto.isSelected();
	}

	public void setTimeText(String text) {
		time.setText(text);
	}

	public void setCallerText(String text) {
		caller.setText(text);
	}
}

Code:
public class ConsoleScrollList extends JScrollPane implements MouseListener,
		ComponentListener {

	private JList list;
	private ListModel model;
	private ConsolePanel cPanel;

	public ConsoleScrollList(ListModel model, ConsolePanel cPanel) {

		this.model = model;
		this.cPanel = cPanel;
		setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		createList();
		this.setViewportView(list);
	}

	private void createList() {

		list = new JList();
		list.setModel(model);
		list.setFont(new Font("Arial", Font.PLAIN, 10));
		list.setBackground(new Color(180, 180, 180));
		list.setForeground(Color.black);
		list.setSelectionBackground(Color.red);
		list.setSelectionForeground(Color.white);
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.addMouseListener(this);
		list.addComponentListener(this);
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		int index = list.locationToIndex(new Point(e.getX(), e.getY()));
		cPanel.setTimeText(model.getTimeFrom(index));
		cPanel.setCallerText(model.getCallerOf(index));
	}

	@Override
	public void componentResized(ComponentEvent e) {
		if (cPanel.isAutoEnabled()) {
			JScrollBar ver = this.getVerticalScrollBar();
			JScrollBar hor = this.getHorizontalScrollBar();
			ver.setValue(ver.getMaximum());
			hor.setValue(hor.getMinimum());
		}
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void componentHidden(ComponentEvent e) {
	}

	public void componentMoved(ComponentEvent e) {
	}

	public void componentShown(ComponentEvent e) {
	}
}

Also, das ganze kann man doch verbessern, sodass andere jetzt zB sich leichter "reinlesen" können und man
einfach mehr Überblick hat, ohne dass man alles unnötig verklompiziert und irgendwelche Dinge x-fach über
Konstruktoren weitergeben muss etc etc.

Aber wie ???:L

DANKE schonmal :toll: :toll: :toll:
 

Templon

Bekanntes Mitglied
Ich muss sagen, ich sehe eigentlich nur etwas, was ich nicht ganz verstehe.

Code:
 public void mouseClicked(MouseEvent e) { 
      int index = list.locationToIndex(new Point(e.getX(), e.getY())); 
      cPanel.setTimeText(model.getTimeFrom(index)); 
      cPanel.setCallerText(model.getCallerOf(index)); 
   }

Warum brauchst du nicht einfach ein "ListSelectionListener" (oder ähnlich)?
Und was sind getTimeFrom() und getCallerOf() für Methoden? Die sind nicht in dem ListModel interface deklariert.

und vllt noch ein bisschen JavaDoc, dann passt das schon meiner Meinung nach =)
 

Marco13

Top Contributor
Hmja... Mir sind die Intentionen hinter den Klassen und deren Schnittstellen nicht ganz klar. Ganz pragmatisch kann man sich immer die Frage stellen: Was soll gehen? (->und was ist nötig, damit das geht?) Welche Schnittstellen sollen nach außen verfügbar sein?

Etwas ... "befremdlich" wirkt erstmal, dass die Klasse "Console" keine eigene Funktionalität anbietet, sondern nur ein paar Components kapselt. Soll man die überhaupt von außen sehen? Wenn ja, ist das OK so. Wenn nein, dann ... ist das auch OK - aber vielleicht(!!!) überflüssig.

Falls das ListModel kein java.swing.ListModel ist, ist der Name schon ziemlich ungünstig gewählt. Aber wie auch immer: Du hast also eine Klasse "ListModel", die vermutlich DefaultListModel erweitert, und zusätzlich diese Methoden "getCallerOf" usw. anbietet. Vermutlich(!) sieht diese Klasse also ziemlich genau so aus
Code:
class ListModel extends DefaultListModel
{
    public String getTimeFrom(int index)
    {
        LogEntry logEntry = (LogEntry)getElementAt(index);
        return logEntry.getTime();
    }
    // die andere analog....
}
Dafür eine eigene Klasse ist eigentlich nich nötig - und in gwisser Hinsicht nachteilhaft, weil man ja kein anderes ListModel mehr verwenden kann.

Und warum wird das ListModel von außen übergeben? Wer erstellt und füllt das? Wer soll noch Zugriff auf das ListModel haben, das eigentlich nur ganz versteckt irgendwo liegen sollte (nämlich in der JList, die in der ConsoleScrollList liegt, die in der Console liegt)

Und die ConsoleScrollList ... also, ich habe noch nie eine Klasse von JScrollPane erben lassen. Und in deinem Fall erbst du von dieser Klasse, weil.... ???? Das erstellen der JList könnte außerhalb gemacht werden, und die Listener könnten auch anonyme Klassen sein ...

Konkrete Verbesserungsvorschläge... sind schwierig, solange man nicht weiß, was damit gehen soll. Ein bißchen hab' ich ja schon aus den anderen Threads mitgekriegt, aber insbesondere die Frage, was das für ein ListModel ist, und WER da WAS damit macht, ist mir nicht klar. Wenn ich es richtig sehe, ist die "Console" ja die einzige Sache, die von außen sichtbar sein soll. Und sie bietet nach außen hin keine echte Funktionalität, sondern verwaltet sich komplett selbst. Insofern könnte das auch alles in eine Klasse - nicht um sich scheinbar das Leben leicht zu machen, oder weil man sich um eine vernünftige Klassendtruktur drücken will, sondern weil "eine Klasse" vielleicht die vernünftigste Klassenstruktur ist.

Aber da kamen jetzt schon SEHR oft die Worte "Vermutlich" und "Vielleicht" vor - wissen kannst nur DU das ...
 

hdi

Top Contributor
okay ich zeig euch jetz doch nochmal die klasse listmodel:

Code:
public class ListModel extends DefaultListModel {

	private ArrayList<Entry> entries;

	public ListModel() {
		entries = new ArrayList<Entry>();
	}

	@Override
	public synchronized void addElement(Object o) {
		super.addElement(entries.add((Entry) o));
	}

	@Override
	public synchronized Object getElementAt(int index) {
		return entries.get(index).getMessage();
	}

	public synchronized String getTimeFrom(int index) {
		return entries.get(index).getTime();
	}

	public synchronized String getCallerOf(int index) {
		return entries.get(index).getCaller();
	}
}

zum Sinn des ganzen: Man kann überall im Programm per Log.say() etwas loggen, und das ist das Model, und die Darstellung in die Console mit ihrer JList usw. Das hier ist die statische Klasse die man zum loggen hernimmt:

Code:
public class Log {

	private static ListModel model;
	private static Console console;
	private static boolean neverUsed = true;

	public static synchronized void say(String message) {

		if (neverUsed) {
			model = new ListModel();
			console = new Console();
			console.setListModel(model);
			console.setVisible(true);
			neverUsed = false;
		}

		final Entry e = new Entry(message);
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				model.addElement(e);
			}
		});
	}
}

So, also eigentlich bin ich mit diesen Klassen schon zufrieden, es kam die Frage warum ich eine eigene Klasse für das ListModel mache. Naja, wegen diesen zwei Methoden getTimeFrom und getCallerOf, die es normalerweise nicht gibt.
Das Problem ist, dass die Sachen in die Liste geschrieben werden (jetzt visuell gemeint), die getElementAt() zurückliefert. D.h. ich kann dort keine Datenstruktur oder sowas returnen, weil dann die Liste voller Object@121dfj und so was ist..
Und mein Modell besteht halt nun mal nicht nur aus einem String, sondern aus einem Objet ("Entry"), dass mehr anbietet. Der Vollständigkeit halber auch dazu mal die Klasse:

Code:
public class Entry {

	private final String MESSAGE, TIME, CALLER;

	public Entry(String message) {

		MESSAGE = message;
		TIME = getFormattedTime();
		StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
		CALLER = getCallerInfo(steArray[steArray.length - 1]);
	}

	private String getCallerInfo(StackTraceElement ste) {
		String caller = ste.getClassName().split("\\.")[1];
		String method = ste.getMethodName();
		int line = ste.getLineNumber();
		return (caller + " : " + method + " (" + line + ")");
	}

	private String getFormattedTime() {
		SimpleDateFormat hms = new SimpleDateFormat("HH:mm:ss");
		return hms.format(new Date());
	}

	public String getMessage() {
		return MESSAGE;
	}

	public String getTime() {
		return TIME;
	}

	public String getCaller() {
		return CALLER;
	}
}

Naja also die 3 Klassen Log, Entry und ListModel find ich eig. okay so wie sie sind. Sie sind klein, übersichtlich und man blickt da schon recht schnell durch... Aber eben diese ganze Consolen-Zeugs nervt etwas.
Ich weiss nich was ihr meint damit, dass sie keine echte Funktionalität "nach außen" anbietet.. Was meint ihr?
Sie zeigt halt Log-Einträge an und man kann da rumklicken, zB auf nen Eintrag dann werden weitere Infos angezeigt (getTimeOf / getCallerOf) und man hat nen Button für Autoscroll etc...

Warum erbe ich von ScrollPane? Ja, das ist echt mal ne gute Frage ;) Das sollte ich mal weglassen. Also eigentlich
bin ich (auch?) mehr der Meinung, man sollte alles in eine Klasse tun extends JFrame, und die hat halt ne Liste und n ScrollPane und n JPanel und Buttons etc.

Leider wird so eine Klasse recht lang, auch wegen den Listenern, und den ganzen Einstellungen. Irgednwie ist es halt doch doof, dass zB die JList, also ein wichtiges Element in dem ganzen hier, dann genauso in einer Klasse Konsole ist wie zB irgenwelche Settings wie Schriftarbe und Grösse des Fenster und sowas, ich meien das passt doch nicht...

Hm naja, vllt könnt ihr jetz mehr anfangen (ihr habt jetz mit diesen 3 neuen Klassen das komplette Programm, bzw es ist ja kein eigenes Programm, man kann es nur für andere Programme verwenden indem man lediglich solche Log.say() Aufrufe macht)..
 

Marco13

Top Contributor
Das Problem ist, dass die Sachen in die Liste geschrieben werden (jetzt visuell gemeint), die getElementAt() zurückliefert. D.h. ich kann dort keine Datenstruktur oder sowas returnen, weil dann die Liste voller Object@121dfj und so was ist..
Und mein Modell besteht halt nun mal nicht nur aus einem String, sondern aus einem Objet ("Entry"), dass mehr anbietet.


Wo ho :shock: vielleicht war dir das nicht bewußt: In der JList wird praktisch "toString" aufgerufen und angezeigt. Wenn du also in der Klasse logEntry sowas machst wie
Code:
class LogEntry
{
    ...
    public String toString() { return "At "+time+" from "+caller+" got message: "+message; }
}
dann stehen in der JList schöne, informative Strings, die den gesamten LogEntry beschreiben.

Aber weder in diesem noch in den vorherigen Threads ist mir klar geworden, warum du die Einträge in einer ArrayList speichern willst ... erübrigt sich das vielleicht durch das "toString"? ???:L

Ich weiss nich was ihr meint damit, dass sie keine echte Funktionalität "nach außen" anbietet..

Naja, z.B. die ConsolePanel Klasse: Niemand, der deinen Logger oder diese Console verwendet, muss die ConsolePanel Klasse kennen. Sie ist nichts weiter als ein JPanel mit zwo, drei Components drauf. EINEN Zweck könnte sie haben: Wenn du Programmierern, die deinen Logger+Console wie ein "Framework" verwenden wollen, die Möglichkeit bieten wolltest, einzelne LogEntries individuall anzuzeigen. Wenn z.B. ein Benutzer nur "Caller" und "Message" anzeigen will, und der andere NUR die Message, oder sonstwas - aber das würde man dann eben allgemeiner machen, z.B. dem ConsolePanel gleich einen LogEntry übergeben oder so (nicht so wichig).

Ich hatte ja auch schon in anderen Threads über den Anwendungsfall spekuliert, und dazu auch schon was complierbares gepostet... Aber für "den Anwendungsfall" reicht es ja, wie es jetzt ist. Ist nur die Frage, wie allgemein verwendbar und abstrakt das ganze werden soll...
 

hdi

Top Contributor
Hm, also erstmal danke für die Info mit dem toString(). Leider kann ich deinen Ratschlag nicht befolgen, denn was in der Liste angezeigt werden soll, soll auch nur die Message sein ;) Ich will dort NICHT die weiteren Infos wie caller etc anzeigen, diese will ich unten in nem Panel anzeigen, wenn man auf einen Eintrag (=Message) klickt.. Nicht weil ich auf Klickorgien stehe, aber weil schlichtweg die Liste so breit wäre wie der halbe Bildschirm wenn ich dort alle Infos reinpacken will. Ich hab dazu weiter unten auch noch eine Frage....

Nun, aber deshalb brauch ich wohl die Methoden im ListModel alle, und komme nicht nur mit der getElementAt() Methode aus.

Die Klasse ConsolePanel gibt es übrigens nur aus einem Grund: Ich hasse generell das arbeiten mit GUI, weil man dort soviele Zeilen Code schreiben muss, um so wenig zu erreichen, und ich will das immer möglichst "wegpacken und in ne Ecke stellen" sodass man sich nicht mehr damit beschäftigen muss.

das "Problem" ist: Was auch immmer die Console für eine Funktionalität anbietet, in diesem Fall das Anzeigen einer Liste mit LogEinträgen und die Möglichkeit, da rumzuklicken und was zu speichern etc, das alles hat doch nix mit der GUI zu tun.

Sprich wenn ich sehen will, was diese Console ist, dann will ich doch nicht so Zeilen lesen wie:

Code:
someButton.setColor(..)
someButton.setFont(new Font(...));
someOtherButton.setForeground(Color.red);
somePanel.setLayout(wahtever);
anotherPanel.add(someButton);
setPreferedSizeOfThousandThings...
anotherPanel.setBakcground()

WEN INTERESSIERT DAS? Versteht ihr was ich mein? Mit so Dingen kriegt man halt locker mal ein- zweihundert Zeilen Code zusammen. Ich wollte diese lästigen und eig. unwichtigen Dinge abstrahieren und absondern von der Klasse Console, da dort nur die Funktionalität zusammengebaut wird. Naja.

Aber ich wollte nochmal auf mein ListModel zurückkommen, und eine Frage die ich schon mal irgendwo gestellt habe, aber irgendwie konnte das bisher nicht (zufriedenstellend) gelöst werden:

Ich suche noch immer die Methode, die ein ListModel mit seiner JList synchronisiert. Aus o.g. Tatsache, dass die Liste nur die MEssages zeigt, und man nur per Klick die weiteren Infos angezeigt bekommt, ensteht für den User das Problem einer Klickorgie wenn viele NAchrichten regelmässig reinkommen und er mitkucken will, woher die genau kommen.

Das wollte ich ihm abnehmen indem ich in der JList jedesmal den neuesten Eintrag selektiere, wenn er kommt. (Damit würden nämlich automatisch im Panel drunter die weiteren Ifnos angezeigt werden) Das kann ich bisher nur, wenn das ListModel seine JList kennt, was ich irgendwie nich so toll find. Ich meine es gibt doch ne Methode, die die beiden synchronisiert? Irgendwo in der JList -Klasse muss es doch ne Methode geben, die aufgerufen wird wann immer das addElement() im Model aufgerufen wird. Und die brauch ich damit ich da noch zusätzlich reinschrieben kann: adde neueste Eintrag UND selektiere ihn auch.

Hab bisher nix gefunden auch in der API nicht, ich meine das kann ja nicht sein, die synchronisieren sich ja nich per Geister-Hand, da steckt doch n Observer-Pattern dahinter und ich such seine update-Methode..

Ich weiss, dass es den CellRenderer gibt. Damit würde das ja durchaus gehen (glaub ich) Mein Problem bisher: Ich konnte mir keinen CellRenderer bauen, der genauso aussieht wie der Default-CellRenderer. Weil ich nicht weiss wie der Default-CellRenderer aussieht, und wenn ich da nen eigenen mach mit JLabels etc. sieht der Kacke aus ;)

Ausserdem hatte ich es schon mit nem ListDataListener probiert, den ich dem ListModel adde. Allerdings weiss ich auch hier nicht, wie ich den benutz ohne dass ich die JList kennen muss in der ListModel Klasse. (Wenn ich sie eh kennen muss, kann ich mir den kompletten ListDataListener sparen und das gleich in der addElement() Methode machen...)
 

Marco13

Top Contributor
Leider kann ich deinen Ratschlag nicht befolgen,...

Leider bist do ohnehin ziemlich Ratschlagsresistent, und das ist ... für denjenigen, der versucht, zu helfen... ziemlich frustrierend. Irgendwie habe ich das Gefühl, dass du ein bißchen in Anlehnung an das "infinite monkey theorem" einen Haufen Code produzierst, in der Hoffnung, dass irgendwann was vernünftiges rauskommt. Aber ohne Nachdenken, API lesen, Nachvollziehen von Vorschlägen, Beispielen und Tutorials kann das ziemlich uneffizient sein.

Wie auch immer.

Du kannst natürlich auch
Code:
    public String toString() { return message; }
schreiben... und die "Object"s, die man mit getElementAt von der List bekommt, kann man nach LogEntry casten:
Code:
LogEntry entry = (LogEntry)list.getElementAt(0);



Sprich wenn ich sehen will, was diese Console ist, dann will ich doch nicht so Zeilen lesen wie:
...
WEN INTERESSIERT DAS? Versteht ihr was ich mein? Mit so Dingen kriegt man halt locker mal ein- zweihundert Zeilen Code zusammen. Ich wollte diese lästigen und eig. unwichtigen Dinge abstrahieren und absondern von der Klasse Console, da dort nur die Funktionalität zusammengebaut wird. Naja.


Ja, das interessiert denjenigen, der sich fragt, warum da so komsiche Fonts und Farben verwendet werden. Wenn du willst, dass ein Button grün ist, musst du irgendwo sagen, dass er grün sein soll. Wenn du weniger Code schreiben willst, lass die Farben und Fonts so, wie sie sind. Punkt.

"Abstrahiert" wird dadurch, dass du das in eine Klasse packst, garnichts. Abstrahiert wird über die Schnittstellen. Über die Frage, welche Klassen und Methoden public sind, und wie genau die Interaktion der Klassen untereinander ist. Dass du da ein "ConsolePanel" verwendest, interessiert wirklich keine Sau. Ob du die Klasse nun verwendest oder nicht, ist wurscht. Du kannst dir noch viel mehr Klassen machen
Code:
class GreenButton extends JButton { public GreenButton() { this.setBackground(Color.GREEN); }}
Grandios. Ändert aber nichts daran, dass deine Log-Klasse ein ListModel enthält, das mehr ist als ein ListModel, und du das "nie" wieder los wirst, weil deine Console (die keine Console ist) GENAU so ein ListModel braucht.

Hier mal ein bißchen was, was ich aus einigen deiner letzten Threads (und MEINER Antworten darauf!!!) zusammengewurstet hatte (ICH würde das eigentlich nicht so machen, aber im anderen Thread hatte sich das so aus deinen Vorgaben ergeben). Der Logger kann ganz normal verwendet werden, und veröffentlicht seine Nachrichten über die "logDataAdded" Methode der LogDataListener-Schnittstelle. Die wird von der LogConsole implementiert, und darum kann man die als LogDataListener dranhängen, und sie tut, was sie soll.

Lies' es, ignorier' es, oder lass es bleiben.

Code:
// Rum-umgebaut für [url]http://www.java-forum.org/de/viewtopic.php?t=76799&highlight=&sid=b4f2875c907fb651b8ea8ef9c131476a[/url]

import javax.swing.*;
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.text.*;

public class LogDemo3
{
    public static void main(String args[])
    {

        try {
            SwingUtilities.invokeAndWait(new Runnable()
            {
                public void run()
                {
                    LogConsole logConsole = new LogConsole();
                    logConsole.setVisible(true);
                    Log.addLogDataListener(logConsole);
                }
            });
        }  catch (Exception e) { e.printStackTrace(); }

        Log.say("Hallo 00");
        Log.say("Hallo 01");
        Log.say("Hallo 02");
        Log.say("Hallo 03");
        Log.say("Hallo 04");
        Log.say("Hallo 05");
        Log.say("Hallo 06");
        Log.say("Hallo 07");
        Log.say("Hallo 08");
        Log.say("Hallo 09");
        Log.say("Hallo 10");
        Log.say("Hallo 11");
        Log.say("Hallo 12");
        Log.say("Hallo 13");
        Log.say("Hallo 14");
        Log.say("Hallo 15");
        Log.say("Hallo 16");
        Log.say("Hallo 17");
        Log.say("Hallo 18");
        Log.say("Hallo 19");

    }
}


class Log
{
    private static LogDataModel logDataModel = new LogDataModel();

    public static void say(String message)
    {
        logDataModel.add(message);
    }

    public static void addLogDataListener(LogDataListener logDataListener)
    {
        logDataModel.addLogDataListener(logDataListener);
    }
    public static void removeLogDataListener(LogDataListener logDataListener)
    {
        logDataModel.removeLogDataListener(logDataListener);
    }

}


interface LogDataListener
{
    void logDataAdded(LogDataEvent logDataEvent);
}

class LogDataEvent
{
    private LogDataModel source;
    private LogEntry logEntry;

    public LogDataEvent(LogDataModel source, LogEntry logEntry)
    {
        this.source = source;
        this.logEntry = logEntry;
    }

    public LogDataModel getSource()
    {
        return source;
    }

    public LogEntry getLogEntry()
    {
        return logEntry;
    }
}

class LogDataModel
{
    private List<LogEntry> logEntries = new ArrayList<LogEntry>();

    private List<LogDataListener> listeners = new ArrayList<LogDataListener>();

    public void addLogDataListener(LogDataListener logDataListener)
    {
        listeners.add(logDataListener);
    }
    public void removeLogDataListener(LogDataListener logDataListener)
    {
        listeners.remove(logDataListener);
    }

    public void add(String message)
    {
        LogEntry logEntry = new LogEntry(message);
        logEntries.add(logEntry);
        fireLogDataAdded(logEntry);
    }

    protected void fireLogDataAdded(LogEntry logEntry)
    {
        LogDataEvent event = new LogDataEvent(this, logEntry);
        for (LogDataListener logDataListener : listeners)
        {
            logDataListener.logDataAdded(event);
        }
    }
}



class LogConsole extends JFrame implements LogDataListener
{

   private JScrollPane scrollPane;
   private JLabel time,caller;
   private DefaultListModel listModel;

   public LogConsole()
   {
      setWindowProperties();

      listModel = new DefaultListModel();
      getContentPane().add(createList(), BorderLayout.NORTH);
      getContentPane().add(createEntryPanel(), BorderLayout.SOUTH);
      pack();
      setLocationOverTray();
   }

   private Component createList()
   {
      JList list = new JList();
      list.setModel(listModel);
      list.setFont(new Font("Arial", Font.PLAIN, 10));
      list.setBackground(new Color(180, 180, 180));
      list.setForeground(Color.black);
      list.setSelectionBackground(Color.red);
      list.setSelectionForeground(Color.white);
      list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      scrollPane = new JScrollPane(list);

      list.addListSelectionListener(new ListSelectionListener()
      {
          public void valueChanged(ListSelectionEvent e)
          {
              JList s = (JList)e.getSource();
              LogEntry entry = (LogEntry)s.getSelectedValue();
              time.setText(entry.getTime());
              caller.setText(entry.getCaller());
          }
      });

      return scrollPane;
   }


   private Component createEntryPanel()
   {
      JPanel entryPanel = new JPanel();
      entryPanel.setLayout(new FlowLayout());
      entryPanel.setBackground(Color.green);
      time = new JLabel("time");
      caller = new JLabel("caller                           ");
      entryPanel.add(time);
      entryPanel.add(caller);
      return entryPanel;
   }


   public void logDataAdded(final LogDataEvent logDataEvent)
   {
       try
       {
           SwingUtilities.invokeAndWait(new Runnable()
           {
               public void run()
               {
                   listModel.addElement(logDataEvent.getLogEntry());
               }
           });
           SwingUtilities.invokeLater(new Runnable()
           {
               public void run()
               {
                   JScrollBar ver = scrollPane.getVerticalScrollBar();
                   JScrollBar hor = scrollPane.getHorizontalScrollBar();
                   ver.setValue(ver.getMaximum());
                   hor.setValue(hor.getMinimum());
               }
           });
       }
       catch (Exception e) { e.printStackTrace(); }
   }

   private void setWindowProperties() {
      setTitle("LogConsole");
      setAlwaysOnTop(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      //setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
      setLayout(new BorderLayout());
   }

   private void setLocationOverTray() {
      int width, height;
      Rectangle visibleDesktop = GraphicsEnvironment
            .getLocalGraphicsEnvironment().getMaximumWindowBounds();
      width = (int) visibleDesktop.getWidth();
      height = (int) visibleDesktop.getHeight();
      Dimension window = getPreferredSize();
      this.setLocation(width - window.width, height - window.height);
   }
}




class LogEntry {

   private final String MESSAGE, TIME, CALLER;

   public LogEntry(String message) {

      MESSAGE = message;
      TIME = getFormattedTime();
      StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
      CALLER = getCallerInfo(steArray[steArray.length - 1]);
   }

   private String getCallerInfo(StackTraceElement ste) {
      String caller = ste.getClassName();//.split("\\.")[1];
      String method = ste.getMethodName();
      int line = ste.getLineNumber();
      return (caller + " : " + method + " (" + line + ")");
   }

   private String getFormattedTime() {
      SimpleDateFormat hms = new SimpleDateFormat("HH:mm:ss");
      return hms.format(new Date());
   }

   public String getMessage() {
      return MESSAGE;
   }

   public String getTime() {
      return TIME;
   }

   public String getCaller() {
      return CALLER;
   }

   public String toString()
   {
       return MESSAGE;
   }
}


Wenn du bereit bist, auf Vorschläge einzugehen, und man in den Nachfragen und den späteren Threads auch sieht, dass du versucht hast, das nachzuvollziehen, und NICHT einfach nur neuen Code postest, dessen Zusammenhang zum vorhergehenden sich vielleicht nichtmal dir selbst erschließt, werde ich in Erwägung ziehen, weiterhin so ausführliche Antworten zu geben, wie bisher.
 

hdi

Top Contributor
Okay, also:

Ich schätze deine Hilfe auf jeden Fall, und ich beschäftige mich auch damit. Allerdings kann es dir so vorkommen, als würde ich das nicht tun, wenn ich zB Code poste, der damit nichts zu tun hat. Du musst es aber so sehen, dass ich nicht wirklich weiss, ob er was damit zu tun hat. Und das kommt auch nicht davon, dass ich mir deinen Code nicht ansehe. Und ich kuck auch in die API. Aber die Zusammenhänge sind manchmal schwer zu erkennen, und wenn ich sie nicht erkenne, weiss ich auch nichts von ihrer Existenz. Im Endeffekt kommt manchmal Hilfe nicht an, das meine ich damit. Ich bemühe mich ja, aber wenn ich etwas schlicht falsch auffasse, dann hab ich es eben falsch aufgefasst. Ist ja nicht so, dass ich mir in dem Moment bewusst bin, dass ich etwas falsch auffasse, weil dann würde ich es anders auffassen ;)

Naja.. also, ich hatte mir schon damals dein Code-Beispiel angekuckt, und dieses jetzt natürlich wieder.

Jetzt bin ich aber wieder in so einer Situation, wo mich dein Code nicht weiterbringt. Nicht, weil er es vllt nicht kann, sondern weil ich halt nicht weiss, wie. So wie ich das jetzt verstehe mit dem, was ich bisher weiss, kann ich meine o.g. Probleme mit deinem Konzept auch nicht (besser) lösen. Das denke ich jetzt, keine Ahnung ob das stimmt.

Vllt ( !!! ) gibt es ja noch immer ein Missverständnis: Ich habe das alles ja schon gecodet, es funktioniert auch alles komplett zu 100%. Nur ich denke, dass man es besser machen kann, dass ich es schlecht gemacht habe.

Dein Code zeigt eine andere Herangehensweise an das Problem, die vermutlich eleganter ist. Obwohl du dir soviel Mühe gegeben und soviel Code geschrieben hast, fehlen aber leider in deinem Beispiel genau die Dinge, mit denen ich bei mir eben unzufrieden bin. Ich will hier nochmal sagen: Vielleicht fehlen sie auch nicht, und ich seh sie nur nicht...

Es geht ganz konkret um folgende Dinge:

- Neue Einträge sollen in der JList automatisch markiert werden:
Ich habe das bisher nicht anders lösen können, als dass ich dem Modell (in deinem Fall LogDataModel) diese JList gebe, was ich halt für nicht schön halte und ich glaube, das Modell muss doch nicht wirklich die JList kennen damit die da etwas selektiert.
Nach meinem Verständnis würde diese funktion in deinem Beispiel auch nur so gehen, dass ich mir die JList über die LogConsole hole, d.h. ich geb der LogConsole eine Instanz von JList und in createList() instantiier ich die dann. Dann würde ich halt in der Klasse LogConsole eine Methode anbieten müssen getJList().

Und das war die Frage oben: Muss das so sein? Die JList bekommt doch auch irgendwie mit, wenn es einen euen Eintrag gibt. Kann sie diesen nicht selektieren? Muss das tatsächlich zB das Model "von außen" machen, kann die das nicht selber.

So, zweites Problem:

Du hast jetz im Panel viele Dinge weggelassen. Da gibts noch eine Checkbox, wenn die an ist, scrollt er (und markiert, s.o.) automatisch mit, ist sie ausgestellt (nicht angehackt), dann nicht. Zudem gibt es einen Save Button.

D.h. genau dann hast du auch in deinem Beispiel eine Klasse LogConsole die scheiss lang sein wird, und nicht mehr übersichtlich, unter anderem weil:

- der actionListener 100 Zeilen hat, er saved den kompletten Log (Ich habe in der Tat eine Klasse "SaveButton" dafür gemacht, du hast ja bei deinem Buttom-Beispiel oben eher gesagt dass sowas Schrott ist)
- du nicht mehr dein kleines borderLayout hast mit den 2 Labels, sondern noch den Button und die Checkbox rechts angeordnet, das sind wieder einige Zeilen mit setPreferredSize(), add(), setLayout(), etc.

Also, ich kann nicht oft genug erwähnen, dass ich deine Hilfe schätze, aber entweder du verstehst mein Problem nicht, oder ich kann mein Problem nicht rüberbringen, oder deine hilfe löst in der Tat das Problem, aber ich sehe nicht wie, obwohl ich mich damit beschäftige !!

Vllt hab ich ja gar kein Problem und bilde mir nur ein, eins zu haben. Vllt ist mein Code 100% okay und gut. Aber ich weiss es leider nicht, es gibt im Internet kein Tool, das mein sein Code scannen lässt, und das dann sagt "Ja perfekt" oder "Du kannst es auch besser lösen"...

Ich weiss nicht mehr, was ich sagen soll. Wie oben beschrieben, bin ich einfach unzufrieden mit meinem Klassen-System und allem, weil um diese ganzen Funktionalitäten wie zB Autoscroll oder das Auto-Select umsetzen zu können, hat bei mir grad jede Klasse eine Instanzvariable von jeder anderen...

Und wenn ich diese funktionalitäten bei deinem Beispiel implementieren möchte, würde es wieder darauf hinauslaufen und nicht besser, nur anders, sein. Aber vllt kannst du diese Dinge einbauen, ohne dass es so endet wie bei mir. Ich wüsste halt jetzt nicht wie. Und letztendlich kann ich ja auch nur sagen: Schon klar, dass es anstrengend sein kann, jemandem zu helfen. Das ist ja freiwillig, wenn du keinen Bock mehr hast darauf, dann lass es doch und les lieber ein gutes Buch ;) Ich bin nur dankbar für jede Hilfe, und stell mich sogut an wie ich kann. Wenn man mir nicht mehr hilft, so what that's life ;)
 

hdi

Top Contributor
ich kann leider nicht editieren, aber ich hab das Bedürfnis mich nochmal GANZ klar auszudrücken, damit du weisst, was ich meinen könnte :p

Was mir an meinem Code also Klassen-System nicht gefällt, ist, dass fast jede Klasse eine Instanzvariable von fast jeder anderen Klasse hat!

Warum? Weil zB die checkbox für das autoscroll im Panel liegt. Die JList soll nur mitscrollen, wenn das aktiv ist, d.h. die JList muss die LogConsole kennen, sich ihr Panel holen, dann die Checkbox darauf.
Die JList soll automatisch das neueste Element markieren. Geht bei mir nur so, dass das Model die JList kennt, d.h. die LogConsole, und das ScrollPane auf dem die Liste liegt.

Und so fort...

Das taugt mir nicht aber ich weiss nicht wie ich es anders implementieren kann, auch nicht mit deinem Konzept!
Naja, ich meine es funktioniert ja schon... Wahrscheinlich such ich nur zwanghaft nach einer vieeeel tolleren Lösung, die es gar nicht gibt..
 

Marco13

Top Contributor
OK, du kannst ja wenn du willst mal EINE Datei in deinen "Eigenen Dateien" uploaden, wo alle Klassen zusammengeurstet wind, so dass man sie einfach compilieren und starten kann (wie das oben gepostete). Dann kann man da mal "als ganzes" drüberschauen. (FALLS "jemand" die Zeit dafür findet)

Bisher ist vermutlich keine deiner Klassen "zu lang". Die gepostete "LogConsole" hat gerade mal lächerliche 50 Zeilen echten Code. Wenn eine Klasse 500 Zeilen hat, ist das aber auch noch OK. (Klassen wie "JTable" oder "Component" haben 1600-2000 Zeilen echten Code - beide Klassen haben jeweils ca. 10000 Zeilen (einschließlich nicht-code) und sind über 300 KB groß - das ist nichts, woran man sich orientieren sollte(!) aber man braucht nicht wegen 200 oder 300 Zeilen in Panik zu verfallen - das Problem ist nicht die Anzahl der Zeilen...)

Speziell beim GUI-Basteln ist das eben so: Wenn jede Component eine bestimmte Farbe, PreferredSize, Schriftart, usw hat, dann kommen da eben viele Zeilen zusammen. Das sollte aber kein Problem sein, weil man sich dann z.B. einfach eine Methode macht
Code:
private JButton createMyComplicatedButton()
{
    JButton button = new JButton();
    button.set....
    button.set....
    button.set....
    button.set....
    button.set....
    button.set....
    button.set....
    button.set....
    button.set....
    return button;
}
Also, nur weil eine Klasse viele Zeilen hat, heißt das nicht notwendigerweise, dass die "kompliziert" ist. Ein bißchen plakativ formuliert: Wie kompliziert eine Klasse ist, sieht man daran, welche public-Methoden sie hat. Der Rest sind Implementierungsdetails. Und wie viele (nicht geerbte) public-Methoden hat die LogConsole? GENAU EINE!:
Code:
public void logDataAdded(final LogDataEvent logDataEvent)
Das ist alles, was den Benutzer der LogConsole interessieren muss: Man kann ihr einen Log-Eintrag hinzufügen. Mehr nicht.

Also: Mach dir weniger Gedanken über die Anzahl der Zeilen, sondern um Schnittstellen, Strukturen und Abhängigkeiten.

Konkret:

Wenn "fast jede Klasse eine Instanzvariable von fast jeder anderen Klasse hat" dann ist das in der Tat ein Zeichen für ungünstiges Design. Wie man das besser machen könnte, kann man nur sagen, wenn man den Überblick hat...

Zu den erwähnten Fragen:

- Neue Einträge sollen in der JList automatisch markiert werden:
Ich habe das bisher nicht anders lösen können, als dass ich dem Modell (in deinem Fall LogDataModel) diese JList gebe, was ich halt für nicht schön halte und ich glaube, das Modell muss doch nicht wirklich die JList kennen damit die da etwas selektiert.


Jetzt ist nicht klar, welches Modell du meinst: Dein "ListModel extends DefaultListModel", oder das "LogDataModel", zu dem es bei dir garkeine Entsprechung gibt!?

Wie auch immer: Das Modell muss die JList nicht kennen. Genauer: Das Modell sollte die JList AUF KEINEN FALL kennen! Das Modell (egal ob ein java-ListModel, oder ein eigenes "LogDataModel") sollte möglichst KEINE Abhängigkeiten zur View oder irgendjemand anderem haben (außer ggf. andere Modelle). Das Modell ist im Idealfall etwas komplett "eigenständiges".

Also: NIEMAND muss die JList kennen, außer
- 1 dem (anonymen) ListSelectionListener, der bewirkt, dass die Zusatzinformationen zum ausgewählten Eintrag angezeigt werden
- 2 demjenigen, der die neuen Einträge markieren soll

1. Wie man ersteres machen kann, ist schon im geposteten Code beschrieben. Schon da gibt es viele Alternativen, aber ein anonymer Listener, der in seiner "valueChanged"-Methode sowas macht wie
Code:
          public void valueChanged(ListSelectionEvent e)
          {
              JList s = (JList)e.getSource();
              LogEntry entry = (LogEntry)s.getSelectedValue();
            
              zeigDenGanzenKramIrgendwieUndIrgendwoAn(entry);
          }
ist sehr allgemeingültig, und kann bei Bedarf sehr leicht geändert werden. (Genaugenommen muss man aber nur die (private!) Methode "zeigDenGanzenKramIrgendwieUndIrgendwoAn" ändern...)

2 Das war ja deine eigentliche Frage: Auch derjenige, der die neuen Einträge markieren soll, kann als anonymer Listener implementiert sein. Man kann ja sowas schreiben wie
Code:
final JList list = .... die JList eben
list.getModel().addListDataListener(new ListDataListener())
{
    public void	contentsChanged(ListDataEvent e) {}
    public void intervalRemoved(ListDataEvent e) {}
    public void intervalAdded(ListDataEvent e) 
    { 
        list.setSelectedIndex(list.getModel().getSize()-1);
    }
});

Es muss also niemand die JList als Instanzvariable kennen. Auch das Modell muss niemand kennen. Man kann dort, wo die JList erstellt wird, mit diesem anonymen Listener diese Funktionalität erreichen. Wenn dir diese anonymen Listener zu unübersichtlich sind, kannst du stattdessen natürlich auch eine (NICHT-public!)-Klasse oder private, statische, innere Klasse erstellen
Code:
// ggf. "private static class"
class FirstEntrySelector implements ListSelectionListener { /* methoden wie oben */ }
und dann einfach einen an das ListModel hängen
Code:
list.getModel().add(new FirstEntrySelector(list));
oder schlicht und einfach wieder eine Methode dafür machen

In gewisser Hinsicht ist 1. sogar noch komplizierter, weil man dort (indirekt) wissen muss, WO und WIE die Daten angezeigt werden sollen, aber auch das kann in einer privaten Methode oder einer Klasse mit EINER public-Methode "showThatStuff(ListEntry e)" versteckt sein....


Noch zu dem Punkt mit der Checkbox: Man muss ja nicht explizit abfragen, ob die CheckBox gesetzt ist oder nicht. Man muss ja nicht wissen, dass es eine CheckBox gibt. Man muss nur dafür sorgen, dass die Funktionalität sich ändert, wenn man die CheckBox anklickt. Man kann also z.B. auch einen anonymen ActionListener an die Checkbox hängen, der - in Anlehung an das oben gepostete - den "FirstEntrySelector" vom ListModel entfernt oder hinzufügt, oder ihn mit einem Flag ein- oder ausschaltet.... Es gibt immer viele Möglichkeiten.
 

hdi

Top Contributor
Gut danke! Ich muss mich noch länger damit beschäftigen weil ich noch nich ganz raushab was bei dir da abgeht... Mich verwirren grad die verschiedenen Listener, da gibt's soviel bei dir ;) Ich muss da erstmal rausfinden was jetzt hier was ist. Verstehe nicht ganz wie das gemacht ist, ich kann doch zB alle Dinge die passieren sollen (autoscroll, letztes element markieren) einfach in die logDataAdded() Methode der Console reinklatschen, oder nicht?

Naja ka ich meld mich wieder wenn ich da durchgestiegen bin und noch immer ein Problem habe. danke :toll:
 

Marco13

Top Contributor
ich kann doch zB alle Dinge die passieren sollen (autoscroll, letztes element markieren) einfach in die logDataAdded() Methode der Console reinklatschen, oder nicht?

Ja, sicher. Und eins davon hatte ich im geposteten Code ja auch gemacht. Es ging nicht zuletzt darum, dass man manche Referenzen/Instanzvariablen eben nicht unbedingt braucht....
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Frage zum UML Design Java Basics - Anfänger-Themen 1
B Frage zu Datenbank Design - Rechnungen, Angebote... und deren Positionen Java Basics - Anfänger-Themen 4
D Besseres Design Frage Java Basics - Anfänger-Themen 1
J MVC- Design Frage Java Basics - Anfänger-Themen 3
B OOP Frage zu Klassen Design Java Basics - Anfänger-Themen 5
hdi Kleine Design/Convention Frage zu Konstruktoren Java Basics - Anfänger-Themen 4
M Java Design Frage Java Basics - Anfänger-Themen 2
S Frage zum Design der Vererbung (Kartendeck und Dupletten) Java Basics - Anfänger-Themen 12
S Design Frage Java Basics - Anfänger-Themen 5
D was ist der vorteil vom Builder-design pattern? Java Basics - Anfänger-Themen 11
N BMI Rechner Was haltet ihr von dem Code habt ihr Verbesserungsvorschläge weil design teschnisch ist das nicht das geilste würde das gerne überarbeiten Java Basics - Anfänger-Themen 12
F Design pattern Java Basics - Anfänger-Themen 29
N design time vs build time vs compile time Java Basics - Anfänger-Themen 2
H Eclipse , Design-Modus, unvollständige Darstellung Java Basics - Anfänger-Themen 0
M LookandFeel Design Java Basics - Anfänger-Themen 4
D Design Pattern Command Java Basics - Anfänger-Themen 3
M Erste Schritte Eclipse + design view Java Basics - Anfänger-Themen 3
J Design Patterns Java Basics - Anfänger-Themen 8
Tarrew Proxy Design-Pattern Java Basics - Anfänger-Themen 1
N Was bedeutet "Implementierung vor dem Client verbergen" bei Design Patterns? Java Basics - Anfänger-Themen 2
C Java Klassen Design? Java Basics - Anfänger-Themen 5
OnDemand Software-Design Java Basics - Anfänger-Themen 1
S Je nach erhaltene Daten unterschiedlich reagieren (Design Pattern?) Java Basics - Anfänger-Themen 3
B Warum haben Java Programme ein anderes Design? Java Basics - Anfänger-Themen 5
S Singleton (Design Patterns) Java Basics - Anfänger-Themen 16
A Design Pattern - Welche? Java Basics - Anfänger-Themen 33
Rudolf OOP Übungen zu Design Pattern in Java Java Basics - Anfänger-Themen 6
K Interface als Instanzvariable = gutes Design Java Basics - Anfänger-Themen 6
S Eclipse Design-Reiter fehlt Java Basics - Anfänger-Themen 6
D Design-Tipps für neues Programm (Excel-Charts-...) Java Basics - Anfänger-Themen 3
M Button mit eigenem Design Java Basics - Anfänger-Themen 6
R Welches Design pattern Java Basics - Anfänger-Themen 10
S Gutes Design mit statischen oder Member-Methoden Java Basics - Anfänger-Themen 53
X Externer GUI Code verwenden / (Design Ansicht) Java Basics - Anfänger-Themen 3
Hamstinator Design und Listener in verschiedenen Klassen Java Basics - Anfänger-Themen 6
J Methoden design Java Basics - Anfänger-Themen 3
hdi Design-Problem Java Basics - Anfänger-Themen 2
Q Listen - DefaultListModel trotz Design ueber GUI? Java Basics - Anfänger-Themen 10
B Java-Anwendung im Windows Design Java Basics - Anfänger-Themen 8
M code design Java Basics - Anfänger-Themen 14
M log4j design Java Basics - Anfänger-Themen 11
D Design Fragen Java Basics - Anfänger-Themen 5
M Design: Abfrage auf korrekte Eingabe Java Basics - Anfänger-Themen 4
W Design Problem Java Basics - Anfänger-Themen 7
T Wie wichtig ist Design Patterns in einer Firma? Java Basics - Anfänger-Themen 8
S log4j "Richtiges" Design Java Basics - Anfänger-Themen 4
D JButton - Design ändern Java Basics - Anfänger-Themen 8
Zrebna Frage zu Test-Driven Development (TDD) Java Basics - Anfänger-Themen 3
I Frage Thymeleaf -> Fehler ignorieren und mit "" ersetzen? Java Basics - Anfänger-Themen 15
I Frage Thymeleaf -> Prefix / Suffix ändern? Java Basics - Anfänger-Themen 11
D Rekursions Probleme / frage Java Basics - Anfänger-Themen 4
T Frage zu Parse Java Basics - Anfänger-Themen 2
H Frage an die Profis Java Basics - Anfänger-Themen 4
J Eine konzeptionelle Frage zu OOP Java Basics - Anfänger-Themen 3
P Frage zu Rekursion und Backtracking Java Basics - Anfänger-Themen 2
H Frage zur Ausgabe Java Basics - Anfänger-Themen 4
H Frage zu arithmetischen Operationen Java Basics - Anfänger-Themen 20
F Kurze Frage zu replace() Java Basics - Anfänger-Themen 19
JavaSchmecktLecker Polymorphie Frage zur Methodenüberschreibung Java Basics - Anfänger-Themen 21
J Frage zu einem "Taschenrechner" code Java Basics - Anfänger-Themen 9
B Erste Schritte Frage zu Instanzierung und Referenzen Java Basics - Anfänger-Themen 8
DoubleM Runtime.getRuntime().exec Frage Java Basics - Anfänger-Themen 2
J Eine theoretische Frage zur Praxis - JPanel oder Canvas Java Basics - Anfänger-Themen 5
O Frage: Formaler Typbezeichner? Java Basics - Anfänger-Themen 3
I BlueJ Queue Frage für Klausur Java Basics - Anfänger-Themen 2
N Verständnis Frage zu Variablen Java Basics - Anfänger-Themen 3
N Spezielle frage zum Comparator Java Basics - Anfänger-Themen 6
L Frage zum Array Java Basics - Anfänger-Themen 1
I Hilfe bei Klausur Frage Java Basics - Anfänger-Themen 8
izoards Drucken Frage zu FAQ Beitrag Java Basics - Anfänger-Themen 2
J Frage zu meinem Code (OOP) Java Basics - Anfänger-Themen 4
sserio Split() -> Regex Frage. Java Basics - Anfänger-Themen 7
A OCA Study Guide: 2. Frage aus Kapitel 3 Java Basics - Anfänger-Themen 9
sserio Date Library Frage Java Basics - Anfänger-Themen 9
Max246Sch Frage zu Währungsrechner Code Java Basics - Anfänger-Themen 2
sserio Frage zu HashMaps Java Basics - Anfänger-Themen 20
sserio Frage zu Threading - Multithreading Java Basics - Anfänger-Themen 2
sserio Frage zu Lambda Ausdrücken Java Basics - Anfänger-Themen 7
sserio Frage zu BigInteger Java Basics - Anfänger-Themen 1
D Frage bzgl. Enum-Handhabung Java Basics - Anfänger-Themen 16
xxx12 Frage Java Basics - Anfänger-Themen 2
I Generelle Frage zu Mikroservices (Spring Boot?), Docker... Java Basics - Anfänger-Themen 7
R Frage zu Methoden (Rückgabewert u. ohne.) Java Basics - Anfänger-Themen 2
A Frage zur programmierung Java Basics - Anfänger-Themen 12
M Frage zur Methode split der Klasse String Java Basics - Anfänger-Themen 32
R Input/Output Frage zu Java IO Java Basics - Anfänger-Themen 6
M Frage zu printWriter Java Basics - Anfänger-Themen 5
C Frage zu OLSMultipleLinearRegression Java Basics - Anfänger-Themen 31
KogoroMori21 Frage zum Euklidischen Algorithmus Java Basics - Anfänger-Themen 11
S Verständnis-Frage zu einer HÜ? Java Basics - Anfänger-Themen 1
F Frage betreff Programm mit dem man C++-Code in JAVA-Code übersetzen lassen kann Java Basics - Anfänger-Themen 2
L Frage zur Ticket Maschine Java Basics - Anfänger-Themen 1
J Frage zu OOP-Klassendiagramm Java Basics - Anfänger-Themen 8
OSchriever Frage zu Compiler Java Basics - Anfänger-Themen 8
H Frage zu Throw Exception Java Basics - Anfänger-Themen 2
TimoN11 Frage zu Java-Vererbung (Cast) Java Basics - Anfänger-Themen 5
Bademeister007 Hallo Leute ich hab eine Frage zur ArrayList Java Basics - Anfänger-Themen 8
F Frage betreff Programmierbücher zu Lagerverwaltung als Konsolenprogramm Java Basics - Anfänger-Themen 3
dieter000 Kurze Frage kann mir ejmand kurz diesen Code erklären, bzw wie man die zeilen erklärt und so Java Basics - Anfänger-Themen 1
I String.split regex Frage Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben