JScrollPane um Paint-Panel

Ich habe einen Kleinen Lvl editor geschrieben, da das Lvl sehr breit sein soll muss (und villeicht auch hoch) möchte ich den “screen” mit einem JScrollPane versehen, leider bekomm ich das nicht hin, es wird einfach nicht angezeigt. In den 2 anderen Classen wird in der Main die Objekte erzeugt, die repaint methode in einer while(true) schleife aufgreufen und das übliche eingestellt, und im background(bg) werden bilder gelade. Bitte um Hilfe!


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

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Scrollbar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Frame {
	
	public JFrame frame;
	
	background bg;
	paint screen;
	JMenuBar bar;
	JMenu file;
	JMenuItem item;
	JMenuItem save; 
	JScrollPane scrollPane;
	JComboBox<String> skin;
	String[] blockString = {"Boden", "Pipe", "Sky", "Player"};
	String name;
	
	private FileWriter writer;
	
	private int skinSelection;
	private int x;
	private int y;
	
	File doco;
	ArrayList<Character> mapLetters;
	ArrayList<background> bgArray;
	ArrayList<background> bgFinish;

	
	public Frame(background bg) {
		frame = new JFrame("Game");
		this.bg = bg;
		
		x = 0;
		y = 0;
		
		bgFinish = new ArrayList<background>();
		mapLetters = new ArrayList<Character>();
		bgArray = new ArrayList<background>();
		
		screen = new paint();
		
		for(int ii = 0; ii < bg.getBoxLength(); ii++){
			char nicht = 'S' ;
			mapLetters.add(nicht);
		}
		for(int i = 0; i < bg.getBoxLength();i++){
			if(x >= 12800){
				y += 64;
				x = 0;
			}
			this.bg = new background(x, y, 0);
			bgArray.add(this.bg);
			x += 64;
			System.out.println("y="+y/64+", x="+x/64);
		}
		
		skin = new JComboBox<String>(blockString);
		bar = new JMenuBar();
		file = new  JMenu("File");
		item = new JMenuItem("New");
		save = new JMenuItem("Save");
		
		screen.setBounds(140, 64, 12800, 768);
		skin.setBounds(10, 50, 120, 50);

		
		
		screen.addMouseListener(new mouseListener());
		skin.addItemListener(new itemListener());
		item.addActionListener(new actionListener());
		save.addActionListener(new actionListener());
		
		bar.add(file);
		file.add(item);
		file.add(save);
		frame.setJMenuBar(bar);

		frame.add(skin);
		frame.add(screen);
	}
	


	private class actionListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent e) {
			if(e.getSource() == item){
			name = JOptionPane.showInputDialog(frame, "Name der File", "File", JOptionPane.OK_OPTION);
			doco = new File(name+".txt");
			try {
				doco.createNewFile();
				writer = new FileWriter(name+ ".txt");
			}catch (IOException e1) {e1.printStackTrace();}
		}
		if(e.getSource() == save ){
			for(int i = 0; i < bg.getBoxLength(); i++){
				try {
					writer.write(mapLetters.get(i));
					writer.flush();
				} catch (IOException e1) {e1.printStackTrace();}
			}
			try {
				writer.close();
			} catch (IOException e1) {e1.printStackTrace();}
		}
	}
}
	
	
	private class itemListener implements ItemListener {
		
		@Override
		public void itemStateChanged(ItemEvent e) {
			if(e.getStateChange() == e.SELECTED){
				if(e.getSource() == skin) {
							skinSelection = skin.getSelectedIndex();
				}
			}
		}
	}
	
	private class mouseListener implements MouseListener{
		@Override
		public void mouseClicked(MouseEvent e) {
			for(int i = 0; i < bgArray.size();i++) {
				if(e.getX() >= bgArray.get(i).getBounding().x && e.getX() <= bgArray.get(i).getBounding().x+64 && e.getY() >= bgArray.get(i).getBounding().y && e.getY() <= bgArray.get(i).getBounding().y+64){
					bg = new background(bgArray.get(i).getBounding().x, bgArray.get(i).getBounding().y, skinSelection);
					bgFinish.add(bg);
					if(skinSelection == 0){
						mapLetters.remove(i);
						mapLetters.add(i,'G');
					}
					else if(skinSelection == 1){
						mapLetters.remove(i);
						mapLetters.add(i,'P');
					}
					else if(skinSelection == 2){
						mapLetters.remove(i);
						mapLetters.add(i,'S');
					}
					else if(skinSelection == 3){
						mapLetters.remove(i);
						mapLetters.add(i,'$');
					}
					System.out.println(i);
			}
		}
	}
	
	
	@Override
	public void mouseEntered(MouseEvent e){}
	
	@Override
	public void mouseExited(MouseEvent e){}
	
	@Override
	public void mousePressed(MouseEvent e){}
		
	@Override
	public void mouseReleased(MouseEvent e){}
	
	}
	
	private class paint extends JLabel{
		protected void paintComponent(Graphics g){
			for(int i = 0; i < bgArray.size();i++) {
				g.drawRect(bgArray.get(i).getBounding().x, bgArray.get(i).getBounding().y, bgArray.get(i).getBounding().width, bgArray.get(i).getBounding().height);
			}
			for(int ii = 0; ii < bgFinish.size();ii++){
				g.drawImage(bgFinish.get(ii).getImage(), bgFinish.get(ii).getBounding().x,bgFinish.get(ii).getBounding().y, null );
			}
			}
	}
	
	public void repaintScreen() {
		screen.repaint();
	}
}```
        frame.add(sp);

und ganz wichtig ist dass screen eine PreferredSize bekommt
screen.setPreferredSize(new Dimension(2000,768));


mehrere Komponenten ins JFrame, Bounds, das ist nicht so toll, das ContentPane des JFrames hat standardmäßig BorderLayout,
verwende (wenn überhaupt, wenn Standard-Layouts nicht reichen)

        JPanel p = new JPanel();
        p.setLayout(null);

        skin.setBounds(10, 50, 120, 50);
        p.add(skin);

        screen.setPreferredSize(new Dimension(2000, 768));
        JScrollPane sp = new JScrollPane(screen);
        sp.setBounds(140, 64, 400, 400);

        p.add(sp);
        frame.add(p);

in paintComponent besser als erste Zeile immer
super.paintComponent(g);

Die PrefferedSize ist afaik nicht nötig, weil die Scrollbars sichbar werden, wenn “screen” groß genug wird.

was bei einer leeren Komponente nur mit paint-Befehlen nicht von alleine der Fall sein wird, PrefferedSize 1x1 oder kleiner

setSize/ setBounds (enthält auch setSize) könnte man annehmen, aber in diesem Fall (wie oftmals in Layout-Fragen außer null-Layout) ignoriert,
die Size wird gar eher neu berechnet und überschrieben,
es muss PrefferedSize sein, darauf wird geachtet

So funktionirt es jetzt bei mir weiß aber nicht ob das gut geschrieben ist :smiley:

package main;

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

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Frame {
	
	public JFrame frame;
	
	background bg;
	Picture pic;
	paint screen;
	JMenuBar bar;
	JMenu file;
	JMenuItem item;
	JMenuItem save; 
	JScrollPane scrollPane;
	JComboBox<String> skin;
	String[] blockString = {"Boden", "Pipe", "Sky", "Player", "BlackBlock", "GroundBottom", "GroundMittle"};
	String name;
	
	private FileWriter writer;
	
	private int skinSelection;
	private int x;
	private int y;
	
	File doco;
	
	ArrayList<Character> mapLetters;
	ArrayList<background> bgArray;
	ArrayList<background> bgFinish;

	
	public Frame(background bg, Picture pic) {
		frame = new JFrame("Level editor");
		this.bg = bg;
		this.pic = pic;
		x = 0;
		y = 0;
		
		bgFinish = new ArrayList<background>();
		mapLetters = new ArrayList<Character>();
		bgArray = new ArrayList<background>();
		
		screen = new paint();
		
		for(int ii = 0; ii < bg.getBoxLength(); ii++){
			mapLetters.add('S');
		}
		for(int i = 0; i < bg.getBoxLength();i++){
			if(x >= 12800){
				y += 64;
				x = 0;
			}
			this.bg = new background(x, y, 0);
			bgArray.add(this.bg);
			x += 64;
			System.out.println("y="+y/64+", x="+x/64);
		}
		
		skin = new JComboBox<String>(blockString);
		bar = new JMenuBar();
		file = new  JMenu("File");
		item = new JMenuItem("New");
		save = new JMenuItem("Save");
		
		skin.setBounds(1550, 50, 120, 50);
		screen.setBounds(140, 64, 12800, 768);
		screen.setPreferredSize(new Dimension(12800, 768));
		
		scrollPane = new JScrollPane(screen,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane.setPreferredSize(new Dimension(1500, 950));
		
		screen.addMouseListener(new mouseListener());
		skin.addItemListener(new itemListener());
		item.addActionListener(new actionListener());
		save.addActionListener(new actionListener());

		bar.add(file);
		file.add(item);
		file.add(save);
		frame.setJMenuBar(bar);
		frame.add(skin);
		frame.add(scrollPane);
		frame.pack();
	}
	


	private class actionListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent e) {
			if(e.getSource() == item){
			name = JOptionPane.showInputDialog(frame, "Name des File", "File", JOptionPane.OK_OPTION);
			doco = new File(name+".txt");
			try {
				doco.createNewFile();
				writer = new FileWriter(name+ ".txt");
			}catch (IOException e1) {e1.printStackTrace();}
		}
		if(e.getSource() == save ){
			for(int i = 0; i < bg.getBoxLength(); i++){
				try {
					writer.write(mapLetters.get(i));
					writer.flush();
				} catch (IOException e1) {e1.printStackTrace();}
			}
			try {
				System.out.println("Datei Gespeichert");
				writer.close();
			} catch (IOException e1) {e1.printStackTrace();}
		}
	}
}
	
	
	private class itemListener implements ItemListener {
		
		@Override
		public void itemStateChanged(ItemEvent e) {
			if(e.getStateChange() == e.SELECTED){
				if(e.getSource() == skin) {
					skinSelection = skin.getSelectedIndex();
				}
			}
		}
	}
	
	private class mouseListener implements MouseListener{
		@Override
		public void mouseClicked(MouseEvent e) {}

		@Override
		public void mouseEntered(MouseEvent e){}
	
		@Override
		public void mouseExited(MouseEvent e){}
	
		@Override
		public void mousePressed(MouseEvent e){}
		
		@Override
		public void mouseReleased(MouseEvent e){
			if(e.getButton() == 1){
			for(int i = 0; i < bgArray.size();i++) {
				if(e.getX() >= bgArray.get(i).getBounding().x && e.getX() <= bgArray.get(i).getBounding().x+64 && e.getY() >= bgArray.get(i).getBounding().y && e.getY() <= bgArray.get(i).getBounding().y+64){
					bg = new background(bgArray.get(i).getBounding().x, bgArray.get(i).getBounding().y, skinSelection);
					bgFinish.add(bg);
					if(skinSelection == 0){
						mapLetters.remove(i);
						mapLetters.add(i,'G');
					}
					else if(skinSelection == 1){
						mapLetters.remove(i);
						mapLetters.add(i,'P');
					}
					else if(skinSelection == 2){
						mapLetters.remove(i);
						mapLetters.add(i,'S');
					}
					else if(skinSelection == 3){
						mapLetters.remove(i);
						mapLetters.add(i,'$');
					}
					else if(skinSelection == 4){
						mapLetters.remove(i);
						mapLetters.add(i,'L');
					}
					else if(skinSelection == 5){
						mapLetters.remove(i);
						mapLetters.add(i,'B');
					}
					else if(skinSelection == 6){
						mapLetters.remove(i);
						mapLetters.add(i,'M');
					}
					System.out.println(i);
				}
			}
			}
		}
	}
	
	private class paint extends JLabel{
		
		protected void paintComponent(Graphics g){
			super.paintComponent(g); 
			for(int i = 0; i < bgArray.size();i++) {
				g.drawRect(bgArray.get(i).getBounding().x, bgArray.get(i).getBounding().y, bgArray.get(i).getBounding().width, bgArray.get(i).getBounding().height);
			}
			for(int ii = 0; ii < bgFinish.size();ii++){
				g.drawImage(pic.getImage(bgFinish.get(ii).getImageInt()), bgFinish.get(ii).getBounding().x,bgFinish.get(ii).getBounding().y, null );
			}
			}
	}
	
	public void repaintScreen() {
		screen.repaint();
	}
}```

zweimal add auf JFrame mit BorderLayout geht nicht gut,
nach bisschen Größenänderung, Minimieren/ Maximieren ist vielleicht was weg

hab ja was zum null-Layout geschrieben, kannst du verwenden falls es Probleme geben sollte