Kinosaal - Sitzplätze erstellen

hi,
ich hab ein kleines Problem, und zwar weiss ich nicht wie ich einen Kinosaal mit Sitzplätzen darin (3 Sääle mit 80, 120 und 160 Sitzen) mit Swing repräsentieren soll.
Also ich wollte es so ähnlich wie beim Cinestar haben wenn man bei der Online Reservierung bzw Online Ticketkauf sich das Fenster öffnet mit dem Kinosaal und den SItzplätzen darin wo man dann auf einen Platz klicken kann und den zur Reservierung auswählen kann, es muss nicht so schön graphisch sein, einfache Kästchen reichen schon, nur ich weiss nicht wie ich da am besten herangehen soll…
ich hab mir verschiedene Möglichkeiten überlegt,

  1. Ein GridBagLayout jedes Kästchen ein Sitzplatz, in jedem Kasten ein JPanel ,allerdings weiss ich nicht wie ich das automatisiert machen kann , (ich hab keine Lust 120 JPanel anzulegen in jedes Kästchen eins…) ausserdem weiss ich nicht wie ich die Größe jedes Kästchens setzen kann und ob man die Kästchen bzw späteren SItze noch indexieren kann, das wäre nützlich (um die Plätze zu nummerieren)
  2. Eine Tabelle erstelle mit n Reihen und m Spalten, dann könnte ich wohl einzelnen Tabellenkästchen auswählen und die wären vllt schon vorher indexiert…
  3. vllt ein „Gitter“ mit mehrfach auswählbaren Radio Buttons oder Checkboxen, aber wird wohl auch nicht einfach zu indexieren sein…

hier mein Code bisher … ich habe das Fenster quasi in 3 Ebenen unterteilt: auf der linken Leiste die liste mit Filmen zur Auswahl (und den zugehörigen Sälen später) in der Oberen Hälfte noch ein paar Infos zum Film, Datum/Spielzeit und Saal, und darunter soll der Kinosaal abgebildet werden mit den Sitzplätzen dazu (den ich im moment nicht hinbekomme :wink: )

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

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.border.EmptyBorder;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JList;

import com.jgoodies.forms.layout.RowSpec;

import javax.swing.JButton;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Component;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JSeparator;

public class TicketOverview extends JFrame {

	private JPanel contentPane;
	private JMenuBar menuBar;
	private JMenu mnStart;
	private JMenu mnHilfe;
	private JSplitPane splitPane;
	private JList list;
	private JList list_1;
	private JButton btnNewButton;
	private FlowLayout flowLayout;
	private BoxLayout boxLayout;
	private JButton btnNewButton_1;
	private JButton btnNewButton_2;
	private JButton btnNewButton_3;
	private JButton btnNewButton_4;
	private JButton btnNewButton_5;
	private JButton btnNewButton_6;
	private JButton btnNewButton_7;
	private JButton btnNewButton_8;
	private JButton btnNewButton_9;
	private JTextArea textArea;
	private JButton btnNewButton_10;
	private JLabel lblFilmtitel;
	private JTextField textField;
	private JLabel lblDatumuhrzeit;
	private JTextField textField_1;
	private JLabel lblSaal;
	private JTextField textField_2;
	private JSeparator separator;
	private JLabel lblLeinwand;

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

	/**
	 * Create the frame.
	 */
	public TicketOverview() {
		initComponents();
	}
	private void initComponents() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 884, 481);
		
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		mnStart = new JMenu("Start");
		menuBar.add(mnStart);
		
		mnHilfe = new JMenu("Hilfe");
		menuBar.add(mnHilfe);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));		
		contentPane.setLayout(null);	
		
		JPanel panelLeft = new JPanel();
		JPanel panelRight = new JPanel();
	        
		splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		
		setContentPane(splitPane);
		splitPane.setLeftComponent(panelLeft);
		
		btnNewButton = new JButton("Film 1");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
			}
		});
		panelLeft.add(btnNewButton);
	    splitPane.setRightComponent(panelRight);  
	    panelRight.setLayout(null);
	    
	    lblFilmtitel = new JLabel("Filmtitel");
	    lblFilmtitel.setBounds(21, 25, 46, 14);
	    panelRight.add(lblFilmtitel);
	    
	    textField = new JTextField();
	    textField.setBounds(76, 22, 86, 20);
	    panelRight.add(textField);
	    textField.setColumns(10);
	    
	    lblDatumuhrzeit = new JLabel("Datum,Uhrzeit");
	    lblDatumuhrzeit.setBounds(197, 25, 111, 14);
	    panelRight.add(lblDatumuhrzeit);
	    
	    textField_1 = new JTextField();
	    textField_1.setBounds(318, 22, 86, 20);
	    panelRight.add(textField_1);
	    textField_1.setColumns(10);
	    
	    lblSaal = new JLabel("Saal");
	    lblSaal.setBounds(440, 25, 46, 14);
	    panelRight.add(lblSaal);
	    
	    textField_2 = new JTextField();
	    textField_2.setBounds(496, 22, 86, 20);
	    panelRight.add(textField_2);
	    textField_2.setColumns(10);
	    
	    separator = new JSeparator();
	    separator.setBounds(0, 93, 587, 2);
	    panelRight.add(separator);
	    
	    lblLeinwand = new JLabel("Leinwand");
	    lblLeinwand.setBounds(243, 68, 70, 14);
	    panelRight.add(lblLeinwand);
	    
	    panelLeft.setLayout(new BoxLayout(panelLeft,BoxLayout.Y_AXIS));
	    
	    btnNewButton_1 = new JButton("Film2");
	    panelLeft.add(btnNewButton_1);
	    
	    btnNewButton_2 = new JButton("Film 3");
	    panelLeft.add(btnNewButton_2);
	    
	    btnNewButton_3 = new JButton("Film 4");
	    panelLeft.add(btnNewButton_3);
	    
	    btnNewButton_4 = new JButton("Film 5");
	    panelLeft.add(btnNewButton_4);
	    
	    btnNewButton_5 = new JButton("Film 6");
	    panelLeft.add(btnNewButton_5);
	    
	    btnNewButton_6 = new JButton("Film 7");
	    panelLeft.add(btnNewButton_6);
	    
	    btnNewButton_7 = new JButton("Film 8");
	    panelLeft.add(btnNewButton_7);
	    
	    btnNewButton_8 = new JButton("Film 9");
	    btnNewButton_8.addActionListener(new ActionListener() {
	    	public void actionPerformed(ActionEvent e) {
	    	}
	    });
	    btnNewButton_8.setAlignmentY(Component.TOP_ALIGNMENT);
	    panelLeft.add(btnNewButton_8);
	    
	    btnNewButton_9 = new JButton("kommende Filme");
	    panelLeft.add(btnNewButton_9);
	    
	    textArea = new JTextArea();
	    textArea.setSize(10,10);   
	    panelLeft.add(textArea);
	    
	    btnNewButton_10 = new JButton("Reservierung suchen");
	    panelLeft.add(btnNewButton_10);
	    
	   
		
		
	}
}

1 und 3 laufen eigentlich auf’s gleiche raus: In beiden Fällen gibt es irgendwelche “Components” (d.h. JPanels oder eben CheckBoxes), die irgendwie angeordnet werden sollen. Dabei stellen sich zwei Fragen: A. welches Layout soll verwendet werden und B. wie werden diese Components verwaltet. Punkt B. ist eigentlich recht einfach: Es gibt dann eben eine Liste mit diesen Components, z.B.

List<Platz> liste = new ArrayList<Platz>();
for (int i=0; i<120; i++)
{
    Platz platz = new Platz();
    liste.add(platz);
    übergeordneteComponent.add(platz);
}

wobei “Platz” dann eben die jeweilige Klasse wäre: JCheckBox, JPanel oder eine eigene, von JComponent abgeleitete Klasse.

Das Layout ist schon etwas schwieriger: GridBagLayout KANN recht kompliziert sein, je nachdem, welche Fancy Anordnungen man damit erreichen will. Wenn es eine rein Gitterförmige Anordung sein soll, würde es schon ein GridLayout tun. Da braucht man dann nicht viel nachzudenken: Alle Gitterzellen (d.h. Plätze) sind automatisch gleich groß.

Das würde dann fast aussehen, wie eine Tabelle - was ja die 2. Option war. Da… weiß ich nicht so genau… man ist eben bei der Darstellung recht “festgelegt”: Es wird immer wie eine JTable aussehen, aber … wie wichtig das Aussehen allgemein ist, wurde bisher nicht so deutlich.

Deswegen noch Option 4.: Man könnte auch die einzelnen Plätze mit Polygonen darstellen, quasi als richtigen “Lageplan”, aber das wäre natürlich recht aufwändig zu erstellen…

ok option 4 hab ich kein plan klingt schwer für anfänger, ich tendiere zu option tabelle oder gridlayout …
nur mit was soll ich die gridlayout kästchen am besten füllen? mit JPanels? und gibt es eine Möglichkeit / Methode auf die einzelnen Kasten im GridLBagLayout zuzugreifen und evtl sogar die größe der Kästchen zu ändern? Oder einzustellen wieviele Kästchen bzw wieviele Reihen / Spalten das Gitter haben soll? Das wäre von Vorteill…

Falls ich das richtig verstehe ist das Layout und das, was du mit ~“darauf zugreifen” meinst, eben unterschiedliche Dinge. Das Layout kümmert sich darum, wie irgendwelche JComponents angeordnet sind. Das “zugreifen” passiert ja nicht über das Layout. Stattdessen würden die “Platz-Objekte” (was auch immer das genau ist) z.B. ein einer Liste liegen.

In einem GridLayout sind alle Kästchen gleich groß. Wenn man sagt
panel.setLayout(new GridLayout(rows, columns));
gibt man ja schon die Anzahl der Zeilen+Spalten vor. Die Größe eines einzelnen Kästchens ergibt sich damit aus der Größe des übergeordneten Panels.

Wenn die Kästchen unterschiedlich groß sein sollten, müßte man ein GridBagLayout verwenden, aber damit können irgendwelche Größenangaben schwierig sein, weil man nur (auf ziemlich unhandliche Weise) sagen kann, wie die Größenverhältnisse sein sollen.

Egal, welches Layout verwendet wird, und welche Größen die einzelnen “Zellen” haben: Die “Zellen” werden immer irgendwelche JComponents sein. Das können eigene JPanels sein, oder gleich JCheckBoxes, oder eine eigene von JComponent abgeleitete Klasse.

Wie soll ein “Platz” denn nun repräsentiert sein? Mit irgendwas selbstgemaltem, oder einer JCheckBox…?

hier mal ein ganz rudimentärer Ansatz mit dem GridbagLayout, weder lange überdacht, noch sonderlich effizient…

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class KinoSaalPanel extends JPanel {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setSize(500, 500);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.add(new KinoSaalPanel(10, 16));
		f.setLocationRelativeTo(null);
		f.setVisible(true);

	}

	Color[] color = { Color.GREEN, Color.RED, Color.YELLOW };

	public KinoSaalPanel(int rows, int numberOfSeatsPerRow) {

		setLayout(new GridBagLayout());

		for (int i = 0; i < numberOfSeatsPerRow; i++) {
			for (int j = 0; j < rows; j++) {
				final SitzPanel p = new SitzPanel(i, j);
				p.setSize(new Dimension(10, 10));
				p.setBackground(color[p.getColorNumber()]);
				GridBagConstraints gbc = new GridBagConstraints();
				gbc.gridx = i;
				gbc.gridy = j;
				int left = 1;
				int top = 1;
				// so könnte man bspw Gänge darstellen...ganz rudimentär
				// angedacht
				// if (i % 5 == 0) {
				// left = 5;
				// }
				// if (j % 5 == 0) {
				// top = 5;
				// }
				gbc.insets = new Insets(top, left, 1, 1);
				p.setBorder(BorderFactory.createBevelBorder(0));
				p.addMouseListener(new MouseListener() {

					@Override
					public void mouseReleased(MouseEvent e) {
					}

					@Override
					public void mousePressed(MouseEvent e) {
					}

					@Override
					public void mouseExited(MouseEvent e) {
					}

					@Override
					public void mouseEntered(MouseEvent e) {
						System.out.println("Reihe: " + (p.getRow() + 1)
								+ "	Platz: " + (p.getNumber() + 1));
					}

					@Override
					public void mouseClicked(MouseEvent e) {
						int actualColor = p.getColorNumber();
						p.setBackground(color[actualColor]);
						String s = "";
						switch (actualColor) {
						case 0:
							s = "frei";
							break;
						case 1:
							s = "vergeben";
							break;
						case 2:
							s = "reserviert";
						default:
							break;
						}
						if (actualColor == color.length - 1) {
							actualColor = 0;
							p.setColorNumber(actualColor);
						} else {
							p.setColorNumber(actualColor + 1);
						}

						System.out.println("Reihe: " + (p.getRow() + 1)
								+ "	Platz: " + (p.getNumber() + 1) + " ist "
								+ s);

					}
				});
				add(p, gbc);
			}
		}
	}
}

class SitzPanel extends JPanel {
	private int row;
	private int number;
	private int colorNumber = 0;

	public SitzPanel(int number, int row) {
		this.row = row;
		this.number = number;
	}

	public int getNumber() {
		return number;
	}

	public int getRow() {
		return row;
	}

	public void setColorNumber(int colorNumber) {
		this.colorNumber = colorNumber;
	}

	public int getColorNumber() {
		return colorNumber;
	}
}

panel.setLayout(new GridLayout(rows, columns));
danke für den Tipp, ich denke ich nehme ein GridLayout, die Kästchen können ruhig alle gleich groß sein, ich wollte JPanels für die Kästchen nehmen und die evtl umranden bzw voneinander abgrenzen und sobald man auf ein panel klickt, dieses andersfarbig markieren (z.B rot oder gelb oder so)

ansonsten könnte ich ja auch für jedes der Panels in den Kästchen ein icon nehmen , z.B ein Sessel icon und das Panel damit füllen sieht halt evtl besser aus, aber im Prinzip erfüllt es so die Funktion, man soll nur erkennen können welche der Sitze schon reserviert wurden, und eben die Nummer des Sitzplatzes zurückbekommen bzw alle Sitze indizieren können.

@jgh danke für den Code, das sieht ja schon ziemlich fortschrittlich aus :wink:
genau in dem Sinne wollte ich das auch machen, aber muss ich mir nochmal genau anschauen… bin halt noch relativ neu in Swing, und kenne die ganzen speziellen Klassen und Methoden wie GridBagConstraints, Insets, createBevelBorder() noch gar nicht…