eigene GUI Bibliothek erstellen.

MJannek

Bekanntes Mitglied
Ich möchte mir eine gemeinsame Oberklasse für alle Elemente eines GUI in Java schreiben.
Java:
package javaext.gui;

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

import javax.swing.*;

public class GuiElement extends JComponent {
    // Gemeinsame Attribute für GUI-Elemente
    protected String text;
    protected int x;
    protected int y;
    protected int width;
    protected int height;

    // Konstruktor
    public GuiElement() {
        setPreferredSize(new Dimension(100, 100));
    }
    public GuiElement(String text){
        this.text = text;
    }

    // Methode zum Setzen des Textes
    public void setText(String text) {
        this.text = text;
        repaint();
    }

    // Methode zum Zeichnen des GUI-Elements (Standardimplementierung)
    protected void draw(Graphics g) {
        // Hier könnte die Standardzeichnung erfolgen, z.B. Hintergrundfarbe setzen
    }

    // Methode zum Behandeln von Ereignissen (Standardimplementierung)
    protected void handleEvent() {
        // Hier könnte die Standardereignisbehandlung erfolgen
    }

    // Überschreibbare Methode zum Zeichnen des GUI-Elements
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }

    // Überschreibbare Methode zur Behandlung von Ereignissen
    protected void processEvent() {
        handleEvent();
    }
    public void setBounds(int x, int y, int width, int height){
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        repaint();
    }
}

Diese Klasse soll dazu genutzt werden, um Dinge wie GUIFrame, GUIButton, GUILabel, GUIPanel etc. zu erstellen.
Ich möchte die J-Objekte wie JFrame, JButton, etc explizit nicht nutzen. Ich habe mir eine Klasse GUIFrame erstellt, weiß jetzt jedoch nicht, wie ich das weiter verarbeiten muss.
Java:
package javaext.gui;

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

public class GUIFrame extends GuiElement {
    private boolean resizable;
    private boolean closable;
    private boolean minimizable;

    public GUIFrame(String title, boolean resizable, boolean closable, boolean minimizable) {
        super(title);
        this.resizable = resizable;
        this.closable = closable;
        this.minimizable = minimizable;
        setupFrame();
    }

    private void setupFrame() {
        setDefaultCloseOperation();
        addWindowListener();
        setResizable();
        setUndecorated();
        pack();
        setVisible(true);
    }

    private void setDefaultCloseOperation() {
        if (closable) {
            addComponentListener(new ComponentAdapter() {
                public void componentHidden(ComponentEvent e) {
                    onClose();
                }
            });
        } else {
            setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        }
    }

    private void addWindowListener() {
        if (minimizable) {
            addWindowStateListener(new WindowAdapter() {
                @Override
                public void windowStateChanged(WindowEvent e) {
                    if (e.getNewState() == Frame.ICONIFIED) {
                        onMinimize();
                    }
                }
            });
        }
    }

    private void setResizable() {
        setPreferredSize(new Dimension(400, 300)); 
        setResizable(resizable);
    }

    private void setUndecorated() {
        if (!closable) {
            setUndecorated(true);
        }
    }

    private void onClose() {
        dispose();
        System.exit(0); 
    }

    private void onMinimize() {
        setState(Frame.ICONIFIED);
    }

    @Override
    protected void draw(Graphics g) {
        super.draw(g);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
        if (text != null) {
            FontMetrics fm = g.getFontMetrics();
            int textWidth = fm.stringWidth(text);
            int x = (getWidth() - textWidth) / 2;
            int y = fm.getHeight();
            g.drawString(text, x, y);
        }
    }

    @Override
    protected void handleEvent() {
        super.handleEvent();
   
    }

    public static void main(String[] args) {
 
        GUIFrame frame = new GUIFrame("Resizable, Closable, Minimizable Frame", true, true, true);
    }
}
Außerdem habe ich eine Klasse GUIButton.
Java:
package javaext.gui;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GuiButton extends GuiElement {
    // Konstruktor
    public GuiButton(String text) {
        super(text);
        // Füge einen ActionListener hinzu, um auf Klicks zu reagieren
        addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // Hier kannst du die Aktion für den Button definieren
                System.out.println("Button geklickt");
            }
        });
    }

    // Überschreibe die draw-Methode für die spezifische Darstellung des Buttons
    @Override
    protected void draw(Graphics g) {
        super.draw(g);
        g.setColor(Color.BLUE);
        g.fillRect(0, 0, width, height);
        g.setColor(Color.WHITE);
        g.drawString(text, 10, 20);
    }
}
Ich möchte wissen, wie ich die Klasse GUIframe verändern muss, um GuiButton hinzufügen kann und das Fenster sichtbar machen zu können
 
Orientiere Dich doch erst mal an dem, was bereits existiert. Wenn Du Dir Swing anschaust, dann siehst Du diese Vererbungsketten

JFrame - Frame - Window - Container - Component - Object
JComponent - Container - Component - Object

Wenn Du jetzt also die Funktionalität eines Fensters brauchst, dann kannst Du Dir die Klassen Window, Frame und JFrame ansehen und dann siehst Du, was da so alles an Funktionalität eingeflossen ist.

Aber die Frage ist erst einmal, was Du genau erreichen willst.

Derzeit setzt Du ja schon bereits auf swing (JComponent im speziellen) - was hindert Dich daran, nicht auch auf andere Swing Klassen zu setzen wie z.B. JFrame? Je nach gewünschter Basis reicht diese Grundlage aber auch nicht. Dann wäre eine Grundlage wie z.B. eine native UI Library denkbar, auf der man dann aufbaut.

Hier wäre also hilfreich, wenn Du Details zu Deinen Vorstellungen bezüglich der GUI Bibliothek teilen würdest.
 
Wenn du bei nahezu Null anfangen willst, dann stehst du vor folgender Entscheidung: Duerfen Komponenten beliebigen Komponenten hinzugefuegt werden, oder nur bestimmten Containern? Ersteres ist zum Beispiel Swing, zweiteres ist JavaFX. Du brauchst aber auf jeden Fall mal einen Container in den du die Komponenten einhaengen kannst. Ich wuerde eine solche Struktur vorschlagen fuer den Anfang:

Java:
public class GuiEleent extends SomethingThatCanDrawStuffForExampleJComponent { }

public class GuiContainer extends GuiElement {
    public void add(GuiElement child);
    public void remove(GuiElement child);
    // TODO More methods for accessing/changing children.
}

Dann kannst du Komponenten in einen Container einhaengen (und Container in einen Container) und kannst einen Baum aus Komponenten bauen. Damit hast du daber nur die halbe Miete geschafft, denn jetzt kommt das schwierige: Layout. Auch hier gibt es wieder zwei Ansaetze, naemlich den von "LayoutManagern" (Swing) und dedizierten Containern (JavaFX). Ich persoenlich mag "LayoutManager" mehr, aber das ist meine persoenliche Meinung.

So oder so brauchst du etwas was bestimmt wie die Kinder in einem Container ausgerichtet und angeordnet werden. Das ist dann der Schritt nachdem du einen Container implementiert hast welcher mehrere Kinder halten kann. Also darueber hinaus ist in irgendeiner Form verwandt mit diesen beiden Entscheidungen.

Klassische Layouts sind zum Beispiel:

* Border (Oben/Unten/Links/Rechts/Mitte)
* Flow (Horizontal/Vertikal angeordnete Kinder)
* Grid (Raster)

Darueber hinaus gibt es viele unterschiedliche Ansaetze, einen der besseren finde ich immernoch das JVx FormLayout, welches ein Anker-basierendes Layout bereitstellt.

Um auf deine Frage zum Fenster zurueck zu kommen, dein GuiFrame muss sich dann eben von GuiContainer ableiten damit er alle Methoden bekommt um Kinder zu halten. Dann erzeugst du darin dein "natives" Fenster (JFrame) und zeichnest in das, oder laesst eben zeichnen.

Auch an dieser Stelle sollte ich mal das Bridge Pattern erwaehnen um "native" Komponenten zu kapseln. Aber das wuerde dann spaeter kommen, denke ich.

Auszerdem ist im Moment deine Struktur etwas vermischt, GuiElement erbt von JComponent, aber GuiFrame nicht von JFrame. Das koennte spaeter mal haesslich werden. Nicht jetzt direkt zu loesen, aber sollte man im Hinterkopf behalten dass man das irgendwie vereinheitlicht (zum Beispiel in dem man die "native" Komponente immer als Feld halt).
 
Orientiere Dich doch erst mal an dem, was bereits existiert. Wenn Du Dir Swing anschaust, dann siehst Du diese Vererbungsketten

JFrame - Frame - Window - Container - Component - Object
JComponent - Container - Component - Object

Wenn Du jetzt also die Funktionalität eines Fensters brauchst, dann kannst Du Dir die Klassen Window, Frame und JFrame ansehen und dann siehst Du, was da so alles an Funktionalität eingeflossen ist.

Aber die Frage ist erst einmal, was Du genau erreichen willst.

Derzeit setzt Du ja schon bereits auf swing (JComponent im speziellen) - was hindert Dich daran, nicht auch auf andere Swing Klassen zu setzen wie z.B. JFrame? Je nach gewünschter Basis reicht diese Grundlage aber auch nicht. Dann wäre eine Grundlage wie z.B. eine native UI Library denkbar, auf der man dann aufbaut.

Hier wäre also hilfreich, wenn Du Details zu Deinen Vorstellungen bezüglich der GUI Bibliothek teilen würdest.
Ich möchte allen GUI Komponenten gemeinsame neue einheitliche Methoden hinzufügen, möchte sie möglichst nur einmal implementieren und kein Interface bzw. default im Interface verwenden
 
Ich möchte allen GUI Komponenten gemeinsame neue einheitliche Methoden hinzufügen, möchte sie möglichst nur einmal implementieren und kein Interface bzw. default im Interface verwenden
Da solltest Du Dir neben Inheritance auch noch andere Entwurfsmuster ansehen wie z.B. das Strategy Pattern. Das kann dann helfen.

Und wenn auf etwas bestehendem aufbauen willst (Wie in dem bisherigen Code), dann hast Du natürlich das generelle Problem, wenn Du. bereits zu spezifisch bist (Bei Dir mit dem JComponent). Hier bräuchtest Du halt Funktionalitäten von Window/Frame/JFrame und da es keine Multiple Inheritance bei Klassen gibt, hast Du hier dann gewisse Probleme. Aber prinzipiell könntest du z.B. in Deinem GUIFrame dann per Composition ein JFrame hinzu fügen. Aber ich sehe hier keinen Mehrwert.

Wozu brauchst Du ein GUIElement? Wenn Du ein spezifisches Verhalten implementiert haben willst, dann kannst Du dieses in einer eigenen Klasse (oder eben auch mehrerer) implementieren. Die Methoden, die nach außen wichtig sind, können in einem Interface sein und dann erben die Klassen immer von der Swing Klasse, die halt erweitert wird:
public class GUIWindow extends JFrame implements GUIElement
public class GUIButton extends JButton implements GUIElement
u.s.w.

Default Methoden sind dann natürlich denkbar, aber in erster Linie wäre die Funktionalität in eigenen Klassen a.la. Strategy Pattern.

Das ist nur eine Idee - ohne genaue Informationen, was Du überhaupt erreichen willst, ist halt kein konkretes Design möglich.
 
Ich möchte allen GUI Komponenten gemeinsame neue einheitliche Methoden hinzufügen, möchte sie möglichst nur einmal implementieren und kein Interface bzw. default im Interface verwenden
Wobei der Gebrauch von Vererbungshierarchien für Code-Reuse wohl überlegt sein sollte, gerade wenns eine Bibliothek werden soll, von der wiederum abgeleitet werden kann/soll. Ich bin da im Sinne der Wartbarkeit eher Anhänger des "favor composition over inheritance"-Prinzips, bzw. nutze für das wiederverwandbare Hinzufügen von Funktionaliät auch ganz gerne mal Traits, wenn es sich als sinnvoll anbietet (in Java typischerweise über Default-Methoden in Interfaces).
 
Ich möchte allen GUI Komponenten gemeinsame neue einheitliche Methoden hinzufügen, möchte sie möglichst nur einmal implementieren und kein Interface bzw. default im Interface verwenden
Dann würde ich dir eher raten, eine bestehende GUI-Bibliothek nach deinen Wünschen zu erweitern.
Swing ist da sehr handlich, und wenn du sowieso schon mit Swing arbeitest, bleib doch dabei. Ich habe mir für Swing mal eine eigene Textbox geschrieben. Ich wollte, daß eine Textbox nie komplett leer ist, sondern einen definierten String mit einer bestimmten Formatierung enthält. Also das z.B. "Vorname" in Schrägschrift in der eigentlich leeren Box angezeigt wird, damit der Benutzer weiß daß er da seinen Vornamen eingeben soll. War recht simpel. In JavaFX geht sowas auch, aber da hat man deutlich weniger Freiheiten.

Es wäre schön, wenn es in Java noch eine Alternative zu JavaFX geben würde, das wäre ein Traum. Ich denke allerdings, du unterschätzt den Aufwand für eine komplette GUI-Bibliothek fürchterlich. Du hast es einerseits mit ziemlich viel Low-Level-Kram zu tun, sehr viel Pixelrechnerei, und wirst da auf interessante Probleme stoßen. Das ganze Hintergrundgeraffel, Events verwalten, usw. kommt auch noch dazu.
Und dann soll es am Ende ja auch hoffentlich noch gut aussehen. Unterschätze die Arbeit von Designern nicht.

Ich denke, bevor du selber eine GUI entwickelst solltest du zwei oder drei GUI-Frameworks recht gut kennen und mal damit gearbeitet haben. Dann weißt du genug darüber wie andere es schonmal gemacht haben, in welche Fallen sie wahrscheinlich bereits getappt sind oder was sonst noch nicht optimal gelaufen ist. Du hast mehrere Denkanstöße und kennst mehrere Ideen sowie deren Vor- und Nachteile, und kannst auswählen, übernehmen, neu kombinieren oder verwerfen und was Neues einbringen.

Dein Thread zeigt, mit Verlaub, daß du da noch ziemlich grün zu sein scheinst. Das ist nicht schlimm, das waren die alten Meister auch alle mal, aber es wäre eben auch schade wenn du dich an ein Riesenprojekt machst bei dem du keine Chance hast es zufriedenstellend zu lösen.
Nur mal als Beispiel: Du hast jetzt eine Basisklasse geschrieben, weißt aber anscheinen noch nicht genau warum eigentlich. Warum sollte ein Button, den du später erstellst, von dieser Klasse ableiten, was hat er denn gemeinsam mit deinen anderen GUI-Elementen?
Interfaces scheinst du nicht zu mögen und willst sie vermeiden, ich versichere dir aber daß Interfaces ihre absolute Daseinsberechtigung haben und das sowohl die Macher von Swing als auch von JavaFX auf Interfaces verzichtet hätten, wenn sie nicht notwendig gewesen wären.

Das nur mal so als Denkanstoß.
 
Dann kannst du Komponenten in einen Container einhaengen (und Container in einen Container) und kannst einen Baum aus Komponenten bauen. Damit hast du daber nur die halbe Miete geschafft, denn jetzt kommt das schwierige: Layout. Auch hier gibt es wieder zwei Ansaetze, naemlich den von "LayoutManagern" (Swing) und dedizierten Containern (JavaFX).
Ach, da gibts noch mehr. ImGUI hat, zumindest soweit ich weiß, keine Container, und ob man das, was da die Elemente anordnet, als Layoutmanager bezeichnen kann, weiß ich auch nicht.

Klingt erstmal merkwürdig, aber ImGUI habe ich bisher am schnellsten verstanden. (Hab da aber auch schon mehr Erfahrung gehabt als ich das erste Mal mit Swing oder JavaFX gearbeitet habe).

@MJannek:
Eine Ergänzun noch: Es gibt für JavaFX eine Erweiterungsbibliothek, die sich controlsfx nennt. Die enthält einen Container zur tabellarischen Anordnung, sieht etwas wie in Excel aus.
Dieser Tabellencontainer (heißt übrigens spreadsheetview) alleine hat über 1.000 Codezeilen, und die wird er nicht umsonst haben. Das nur mal so als Vorwarnung, was da an Arbeit auf dich zukommt.
 
Es wäre schön, wenn es in Java noch eine Alternative zu JavaFX geben würde, das wäre ein Traum. Ich denke allerdings, du unterschätzt den Aufwand für eine komplette GUI-Bibliothek fürchterlich.
Ich weisz das ist jetzt nicht direkt was du meintest, aber tatsaechlich gibt es eine relativ gute Auswahl an GUI-Bibliotheken:

* Swing
* JavaFX
* SWT
* Pivot
* QtJambi

Ueber Java Native Access (JNA) kann man sich auch ganz einfach jede C-Bibliothek hineinzeihen. Und wenn du ganz, ganz, was anderes sehen und machen willst, die Godot-JVM Anbindung funktioniert echt gut und Godot stellt sehr viele Komponenten fuer die GUI Erstellung zur verfuegung.

Nicht zu vergessen das Swing eine lange Liste an Bibliotheken hat welche dafuer erstellt wurden. Ich haette eigentlich auch gerne ein schoenes, neues GUI-Framework fuer Java, aber JavaFX ist da leider in meinem Erwartungen etwas kurz geblieben, und Swing hat den Vorteil dass es in der Installation einfach mit dabei ist und damit kein Paket je Platform gebaut werden muss.

Eine Ergänzun noch: Es gibt für JavaFX eine Erweiterungsbibliothek, die sich controlsfx nennt. Die enthält einen Container zur tabellarischen Anordnung, sieht etwas wie in Excel aus.
Dieser Tabellencontainer (heißt übrigens spreadsheetview) alleine hat über 1.000 Codezeilen, und die wird er nicht umsonst haben. Das nur mal so als Vorwarnung, was da an Arbeit auf dich zukommt.
Sehr guter Punkt. Als Ergaenzung dazu: Die Idee dass GUI-Code jemals "wirklich schoen" wird kann man auch direkt knicken. Zu komplex, zu viele Sonderfaelle.

Dein Thread zeigt, mit Verlaub, daß du da noch ziemlich grün zu sein scheinst. Das ist nicht schlimm, das waren die alten Meister auch alle mal, aber es wäre eben auch schade wenn du dich an ein Riesenprojekt machst bei dem du keine Chance hast es zufriedenstellend zu lösen.
Als Lernerfarhung dennoch wertvoll, nur als Anmerkung.
 
QtJambi...ich glaube, das probiere ich als nächstes, danke für den Hinweis.

Auch wenn ich "Kannste einfach mit JNI einbinden" jetzt nicht unbedingt einfach nennen würde. ImGUI ist auch ein JNI-Biding aus C++. Einfach sah mir das aber nicht aus (das Binding, das Binding selber zu benutzen ging recht gut, auch wenn man da immer noch merkt daß da C++ drunter läuft).
 
Auch wenn ich "Kannste einfach mit JNI einbinden" jetzt nicht unbedingt einfach nennen würde. ImGUI ist auch ein JNI-Biding aus C++. Einfach sah mir das aber nicht aus (das Binding, das Binding selber zu benutzen ging recht gut, auch wenn man da immer noch merkt daß da C++ drunter läuft).
JN*A*, nicht JNI, anderes Ding das so funktioniert wie man sich das wuenschen wuerde.
 

Neue Themen


Zurück
Oben