getSize() - Echte Höhe bestimmen

Hallihallöle,

ich habe mich in letzter Zeit intensiv mit der Graphischen Oberfläche mit Canvas beschäftigt und bin auf eine Sache gestoßen, die mich ziemlich nervt.
Ich habe ein JFrame erschaffen, mein Fenster in welchem das Programm läuft und darauf ist ein Canvas, was 100% der Fläche einnimmt.
Nun möchte ich gerne genau die Mitte treffen, weil ich ausgehend von selbiger weiterarbeiten möchte.

Leider ist es mir nie möglich gewesen die Mitte zu finden, obwohl ich es immer genau eingegeben habe…
Meine Hauptklasse sieht so aus, man ignoriere mal das Zeuchs drumherum:


import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;

public class CafeMain {
	
	protected static String OS = System.getProperty("os.name").toLowerCase();
	protected static String spielname = "Café International";
	protected static String[] spielername = new String[2];
	protected static List<Gastkarte> gastkarten = new ArrayList<Gastkarte>();
	protected static List<Laenderkarte> laenderkarten = new ArrayList<Laenderkarte>();
	protected static int anzahlbarplaetze = 21;
	protected static int[] punktespieler = new int[2];
	protected static int spieler = 1;
	protected static List<Gastkarte> kartenspieler1 = new ArrayList<Gastkarte>();
	protected static List<Gastkarte> kartenspieler2 = new ArrayList<Gastkarte>();
	protected static String filepath = new File("").getAbsolutePath();
	protected static Canvas spielfeld = new Canvas() {
	    public void paint(Graphics stift) {
	      Spielfeld.zeichne(stift);
	    }
	};
	protected static List<Tisch> tische = new ArrayList<Tisch>(12);
	protected static List<Stuhl> stuehle = new ArrayList<Stuhl>(24);
	protected static boolean spielernamenkorrekt = false;
	protected static JFrame spielframe = new JFrame(spielname);
	protected static int frameWidth, frameHeight;
	
	public CafeMain() throws IOException {
		frameWidth = 600;
	    frameHeight = 600;
	    spielframe.setSize(frameWidth, frameHeight);
	    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
	    int x = (d.width - spielframe.getSize().width) / 2;
	    int y = (d.height - spielframe.getSize().height) / 2;
	    spielframe.setLocation(x, y);
	    spielframe.setResizable(false);
	    spielframe.setLocationRelativeTo(null);
	    spielframe.setVisible(false);
	    spielframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    // === Komponenten ===
	    Container cp = spielframe.getContentPane();
	    cp.setLayout(null);
	    spielfeld.setBounds(0, 0, spielframe.getWidth(), spielframe.getHeight());
	    cp.add(spielfeld);
	    // === Komponenten ===
	    ablauf();
	}
	
	public static void ablauf() {
		if(SysWin()) {
			JOptionPane.showMessageDialog(null, "Dein System ist hoffnungslos veraltet!
Windoof ist nicht kompatibel mit diesem Spiel.
Sollte es zu Problemen bei der Ausführung kommen,
dann öffne das Spiel bitte auf einem PC
mit Mac OS oder Linux!", "System veraltet", JOptionPane.WARNING_MESSAGE);
		}
		do{
		Spielstart.namensfrage();
		} while(spielernamenkorrekt == false);
		spielframe.setVisible(true);
		Spielstart.gastkartenmischen();
        Spielstart.laenderkartenmischen();
        Spielstart.spielfeldgenerieren();
	}

	public static void main(String[] args) throws IOException {
		new CafeMain();
	}
	
	public static boolean SysWin() {
		return (OS.indexOf("win") >= 0);
	}

}

dann später habe ich zur Kontrolle eine Linie in alle 4 Richtungen gezeichnet, die dann gleichmäßig verteilt nahe der Ecken ankommen muss:

	    stift.drawLine(frameWidth/2, frameHeight/2, (frameWidth/2)+k, (frameHeight/2)+k);
	    stift.drawLine(frameWidth/2, frameHeight/2, (frameWidth/2)-k, (frameHeight/2)+k);
	    stift.drawLine(frameWidth/2, frameHeight/2, (frameWidth/2)+k, (frameHeight/2)-k);
	    stift.drawLine(frameWidth/2, frameHeight/2, (frameWidth/2)-k, (frameHeight/2)-k);```

So sieht dann das Resultat aus:


Wie man sieht, ist die Mitte auf der y-Achse sehr unnötig verschoben.

Das liegt, wie ich es denke daran, dass das böse Java auch die Titelleiste des JFrames mit zur Größe hinzuzieht.

Kann mir jemand codetechnisch erläutern, wie ich das verhindere und ein bestmögliches Ergebnis erziele?


Vielen Dank
Lukas :)

Naja, soweit ich mich erinnere gehören die Dekorationen (Titelleiste) halt zu einem Frame. Folglich solltest du die Größenangaben nicht beim Frame erfragen sondern beim Canvas. Oder, noch besser, du bettest ersteinmal ein Panel in den Frame ein und malst dann auf diesem herum. Das Panel wird auf jeden Fall wissen wie groß es genau ist.

spielframe.getContentPane().getHeight()

Hallöle und Danke für eure Antworten,

wenn ich das hier probiere, dann ist mein komplettes Fenster leer. Ohne alles:
spielfeld.setBounds(0, 0, spielframe.getContentPane().getWidth(), spielframe.getContentPane().getHeight());

Naja, soweit ich mich erinnere gehören die Dekorationen (Titelleiste) halt zu einem Frame. Folglich solltest du die Größenangaben nicht beim Frame erfragen sondern beim Canvas. Oder, noch besser, du bettest ersteinmal ein Panel in den Frame ein und malst dann auf diesem herum. Das Panel wird auf jeden Fall wissen wie groß es genau ist.

Das Problem hierbei ist einfach, das Canvas soll 100% der Fläche einnehmen, die nicht zur Titelleiste gehört. Und ich kann nach wie vor selbiges nicht genau so auf dem JFrame positionieren, damit selbiges eintrifft, da ich nicht bestimmen kann, wie groß diese Leiste da oben ist.

Gruß
Lukas

Du könntest dem Frame ein GridLayout spendieren und ein Panel adden. Und dann eben auf dem Panel herumzeichen (oder das Canvas halt dem Panel hinzufügen, k.A., habe mich nie mit Canvases auseinandergesetzt). Alternative müsste man die Höhe der Titelleiste vom OS erfragen. Geht wahrscheinlich auch irgendwie, dürfte aber letztendlich auch keinen wirklichen Unterschied machen.

Hallöle,

hab mich nicht viel bzw. gar nicht mit GridLayout befasst und deshalb auch keine Ahnung davon. Ich werde mir das mal ansehen.
Aber in erster Linie bin ich an der Lösung interessiert, ob man irgendwo die Höhe dieser Titelleiste abfragen und dann entsprechend verrechnen kann.

Gruß
Lukas :slight_smile:

Ich sehe nicht warum du die Höhe der Titelleiste brauchst? Das funktioniert eigentlich relativ einfach so:

final JFrame frame = new JFrame("Canvas Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Canvas canvas = new Canvas() {
    @Override
    public void paint(Graphics g)
    {
        int height = frame.getContentPane().getHeight();
        int width = frame.getContentPane().getWidth();

        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);
    }
};

frame.add(canvas);
frame.setPreferredSize(new Dimension(200, 200));
frame.pack();
frame.setVisible(true);

Statt frame.getContentPane().getHeight() würde ich allerdings direkt die Größe des Canvas auslesen. Das dient nur als ein kleines Beispiel, dass die oben genannten Lösungen wunderbar passen. Was genau funktioniert denn da bei dir nicht?

Hallöle,
ich habe das jetzt so gelöst:

	protected static int height, width;
	protected static Canvas spielfeld = new Canvas() {
		@Override
		public void paint(Graphics stift) {
	      Spielfeld.zeichne(stift);
	      height = spielframe.getContentPane().getHeight();
	      width = spielframe.getContentPane().getWidth();
	        //stift.drawLine(0, 0, width, height);
	        //stift.drawLine(0, height, width, 0);
	        System.out.println(height);
	    }
	};```

Dann unten:
```public CafeMain() throws IOException {
		frameWidth = 600;
	    frameHeight = 600;
	    spielframe.setSize(frameWidth, frameHeight);
	    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
	    int x = (d.width - spielframe.getSize().width) / 2;
	    int y = (d.height - spielframe.getSize().height) / 2;
	    spielframe.setLocation(x, y);
	    spielframe.setResizable(false);
	    spielframe.setLocationRelativeTo(null);
	    spielframe.setVisible(false);
	    spielframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    // === Komponenten ===
	    Container cp = spielframe.getContentPane();
	    cp.setLayout(null);
	    spielfeld.setBounds(0, 0, frameWidth, frameHeight);
	    cp.add(spielfeld);
	    // === Komponenten ===
	    ablauf();
	}```

Und dann beim Zeichen der vier Linien:
```package spiel;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Spielfeld extends CafeMain {
	public Spielfeld() throws IOException {
		super();
	}

	public static void zeichne(Graphics stift) {
		int[] arrayx = new int[4];
		int[] arrayy = new int[4];
	    
	    arrayx[0] = 10;
	    arrayx[1] = 100;
	    arrayx[2] = 100;
	    arrayx[3] = 20;
	    arrayy[0] = 10;
	    arrayy[1] = 30;
	    arrayy[2] = 70;
	    arrayy[3] = 80;
	    stift.draw3DRect(10, 10, 100, 100, true);
	    stift.fillPolygon(arrayx, arrayy, 4);
	    int k = 290;
	    stift.drawLine(spielfeld.getWidth()/2, spielfeld.getHeight()/2, (spielfeld.getWidth()/2)+k, (spielfeld.getHeight()/2)+k);
	    stift.drawLine(spielfeld.getWidth()/2, spielfeld.getHeight()/2, (spielfeld.getWidth()/2)-k, (spielfeld.getHeight()/2)+k);
	    stift.drawLine(spielfeld.getWidth()/2, spielfeld.getHeight()/2, (spielfeld.getWidth()/2)+k, (spielfeld.getHeight()/2)-k);
	    stift.drawLine(spielfeld.getWidth()/2, spielfeld.getHeight()/2, (spielfeld.getWidth()/2)-k, (spielfeld.getHeight()/2)-k);
	   
		//tische.add(new Tisch()); tische.get(0).setLand(laenderkarten.get(0)); tische.get(0).setKoord(10, 10); tischzeichnen(stift,0);
		//tische.add(new Tisch()); tische.get(1).setLand(laenderkarten.get(1)); tische.get(1).setKoord(220, 10); tischzeichnen(stift,1);
		//tische.add(new Tisch()); tische.get(2).setLand(laenderkarten.get(2)); tische.get(2).setKoord(430, 10); tischzeichnen(stift,2);
		
	  }
	
	public static void tischzeichnen(Graphics stift, int tischnummer) {
		Image img2 = null;
		try {
			img2=ImageIO.read(new File("./src/spiel/demo_"+tische.get(tischnummer).getLand().land+".jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		ImageObserver napoleon = null;
		stift.drawImage(img2, tische.get(tischnummer).getX(), tische.get(tischnummer).getY(), 200, 200, napoleon);
		System.out.println(tische.get(tischnummer).getLand().land);
	}

}

Leider immer noch das gleiche Ergebnis. Ich bin mir dem Bewusst, dass Deine zwei Linien in dem Beispiel da korrekt zeichnen. :wink:
Aber ich wollte das jetzt mal auch von einer externen Methode aus ausrufen und da klappt es noch nicht so recht…

Sagst Du mir, was ich da noch immer falsch mache?

Gruß
Lukas

Also zunächst mal ist dein Code sehr unübersichtlich. Viel static, unnötige Vererbung (Spielfeld extends CafeMain), viel unnötiger Kram wie z.b.

Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - spielframe.getSize().width) / 2;
int y = (d.height - spielframe.getSize().height) / 2;
spielframe.setLocation(x, y);
spielframe.setResizable(false);
spielframe.setLocationRelativeTo(null);

oder

Container cp = spielframe.getContentPane();
cp.setLayout(null);
spielfeld.setBounds(0, 0, frameWidth, frameHeight);
cp.add(spielfeld);

oder dass du setVisible(true) vor dem hinzufügen der Komponenten aufrufst.

In deinem Beispiel gibt es bezüglich des Zeichnens zwei Probleme:

  1. Du setzt spielfeld.setBounds(0, 0, frameWidth, frameHeight); damit die Größe des Canvas schon zu groß. Füge das Canvas in ein BorderLayout (siehe mein Beispiel) ein, es nimmt dann automatisch den gesamten Bereich des JFrames ein.
  2. In deiner Spielfeld Klasse nutzt du mit spielfeld.getWidth()/getHeight() die falschen Werte zum zeichnen der Linien, da du die Größe in deiner CafeMain schon falsch gesetzt hast.

Falls du das Spielfeld in eine eigene Klasse auslagern willst, dann sollte das eher so aufgebaut sein:

class Spielfeld extends Canvas {

    @Override
    public void paint(Graphics g)
    {
        int height = getHeight();
        int width = getWidth();

        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);
    }
}

Statt dem statischen delegate also eine eigene Klasse die von Canvas erbst. Dort kannst du dann in der paint Methode zeichnen was du magst (in diesem Beispiel die beiden Linien). Hinzufügen kannst du das dann folgendermaßen:

JFrame frame = new JFrame();
[...]

Canvas canvas = new Spielfeld();
frame.add(canvas);
frame.pack();
frame.setVisible(true);

Hier nutzen wir das BorderLayout, das dafür sorgt, dass das Canvas die gesamte Fläche einnimmt. Wir müssen das also nicht händisch per setBounds setzen wie du es in deinem Code gemacht hast.

Ggf. solltest du genauer sagen, was du erreichen willst.

Aber erstmal vorneweg: Üblicherweise verwendet man in einem JFrame keinen Canvas (AWT), sondern ein JPanel (Swing). Insbesondere weil man da double buffering gleich mit bekommt. Dort wird dann paintComponent überschrieben. Z.B.

class BoardPanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int w = getWidth();
        int h = getHeight();
        g.setColor(Color.BLACK);
        g.drawLine(0,0,w,h);
        g.drawLine(0,h,w,0);
    }
}

Zur Größe:

Dem Frame eine feste Größe zu geben macht praktisch nie Sinn, weil je nach Windows-Version, Look And Feel etc. die Titelleiste und der Rand unterschiedlich groß sind.

Üblicherweise gibt man bei “so wenigen Components wie möglich” eine feste Größe vor. So ein Spielfeld KANN da eine der wenigen Ausnahmen sein, aber … “besser” wäre natürlich auch da, wenn es frei skalierbar wäre. (Wenn du genauer sagst, was da alles gezeichnet werden soll, kann man da konkretere Tipps geben (hatte da kürzlich auch etwas ausführlicher in java - How do you use re-size all Graphic2D - Stack Overflow drüber referiert)).

WENN man aber eine feste Größe vorgeben will, dann macht man das üblicherweise, indem man entweder getPreferredSize überschreibt, oder setPreferredSize mit der passenden Größe aufruft, und den Rest dem Layout Manager überläßt - was schon erledigt wäre, wenn man auf dem Frame dann “pack” aufruft.

Hier nochmal ein Beispiel, c&p von woanders:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

// Ein JPanel, bei dem die paintComponent-Methode überschrieben ist,
// so dass man in das JPanel etwas reinmalen kann.
class PaintPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics graphics)
    {
        super.paintComponent(graphics);
        Graphics2D g = (Graphics2D)graphics;

        // Hier die Zeichenbefehle einfügen:
        g.setColor(Color.BLACK);
        g.drawString("Hello, Swing!", 60, 50);
    }
}


public class SwingSimplePaint
{
    public static void main(String args[])
    {
        // Das Erzeugen des GUIs muss auf dem
        // Swing-Thread ausgeführt werden:
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        // Fenster erstellen
        JFrame frame = new JFrame("Simple Paint");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // PaintPanel erstellen und in das Fenster legen
        PaintPanel paintPanel = new PaintPanel();
        paintPanel.setPreferredSize(new Dimension(200, 100));
        frame.getContentPane().add(paintPanel);

        // Fenster zentrieren und anzeigen
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
}

Hallöle,

ich habe absolut keine Peilung von Grafik, da benötige ich kurz Hilfe. Vielen Dank für die bisherigen Antworten. Ich habe bisher nur mit Canvas gearbeitet. Aber nach euren Überzeugungen und dem, was ich gelesen habe, bin ich nun auf das JPanel umgestiegen.

So sieht nun meine Hauptklasse aus:


import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class CafeMain {
	
	protected static String OS = System.getProperty("os.name").toLowerCase();
	protected static String spielname = "Café International";
	protected static String[] spielername = new String[2];
	protected static List<Gastkarte> gastkarten = new ArrayList<Gastkarte>();
	protected static List<Laenderkarte> laenderkarten = new ArrayList<Laenderkarte>();
	protected static int anzahlbarplaetze = 21;
	protected static int[] punktespieler = new int[2];
	protected static int spieler = 1;
	protected static List<Gastkarte> kartenspieler1 = new ArrayList<Gastkarte>();
	protected static List<Gastkarte> kartenspieler2 = new ArrayList<Gastkarte>();
	protected static String filepath = new File("").getAbsolutePath();
	protected static JFrame spielframe = new JFrame(spielname);
	protected static JPanel spielpanel = new JPanel() {
		@Override
	    protected void paintComponent(Graphics stift) {
	        super.paintComponent(stift);
	        Graphics2D g = (Graphics2D)stift;
	        g.drawString("Hallöle Java!", 60, 50);
	        Spielfeld.zeichne(stift);
	    }
	};
	protected static List<Tisch> tische = new ArrayList<Tisch>(12);
	protected static List<Stuhl> stuehle = new ArrayList<Stuhl>(24);
	protected static boolean spielernamenkorrekt = false;
	protected static int x, y;
	
	public CafeMain() throws IOException {
		x = 600;
	    y = 600;
	    spielframe.setSize(x, y);
	    spielframe.setResizable(false);
	    spielframe.setLocationRelativeTo(null);
	    spielframe.setVisible(false);
	    spielframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    // === Komponenten ===
	    Container cp = spielframe.getContentPane();
	    cp.setLayout(null);
	    spielpanel.setBounds(0, 0, x, y);
	    cp.add(spielpanel);
	    // === Komponenten ===
	    ablauf();
	}
	
	public static void ablauf() {
		if(SysWin()) {
			JOptionPane.showMessageDialog(null, "Dein System ist hoffnungslos veraltet!
Windoof ist nicht kompatibel mit diesem Spiel.
Sollte es zu Problemen bei der Ausführung kommen,
dann öffne das Spiel bitte auf einem PC
mit Mac OS oder Linux!", "System veraltet", JOptionPane.WARNING_MESSAGE);
		}
		do{
		Spielstart.namensfrage();
		} while(spielernamenkorrekt == false);
		spielframe.setVisible(true);
		Spielstart.gastkartenmischen();
        Spielstart.laenderkartenmischen();
        Spielstart.spielfeldgenerieren();
	}

	public static void main(String[] args) throws IOException {
		new CafeMain();
	}
	
	public static boolean SysWin() {
		return (OS.indexOf("win") >= 0);
	}

}

Und dazu meine Nebenklasse zum Zeichnen:


import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Spielfeld extends CafeMain {
	public Spielfeld() throws IOException {
		super();
	}

	public static void zeichne(Graphics stift) {
		int[] arrayx = new int[4];
		int[] arrayy = new int[4];
	    
	    arrayx[0] = 110;
	    arrayx[1] = 200;
	    arrayx[2] = 200;
	    arrayx[3] = 120;
	    arrayy[0] = 110;
	    arrayy[1] = 130;
	    arrayy[2] = 170;
	    arrayy[3] = 180;
	    //stift.draw3DRect(10, 10, 100, 100, true);
	    stift.fillPolygon(arrayx, arrayy, 4);
	    int k = 290;
        stift.drawLine(x/2, y/2, (x/2)+k, (y/2)+k);
        stift.drawLine(x/2, y/2, (x/2)-k, (y/2)+k);
        stift.drawLine(x/2, y/2, (x/2)+k, (y/2)-k);
        stift.drawLine(x/2, y/2, (x/2)-k, (y/2)-k);
	   
		//tische.add(new Tisch()); tische.get(0).setLand(laenderkarten.get(0)); tische.get(0).setKoord(10, 10); tischzeichnen(stift,0);
		//tische.add(new Tisch()); tische.get(1).setLand(laenderkarten.get(1)); tische.get(1).setKoord(220, 10); tischzeichnen(stift,1);
		//tische.add(new Tisch()); tische.get(2).setLand(laenderkarten.get(2)); tische.get(2).setKoord(430, 10); tischzeichnen(stift,2);
		
	  }
	
	public static void tischzeichnen(Graphics stift, int tischnummer) {
		Image img2 = null;
		try {
			img2=ImageIO.read(new File("./src/spiel/demo_"+tische.get(tischnummer).getLand().land+".jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		ImageObserver napoleon = null;
		stift.drawImage(img2, tische.get(tischnummer).getX(), tische.get(tischnummer).getY(), 200, 200, napoleon);
		System.out.println(tische.get(tischnummer).getLand().land);
	}

}

Das Problem hat sich nicht verändert. Kann es ja auch gar nicht, da ich auch nur aus dem Canvas ein JPanel gemacht habe. Zentriert ist da weiterhin nichts.

Kann mir einer verraten, wie ich das lösen kann?
Vielleicht könnte das auch eine Funktion, die sagt, dass das Panel 100% der JFramefläche (ohne Titelleiste) einnimmt und nicht immer diese direkten Pixelangaben.

Schöne Grüße
Lukas

Das wurde doch jetzt schon einige male genannt. Verabschiede dich von deinem null-Layout und nehme das (standarmäßige) BorderLayout. Code dazu findest du weiter oben von mir.

Du hast außerdem die angesprochenen Punkte nicht verbessert (static, Spielfeld extends CafeMain, …). Das würde deinen Code wesentlich übersichtlicher und weniger Fehleranfällig machen.

Hallöle,

um kleinere Einzelheiten kümmere ich mich später.
Ich versuche erst einmal ein Border Layout zu erschaffen.

Aber er zeigt mir meine zwei Beispieltextfelder partout nicht an.


import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class CafeMain {
	
	protected static String OS = System.getProperty("os.name").toLowerCase();
	protected static String spielname = "Café International";
	protected static String[] spielername = new String[2];
	protected static List<Gastkarte> gastkarten = new ArrayList<Gastkarte>();
	protected static List<Laenderkarte> laenderkarten = new ArrayList<Laenderkarte>();
	protected static int anzahlbarplaetze = 21;
	protected static int[] punktespieler = new int[2];
	protected static int spieler = 1;
	protected static List<Gastkarte> kartenspieler1 = new ArrayList<Gastkarte>();
	protected static List<Gastkarte> kartenspieler2 = new ArrayList<Gastkarte>();
	protected static String filepath = new File("").getAbsolutePath();
	protected static JFrame spielframe = new JFrame(spielname);
	protected static JPanel spielpanel = new JPanel() {
		@Override
	    protected void paintComponent(Graphics stift) {
	        super.paintComponent(stift);
	        Graphics2D g = (Graphics2D)stift;
	        g.drawString("Hallöle Java!", 60, 50);
	        Spielfeld.zeichne(stift);
	    }
	};
	protected static List<Tisch> tische = new ArrayList<Tisch>(12);
	protected static List<Stuhl> stuehle = new ArrayList<Stuhl>(24);
	protected static boolean spielernamenkorrekt = false;
	protected static int x, y;
	protected static Container cp = spielframe.getContentPane();
	
	public CafeMain() throws IOException {
		x = 600;
	    y = 600;
	    spielframe.setSize(x, y);
	    spielframe.setResizable(false);
	    spielframe.setLocationRelativeTo(null);
	    spielframe.setVisible(false);
	    spielframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    // === Komponenten ===
	    
	    spielpanel.setBounds(0, 0, x, y);
	    cp.add(spielpanel);
	    cp.setLayout(new BorderLayout());
	    cp.add(new JTextField("Texteingabe"),
                BorderLayout.CENTER);
	    cp.add(new JTextField("Texteingabe"),
                BorderLayout.SOUTH);
	    // === Komponenten ===
	    ablauf();
	}
	
	public static void ablauf() {
		if(SysWin()) {
			JOptionPane.showMessageDialog(null, "Dein System ist hoffnungslos veraltet!
Windoof ist nicht kompatibel mit diesem Spiel.
Sollte es zu Problemen bei der Ausführung kommen,
dann öffne das Spiel bitte auf einem PC
mit Mac OS oder Linux!", "System veraltet", JOptionPane.WARNING_MESSAGE);
		}
		do{
		Spielstart.namensfrage();
		} while(spielernamenkorrekt == false);
		spielframe.setVisible(true);
		Spielstart.gastkartenmischen();
        Spielstart.laenderkartenmischen();
        Spielstart.spielfeldgenerieren();
	}

	public static void main(String[] args) throws IOException {
		new CafeMain();
	}
	
	public static boolean SysWin() {
		return (OS.indexOf("win") >= 0);
	}

}

Da muss doch noch irgendetwas schief laufen.

Die führen bei dir aber zu den Problemen :wink:

In deinem Beispiel machst du (wieder) zuerst dein Fenster sichtbar und fügst danach erst die Komponenten hinzu.

Sorry, aber ich verstehe nicht, was Du jetzt mit sichtbar machen meinst.
Den Befehl spielframe.setVisible(true); führe ich ganz zum Schluss aus.

Was genau meinst Du denn sonst damit?

Achso, da hatte ich mich von deinem Code verwirren lassen :wink:
Solange da in Spielstart nichts außergewöhnliches passiert funktioniert dein Code so. Die zwei Textfelder werden bei mir angezeigt.

Ich würde dir allerdings wirklich dazu raten nochmal von vorne anzufangen und deinen Code vernünftiger aufzubauen.

[QUOTE=EikeB]Achso, da hatte ich mich von deinem Code verwirren lassen :wink:
Solange da in Spielstart nichts außergewöhnliches passiert funktioniert dein Code so. Die zwei Textfelder werden bei mir angezeigt.

Ich würde dir allerdings wirklich dazu raten nochmal von vorne anzufangen und deinen Code vernünftiger aufzubauen.[/QUOTE]

Da ist so wenig Code, wo willste da von vorne anfangen?
Und bei meinem Wissen zum JPanel, würde ein neuer Code haargenau so aussehen wie der alte. :wink:

Naja, von dem “bisschen Code” ist halt leider relativ viel relativ schlecht gelöst… Das JPanel ist auch gar nicht das Problem. Es geht da eher um die Architektur (falsche Vererbungen, alles static, …). Ich würde beispielsweise so anfangen:

public class CafeMain {

    public CafeMain() {
        JFrame frame = new JFrame("Cafe Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        Spielfeld spielfeld = new Spielfeld();
        frame.add(spielfeld);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new CafeMain();
    }
}
public class Spielfeld extends JPanel
{
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        int height = getHeight();
        int width = getWidth();

        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);
    }
}

Damit hast du jetzt schonmal zwei saubere Klassen, die einmal deine ganze Anwendung starten und das Spielfeld, das das zeichnen übernimmt.

Viel mehr kann ich aus deinem Code auf den ersten Blick nicht herauslesen. Was da jetzt noch fehlt ist eine art Model, das den aktuellen Stand des Spiels vorhält.

Hallöle,

ich habe Deine Ratschlage genutzt und alles ein wenig umgebaut, vielen lieben Dank. Auch habe ich etwas Ordnung einkehren lassen, sieht viel geordneter aus.

Er zeichnet nun Brav zwei Linien von den Ecken aus, wie es der Quellcode, den Du mir geschickt hast ja machen sollte:

        g.drawLine(0, height, width, 0);```


Nun sieht meine Hauptklasse so aus:
```package spiel;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class CafeMain {
	
	// System Variablen
	protected static String OS = System.getProperty("os.name").toLowerCase();
	protected static String dateipfad = new File("").getAbsolutePath();
	protected static String programmname = "Café International";
	protected static JFrame spielframe = new JFrame(programmname);
	
	// Spieler Variablen
	protected static int spieler = 1;
	protected static String[] spielername = new String[2];
	protected static int[] punktespieler = new int[2];
	protected static List<Gastkarte> kartenspieler1 = new ArrayList<Gastkarte>();
	protected static List<Gastkarte> kartenspieler2 = new ArrayList<Gastkarte>();
	
	// Spielkarten
	protected static List<Gastkarte> gastkarten = new ArrayList<Gastkarte>();
	protected static List<Laenderkarte> laenderkarten = new ArrayList<Laenderkarte>();
	
	// Spielfeld
	protected static List<Tisch> tische = new ArrayList<Tisch>(12);
	protected static List<Stuhl> stuehle = new ArrayList<Stuhl>(24);
	protected static int[] tischex = new int[12];
	protected static int[] tischey = new int[12];
	protected static int anzahlbarplaetze = 21;
	
	// Sonstiges
	protected static boolean spielernamenkorrekt = false;
	
	
	public CafeMain() throws IOException {
        spielframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        spielframe.setLocationRelativeTo(null);
        Spielfeld spielfeld = new Spielfeld();
        spielframe.add(spielfeld);
        spielframe.setSize(600,600);
        spielframe.setResizable(false);
        spielframe.setVisible(false);
        ablauf();
	}
	
	
	
	public static void ablauf() {
		if(SysWin()) {
			JOptionPane.showMessageDialog(null, "Dein System ist hoffnungslos veraltet!
Windoof ist nicht kompatibel mit diesem Spiel.
Sollte es zu Problemen bei der Ausführung kommen,
dann öffne das Spiel bitte auf einem PC
mit Mac OS oder Linux!", "System veraltet", JOptionPane.WARNING_MESSAGE);
		}
		do{
		Spielstart.namensfrage();
		} while(spielernamenkorrekt == false);
		spielframe.setVisible(true);
		Spielstart.gastkartenmischen();
        Spielstart.laenderkartenmischen();
        Spielstart.spielfeldgenerieren();
	}

	public static void main(String[] args) throws IOException {
		new CafeMain();
	}
	
	public static boolean SysWin() {
		return (OS.indexOf("win") >= 0);
	}

}

Und meine Klasse zum Zeichnen des Spielfeldes sieht so aus:


import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Spielfeld extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int height = getHeight();
        int width = getWidth();
        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);
    }
    
    public void zeichnen() {
    	CafeMain.tischex[0] = 300; CafeMain.tischey[0] = 300;
    	CafeMain.tischex[1] = 300; CafeMain.tischey[1] = 300;
    	CafeMain.tischex[2] = 300; CafeMain.tischey[2] = 300;
    	CafeMain.tischex[3] = 300; CafeMain.tischey[3] = 300;
    	CafeMain.tischex[4] = 300; CafeMain.tischey[4] = 300;
    	CafeMain.tischex[5] = 300; CafeMain.tischey[5] = 300;
    	CafeMain.tischex[6] = 300; CafeMain.tischey[6] = 300;
    	CafeMain.tischex[7] = 300; CafeMain.tischey[7] = 300;
    	CafeMain.tischex[8] = 300; CafeMain.tischey[8] = 300;
    	CafeMain.tischex[9] = 400; CafeMain.tischey[9] = 300;
    	CafeMain.tischex[10] = 500; CafeMain.tischey[10] = 300;
    	CafeMain.tischex[11] = 600; CafeMain.tischey[11] = 300;
	   
		//tische.add(new Tisch()); tische.get(0).setLand(laenderkarten.get(0)); tische.get(0).setKoord(10, 10); tischzeichnen(stift,0);
		//tische.add(new Tisch()); tische.get(1).setLand(laenderkarten.get(1)); tische.get(1).setKoord(220, 10); tischzeichnen(stift,1);
		//tische.add(new Tisch()); tische.get(2).setLand(laenderkarten.get(2)); tische.get(2).setKoord(430, 10); tischzeichnen(stift,2);
	    for(int n=0;n<12;n++) {
	    	//tischzeichnen(stift, n);
	    }
    }
    
    public static void tischzeichnen(int tischnummer) {
    	/*Image img2 = null;
		try {
			img2=ImageIO.read(new File("./src/spiel/demo_"+tische.get(tischnummer).getLand().land+".jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		ImageObserver napoleon = null;
		stift.drawImage(img2, tische.get(tischnummer).getX(), tische.get(tischnummer).getY(), 20, 20, napoleon);
		System.out.println(tische.get(tischnummer).getLand().land);*/
    	Image tischbild = null;
    	try{
    		tischbild = ImageIO.read(new File("./src/spiel/demo_"+CafeMain.tische.get(tischnummer).getLand().land+".jpg"));
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    	ImageObserver tischweg = null;
    	
    }
    
}```

Läuft alles gut, aber durch den Wechsel von Canvas auf JPanel habe ich den status quo von vorher noch nicht ganz erreicht, es fehlt ein winziges Detail.

Ich möchte gerne ein Bild aufmalen, aber bekomme das nicht richtig hin.

Das macht diese Methode hier:
```public static void tischzeichnen(int tischnummer) {
    	Image tischbild = null;
    	try{
    		tischbild = ImageIO.read(new File("./src/spiel/demo_"+CafeMain.tische.get(tischnummer).getLand().land+".jpg"));
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    	ImageObserver tischweg = null;
    	
    }```

Also sie erstellt ein Bild aus dem angegebenen Pfad heraus, aber ich habe keinen blassen Schimmer, wie ich diese PaintComponent verwenden soll, um das Bild zu zeichnen.
Also was danach kommt?

Also würde ich gerne 1) das wissen und 2) wissen wollen, ob ich Deinen Vorschlag mit dem nun vorliegenden Quelltext korrekt umgesetzt habe.

Vielen Dank
Gruß
Lukas :)

Der Code schaut auf jeden Fall schon besser aus! Einen wichtigen Punkt hast du bisher allerdings noch völlig ignoriert: Bei dir ist (fast) alles weiterhin statisch :wink:

Bei einer objektorientierten Sprache, wie Java, ist es sehr wichtig den Unterschied zwischen static und non-static zu verstehen. Im Normalfall kommst du (bis auf die main Methode) nämlich komplett ohne static aus. Und genau das solltest du auch machen, bis du dir wirklich sicher bis wie und wann man static nutzen sollte.
In deinem Fall führt das nämlich dazu, dass du versuchst von überall auf bestimmte Dinge zuzugreifen. Ich denke deine Klasse Spielstart ist so ein Kandidat :wink:

Nun mal zu deinem Problem mit dem Zeichnen des Bildes:
Das zeichnen übernimmt komplett die Methode paintComponent, außerhalb dieser Methode wird nichts gezeichnet. Diese paintComponent Methode wird jedesmal dann aufgerufen wenn das System entscheidet, dass jetzt mal neugezeichnet werden muss. Bspw. wenn der User das Fenster vergrößert/verkleinert.
Das Zeichnen eines festen Bildes (bspw. eines Hintergrunds für dein Spiel) könnte man so realisieren:

public class Spielfeld extends JPanel
{
    private Image background;

    public Spielfeld()
    {
        try {
            // load the background image
            this.background = ImageIO.read(this.getClass().getResourceAsStream("/background.jpg"));
        } catch (IOException e) {
            // something went terribly wrong...
            e.printStackTrace();
        }
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        int height = getHeight();
        int width = getWidth();

        // draw the background image
        g.drawImage(this.background, 0, 0, width, height, null);

        // draw some lines
        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);
    }
}

Nun deute ich deinen Code allerdings so, dass deine Bilder (bzw. Tische) dynamische Bilder sein sollen. Man soll also von außen das dargestellte Bild ändern können. Dazu muss das ganze ein wenig angepasst werden. Wir brauchen eine Instanz(!)methode der wir den zu zeichnenden Tisch übergeben und danach das neuzeichnen des Spielfelds anstoßen:

public class Spielfeld extends JPanel
{
    private Image background;

    private Image table;

    public Spielfeld()
    {
        try {
            // load the background image
            this.background = ImageIO.read(this.getClass().getResourceAsStream("/background.jpg"));
        } catch (IOException e) {
            // something went terribly wrong...
            e.printStackTrace();
        }
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        int height = getHeight();
        int width = getWidth();

        // draw the background image (stretched)
        g.drawImage(this.background, 0, 0, width, height, null);

        // draw some lines
        g.drawLine(0, 0, width, height);
        g.drawLine(0, height, width, 0);

        // draw the table, if set
        if (table != null) {
            g.drawImage(this.table, 20, 20, this.table.getWidth(null), this.table.getHeight(null), null);
        }
    }

    public void showTable(int table)
    {
        try {
            // load the table image
            this.table = ImageIO.read(this.getClass().getResourceAsStream("/table" + table + ".png"));

            // force repaint
            repaint();
        } catch (IOException e) {
            // something went terribly wrong...
            e.printStackTrace();
        }
    }
}

Die Methode showTable kannst du dann von außerhalb aufrufen und dadurch steuern welcher Tisch angezeigt werden soll. Wichtig ist dabei aber wie gesagt, dass du den Unterschied zwischen static und non-static verstehst.