vererbung mit swing?

  • Themenstarter Themenstarter Gast
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Gast

Gast
Bin gerade bissel aufm Schlauch. Wenn ich die Panels nicht über eine extra klasse lade, sonder direkt in der klasse, wo ich auch das fenster habe dann gehts. Wenn ich aber eine klasse mir baue, wo ich diese erstellen will(weil werden verdammt viele) dann gehts nicht. Also das Panel wechselt einfach nicht wenn ich auf denn button klicke...

Code:
package jFRame;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test extends JFrame implements KeyListener{
	boolean run;
	JLabel l;
	JPanel j;
	int x=0;
	int y=0;
	
	public Test(){
		this.setSize(500+4, 500+34);
		this.setTitle("Test");
		//this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.addKeyListener(this);
		this.setFocusable(true);
		//this.add(m.start());
		this.run=false;
	}
	
	public void chancepanels(int x){
		MakeP m=new MakeP();
		if(x==0){
			this.getContentPane().removeAll();
		    this.getContentPane().add(m.start());
		    this.getContentPane().validate();
		}
		if(x==1){
			this.getContentPane().removeAll();
		    this.getContentPane().add(m.nummer1());
		    this.getContentPane().validate();
		}
	}
	
	

	public void keyReleased(KeyEvent ke){
	}
	public void keyTyped(KeyEvent ke){
	}
	public void keyPressed(KeyEvent ke){
		int key = ke.getKeyCode();
		if(run){
		if(x<450){
			System.out.println("taste");
		x=x+50;
		//Animation ani=new Animation(this);
		//ani.start();
		ani();
		}
		}
	}
	public void ani(){
		for(int i=0;i<=50;i=i+10){
			l.setLocation(x-50+i,y);
		}
	}
	
	public static void main(String[] args) {
		Test f=new Test();
		f.chancepanels(0);
		f.setVisible(true);
	}
}

class MakeP extends Test{
	
	public JPanel start(){
		j= new JPanel();
		j.setLayout(null);
		j.setSize(500, 500);
		JLabel s=new JLabel(new ImageIcon("jFrame/bg.gif"));
		s.setSize(500, 500);
		s.setLocation(0, 0);
		JButton b1=new JButton(new ImageIcon("jFrame/button.gif"));
		b1.setSize(100, 25);
		b1.setLocation(50, 475);
		b1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				chancepanels(1);
				run=true;
			}
		});
		j.add(b1);
		j.add(s);
		
		return j;
	}
	
	public JPanel nummer1(){
		j= new JPanel();
		j.setLayout(null);
		j.setSize(500, 500);
		l=new JLabel(new ImageIcon("jFrame/fg.gif"));
		l.setSize(50, 50);
		l.setLocation(x, y);
		JLabel s=new JLabel(new ImageIcon("jFrame/bg.gif"));
		s.setSize(500, 500);
		s.setLocation(0, 0);
		JButton b1=new JButton(new ImageIcon("jFrame/button.gif"));
		b1.setSize(100, 25);
		b1.setLocation(150, 475);
		b1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
					chancepanels(0);
					run=false;
				}
		});
		j.add(b1);
		j.add(l);
		j.add(s);
		
		return j;
	}	
}
 
Es gibt in deinem Programm mehrere Test-Objekte, und du rufst die Methode "chancepanels" beim Falschen auf.
:arrow: Stelle sicher, dass du nur ein Test-Objekt hast: erstelle nie mehr als eines.
Eine Lösung die nur wenig am Code verändert (alle Veränderungen sind mit einem // <------- markiert):
Code:
package jFRame;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public abstract class Test extends JFrame implements KeyListener{ // <-------
   boolean run;
   JLabel l;
   JPanel j;
   int x=0;
   int y=0;
   
   public Test(){
      this.setSize(500+4, 500+34);
      this.setTitle("Test");
      //this.setResizable(false);
      this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      this.addKeyListener(this);
      this.setFocusable(true);
      //this.add(m.start());
      this.run=false;
   }
   
   public void chancepanels(int x){
      if(x==0){
         this.getContentPane().removeAll();
          this.getContentPane().add(start()); // <-------
          this.getContentPane().validate();
      }
      if(x==1){
         this.getContentPane().removeAll();
          this.getContentPane().add(nummer1()); // <-------
          this.getContentPane().validate();
      }
   }
   
   

   public void keyReleased(KeyEvent ke){
   }
   public void keyTyped(KeyEvent ke){
   }
   public void keyPressed(KeyEvent ke){
      int key = ke.getKeyCode();
      if(run){
      if(x<450){
         System.out.println("taste");
      x=x+50;
      //Animation ani=new Animation(this);
      //ani.start();
      ani();
      }
      }
   }
   public void ani(){
      for(int i=0;i<=50;i=i+10){
         l.setLocation(x-50+i,y);
      }
   }
   
   public static void main(String[] args) {
      Test f=new MakeP(); // <-------
      f.chancepanels(0);
      f.setVisible(true);
   }
   
   protected abstract JPanel start(); // <-------
   protected abstract JPanel nummer1(); // <-------
}

class MakeP extends Test{
   @Override // <-------
   public JPanel start(){
      j= new JPanel();
      j.setLayout(null);
      j.setSize(500, 500);
      JLabel s=new JLabel(new ImageIcon("jFrame/bg.gif"));
      s.setSize(500, 500);
      s.setLocation(0, 0);
      JButton b1=new JButton(new ImageIcon("jFrame/button.gif"));
      b1.setSize(100, 25);
      b1.setLocation(50, 475);
      b1.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent evt) {
            chancepanels(1);
            run=true;
         }
      });
      j.add(b1);
      j.add(s);
      
      return j;
   }
   
   @Override // <-------
   public JPanel nummer1(){
      j= new JPanel();
      j.setLayout(null);
      j.setSize(500, 500);
      l=new JLabel(new ImageIcon("jFrame/fg.gif"));
      l.setSize(50, 50);
      l.setLocation(x, y);
      JLabel s=new JLabel(new ImageIcon("jFrame/bg.gif"));
      s.setSize(500, 500);
      s.setLocation(0, 0);
      JButton b1=new JButton(new ImageIcon("jFrame/button.gif"));
      b1.setSize(100, 25);
      b1.setLocation(150, 475);
      b1.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent evt) {
               chancepanels(0);
               run=false;
            }
      });
      j.add(b1);
      j.add(l);
      j.add(s);
      
      return j;
   }   
}

Schöner (und im Endeffekt auch übersichtlicher) wäre es, wenn du eine Klasse "StartPanel", "Nummer1Panel", "EtcPanel..." hast, und dann jeweils direkt ein "contentPane.add( new StartPanel() )" machst.
 
Aber wie soll das gehen, mit denn vielen Klassen? Es gibt so viele Variablen, die die klassen benutzen müssen und diese verändern. Dann muss ich jeder Klasse ja diese übergeben?
 
Oder hast du noch andere Vorschläge? Also ich schildere dir mal mein Problem.

Es soll ein Rollenspiel werden, da müssen natürlich viele dinge geändert werden, z.b. Spieler, Gegner usw...also sehr viele Dinge.

Die Panels sind immer nur die Oberflächen wo z.b. Verkauf/Kaufen-Buttons drauf sind, oder Labels die die "Oberfläche" darstellen.

Es gibt z.b. viele "Landschaften" auf dennen immer Buttons auf den NPC's (Spielfiguren ...) drauf sind um diese anzusprechen. Nun werden das ~130 Landschaften, jeder NPC hat noch eigens Verkaufen etc Panel...werden halt unzählig viele. Kann man das irgendie vereinfachen und ist deine Idee da noch sinnvoll? Vorallem das über die Buttons die "Spielinhalte" verändert werden und somit immer auf ein "zentrales Objekt" zugreifen müssen.
 
Im Moment hast du eine riesen-Klasse, wo irgendwelcher trashiger Quäl-Kot drinsteht (Member-Variablennamen, die nur aus einen Buchstaben bestehen sind .... :autsch: )

Wenn du ein Programm mit vielen Funktionen schreiben willst, wirst du dich damit abfinden müssen, viel schreiben zu müssen. Man kann sich viel Arbeit sparen, wenn man die geeigneten Teile rausfaktorisiert und in eine abstrakte Oberklasse packt. Aber im Moment sieht das, was du da geschrieben hast, ein bißchen nach eine Systematik aus, die ... ja, zwar kreativ ist, aber ... das im negativsten Sinn.

class PanelWithLabel extends JPanel { JLabel x; }
class PanelWithLabelAndButton extends PanelWithLabel { JButton y; }
class PanelWithThreeLabelsAndTwoButtons extends PanelWithButton { JLabel a; JLabel b; JButton c; }
...
:autsch:

Man zieht normalerweise die Dinge in eine (abstrakte) Oberklasse Klasse, die die Klassen "natürlicherweise" gemeinsam haben - und nicht die Dinge, die man mit irgendwelchen Krämpfen "zu Gemeinsamkeiten machen kann".

Mach' dir erstmal über die Klassenstruktur gedanken. D.h. schalt den Computer aus, ( :shock: halt, erst den Beitrag hier fertig lesen! :shock: :wink: ), und denk dann eine Weile nach, was in deinem Spiel alles vorkommen soll. Welche Klassen von Objekten benötigt werden. Und wie die Objekte interagieren sollen. Dann überleg' dir, welche Methoden die Klassen anbieten müssen, damit sie alles machen können, was sie machen können sollen. Dann nimmst du Bleistift und Papier, und malst dir für jede Klasse ein Kästchen auf, und Linien zwischen den Kästchen, wenn die Klassen einander kennen müssen. Dann denk nochmal über das ganze nach. Und nochmal. Und nochmal. Und dann fang an, es in groben Zügen anzuimplementieren. D.h. alle Methoden sind erstmal leer oder geben 'null' zurück, und schau, ob das wirklich übehaupt so funktionieren KÖNNTE, wie du es dir gedacht hast.

Da ich nicht weiß, was du machen willst, habe ich alle Schritte (bis auf den letzten) jetzt mal überprungen :wink: aber da wird dann vielleicht ungefähr sowas änliches rauskommen wie sowas
Code:
class GameController
{
    List players;
    List gameMaps;

    TradePanel tradePanel;
    FightPanel fightPanel;
    ....
}

class Player
{
    int strength;
    int health;

    int gold;

    List items;
    Weapon weapon;

    public tradeWith(Player other);
    public fightWith(Player other);
    public void setActiveWeapon(Weapon weapon);
}

class HumanPlayer extends Player {...}
class ComputerPlayer extends Player { ... }

class Item 
{
    int price;
    int weight;
    int space;
}

class Weapon extends Item
{
     int damage;
}

class GameMap
{
     List players;

     Image mapBackground;

     public void paintMap(Graphics g)
}

class TradePanel extends JPanel
{
    void trade(Player player0, Player player1)
    {
          createList(player0.getInventory());
          createList(player1.getInventory());
    }

    void createList(Inventory inventory)
    {  
          for (all items in inventory)
          {
               addLabelDescribing(item);
               createButtonThatCausesTransfer(item);
          }
    }

    void transfer(Item item, Player fromPlayer, Player toPlayer)
    {
         if (agreesToTrade(fromPlayer) && agreesToTrade(toPlayer))
         {
              ...
         }
    }
}

Der Zugriff auf ein "Zentrales Objekt" klingt nicht soo toll. Über die Buttons werden ja nur winzig kleine Teile des Spiels verändert. Wenn man z.B. ein "TradePanel" für zwei Player aufmacht, und sie sich dann über einen Handel einig werden, dann klickt man den "Trade-Button" - und der hat mit der Hauptklasse oder den Maps nichts zu tun: Er sorgt nur dafür, dass ein "Item" von Player0 zu Player1 transferiert wird, und Gold von Player1 zu player0. Dann evtl. noch das TradePanel aktualisieren, und gut ist.

Zu der Frage, wo dort Vererbung ins Spiel kommt: Z.B. hab ich mir ja oben was von einem TradePanel und einen FightPanel aus den Fingern genuckelt. Die KÖNNTEN einige Gemeinsamkeiten haben: Beide zeigen Informationen zu den beiden Spielern an. Vielleicht zeigen auch Beide das Inventar (und die aktuelle Waffe) an. Dann könnte man dort eine abstrakte Oberklasse machen
Code:
abstract class TwoPlayerPanel 
{
    void init(Player player0, Player player1)
    {
          createPlayerInfo(player0);
          createList(player0.getInventory());
          createPlayerInfo(player1);
          createList(player1.getInventory());
          createControlPanel();
    }
    abstract void createControlPanel();
}
Die Methode "createControlPanel" ist dann abstrakt, und ist im "TradePanel" anders implementiert, als im "FightPanel":
Code:
class TradePanel extends TwoPlayerPanel 
{
     void createControlPanel()
     {
         createTradeButton();
     }
}
class FightPanel extends TwoPlayerPanel 
{
     void createControlPanel()
     {
         createFightButton();
     }
}
(sehr schwammig, und vielleicht ist diese Oberklasse hier garnicht so sinnvoll, aber es wird hoffentlich deutlich, was gemeint ist)

Aber wie gesagt: WIE die Sturkur der Klassen sein soll, und WAS dort WANN passieren soll, ist eben das, worüber du dir Gedanken machen solltest, bevor du dich fragst, ob irgendein Label nun 50 oder 55 Pixel breit sein sollte oder so :roll:

So. Jetzt: Ausschalten :wink:
 
Oder hast du noch andere Vorschläge?
Ich kann nicht mehr viel nach Marco13's Beitrag sagen...

Ein oft erprobter und erfolgreicher Weg ist es, solch ein grosses Programm aufzuteilen:

Ein Model das alle Daten zum Spiel enthält (z.B. ein Rucksack eines Spielers), eine View die einzelne Aspekte darstellen kann (z.B. eine Tabelle die den Inhalt eines Rucksackes auflistet) und ein Controller der Model und View verknüpft (und z.B. dafür sorgt, dass alle Sekunden die Position der NPCs neu berechnet wird).
Also typische Klassen des Models wären "Spieler", "Rucksack", "Waffe", "Welt"; und typische Dinge der View wären "RucksackTabelle", "SpielerOptionen", "WaffenDetails", "WeltAnsicht", ...

Es gibt so viele Variablen, die die klassen benutzen müssen und diese verändern. Dann muss ich jeder Klasse ja diese übergeben?
Das "WaffenDetail"-Panel interessiert sich nicht für den Apfelbaum auf der anderen Seite der Welt. Es interessiert sich für genau eine Waffe, und nur diese eine Referenz auf ein Waffen-Objekt musst du ihm übergeben.

jeder NPC hat noch eigens Verkaufen etc Panel
Jein, jeder NPC verkauft was anderes, aber eigentlich können alle dasselbe Panel benutzen (oder zumindest dieselbe Panel-Klasse).

:arrow: Schlussendlich will ich sagen, dass du die Komplexität hinter mehreren Schichten "verstecken" solltest:
- Baue deine Klassen "lokal", so dass sie möglichst wenig von ihrer Umgebung wissen müssen.
- Verteile nie mehr Informationen als notwendig.
- Bau ein Model das falsche Daten (jemandem 3 Waffen in die Hände drücken) nicht zulässt.
- Du kannst "Knoten" im Programm haben, die einen grösseren Überblick haben. Z.B. ein Objekt welches weiss, welche Panels existieren und wann man sie öffnen kann.
- Versuch Klassen wiederzuverwerten (das Verkaufs-Panel)

Und da ich nicht ganz unerfahren bin: lieber eine Klasse, Interface oder Abstraktion zuviel als zuwenig :wink:
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben