Swing Scrollen über JPane

Amios

Mitglied
Hallo, ich habe mir eine von JPane erbende Klasse erstellt, die so aussieht
Java:
public class JImagePanel extends JPanel{

	  private Image img;

	  public JImagePanel(String img) {
	    this(new ImageIcon(img).getImage());
	  }

	  public JImagePanel(Image img) {
	    this.img = img;
	    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
	    setPreferredSize(size);
	    setMinimumSize(size);
	    setMaximumSize(size);
	    setSize(size);
	    setLayout(null);
	  }

	  public void paintComponent(Graphics g) {
	    g.drawImage(img, 0, 0, null);
	  }

	}
nun instantiiere ich ein solches und füge ich in dieses Panel beliebige SwingObjecte ein (was auch funktioniert).
Ich möchte jedoch, wenn der Anzeigebereich erschöpft ist, eine Scrollbar angezeigt bekommen und mit dieser über den Inhalt des Panels scrollen können( der Background soll sich nicht verändern).

Daher habe ich eine JScrollbar erstellt und als View jenes JImagePane zugewiesen.
Java:
JImagePanel cardpanel = new JImagePanel("./spielflaeche.gif");
JScrollPane scrollpane = new JScrollPane(cardpanel);
Jedoch kann ich nicht über die Elemente scrollen. Wo dran mag das liegen?
 
Es liegt daran, dass su der JScrollPane eine size (width, height) geben musst -> z.B.: JScrollPane#setSize(width, height);
 
Zuletzt bearbeitet:
Danke, ich habe nun

Java:
scrollpane.setSize(cardpanel.getSize());

zum Quellcode hinzugefügt, jedoch ohne Auswirkungen.
 
Was ist wenn du die JScrollPane etwas kleiner als cardpanel.getSize() machst, Dann müssten die ScrollBars schonmal sichtbar sein.
 
Java:
scrollpanel.setSize((int) cardpanel.getSize().getWidth()-50, (int) (cardpanel.getSize().getHeight()));
keine Änderung.

ich poste mal grade den kompletten Code meiner Klass
Java:
public class PlayerGui extends Thread {
	private int tableID = 0;
	private boolean isAlive = true;
	
	private LinkedBlockingQueue<Card> cards = null;

	private JFrame frame = null;
	private JMenuBar menubar = null;
	private JMenuItem exit;
	private JRadioButtonMenuItem show;
	private JMenu data;
	private JMenu view;
	private JMenu help;
	private JPanel mainpanel = null;
	private JPanel buttons = null;
	private JButton check = null;
	private JButton allin = null;
	private JButton flod = null;
	private JButton raise = null;
	private JTextField raisamount = null;
	private JScrollPane scrollpanel = null;
	private JPanel cardpanel = null;
	private Logger log = null;

	public PlayerGui(int tableID) {
		this.tableID = tableID;
		cards = new LinkedBlockingQueue<Card>();
		this.log = new Logger(this);
		log.setDateFormat(Setup.DATEFORMAT);
		log.setStandardLoggingPath(Setup.loggingPath + "/"
				+ this.getClass().getSimpleName() + ".log");
		log.setErrorLoggingPath(Setup.loggingPath + "/"
				+ this.getClass().getSimpleName() + ".err.log");
		setup();
	}

	public void setup() {
		frame = new JFrame("IViRNN Table:" + tableID);
		mainpanel = new JPanel();
		
		menubar = new JMenuBar();
		data = new JMenu("Datei");
		view = new JMenu("Ansicht");
		help = new JMenu("Hilfe");
		exit = new JMenuItem("Tisch verlassen");
		show = new JRadioButtonMenuItem("Serverinfo einblenden");
		
		buttons = new JPanel();
		check = new JButton("check");
		allin = new JButton("All-in");
		flod = new JButton("flod");
		raisamount = new JTextField("0");
		raise = new JButton("raise");
		
		cardpanel = new JImagePanel(initBackgroundImage());
		cardpanel = new JPanel();
		scrollpanel = new JScrollPane(cardpanel);
	}

	public void init() {
		addActionListeners();
//		scrollpanel.setVisible(true);
		scrollpanel.setSize((int) cardpanel.getSize().getWidth()-50, (int) (cardpanel.getSize().getHeight()));
		cardpanel.setLayout(new FlowLayout());
		
		raisamount.setSize(raise.getSize());

		buttons.add(allin);
		buttons.add(flod);
		buttons.add(raise);
		buttons.add(raisamount);
		buttons.add(check);

		mainpanel.setLayout(new BorderLayout());
		mainpanel.add(scrollpanel, BorderLayout.CENTER);
		mainpanel.add(buttons, BorderLayout.SOUTH);

		data.add(exit);
		data.setMnemonic('D');
		view.add(show);
		view.setMnemonic('A');
		show.setSelected(true);

		menubar.add(data);
		menubar.add(view);
		menubar.add(help);

		frame.getContentPane().add(mainpanel);
		frame.setLocationRelativeTo(null);
		frame.setIconImage(new ImageIcon(Setup.PATH + "icon.gif").getImage());
		frame.setResizable(false);
		frame.setJMenuBar(menubar);
		frame.setVisible(true);
	}

	private String initBackgroundImage() {
		File f = new File("./CardImages/Felt.gif");
		if (f.exists()) {
			return f.getAbsolutePath();
		} else {
			System.err.println("File does not exist");
		}
		throw new FileNotFoundException();
	}

	private void addActionListeners() {
		exit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// ln.shutdown();
			}
		});

		// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent we) {
				/* ln.shutdown(); */
			}
		});
	}

	@Override
	public void run() {
		init();
		try {
			while (isAlive) {
				Card c = cards.take();
				showCard(c);
				frame.pack();

			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public synchronized void addCard(Card card) {
		cards.add(card);
		log.logDebug("Karte " + card.getColor() + "-" + card.getValue()
				+ " wurde erhalten");
	}

	private void showCard(Card c) {
		Icon image = c.getImage();
		if (c != null) {
			JLabel l = new JLabel(image);
			JLabel text = new JLabel();
			text.setText(c.getColor() + "-" + c.getValue());
			l.add(text);
			cardpanel.add(l);
		} else {
			log.logError("Card image was not found");
		}
	}

	public static void main(String[] args) {
		PlayerGui pg = new PlayerGui(182);
		pg.start();
		Deck d = new Deck();
		d.shuffle();
		for (int i = 0; d.size() != 0; i++) {
			pg.addCard(d.drawCard());
		}

	}
}
 
Zuletzt bearbeitet:
ja, ich denke, dass es nicht nötig ist die Scrollpane extra sichtbar zu machen(ist sie glaube ich standartmäßig). aber ich habe die Kommentare weg genommen -> keine Änderung

ich vermute, dass das problem im frame.pack() im run() liegt.
 
Zuletzt bearbeitet:
So funktionierts (ich hab deine Version jetzt mal ziemlich abgespckt und auf das Wesentliche reduziert), Du darfst die Komponente bei der JScrollPane nicht direkt über den Konstruktor hinzufügen sondern musst es über den ViewPort machen, sollte es dann noch immer nicht funktionieren, musst du noch die PreferedSize setzen, dann sollte es klappen.
lg


Java:
package classpathtest;

import java.awt.Color;
import java.awt.Dimension;
import java.io.FileNotFoundException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

public class PlayerGui {

    private static class JImagePanel extends JPanel {

        public JImagePanel(String initBackgroundImage) {
            super();
        }
    }

    private int tableID = 0;
    private boolean isAlive = true;
    private LinkedBlockingQueue<Card> cards = null;
    private JFrame frame = null;
    private JMenuBar menubar = null;
    private JMenuItem exit;
    private JRadioButtonMenuItem show;
    private JMenu data;
    private JMenu view;
    private JMenu help;
    private JPanel mainpanel = null;
    private JPanel buttons = null;
    private JButton check = null;
    private JButton allin = null;
    private JButton flod = null;
    private JButton raise = null;
    private JTextField raisamount = null;
    private JScrollPane scrollpanel = null;
    private JPanel cardpanel = null;
    private Logger log = null;

    public PlayerGui(int tableID) throws FileNotFoundException {
        this.tableID = tableID;
        cards = new LinkedBlockingQueue<Card>();
        init();
        }

    public void init() {      
        frame = new JFrame("IViRNN Table:" + tableID);

        cardpanel = new JImagePanel("");
        cardpanel = new JPanel();
        cardpanel.setBackground(new Color(255, 0, 0));
        
        scrollpanel = new JScrollPane();
        scrollpanel.setBackground(new Color(0,255, 0));
        cardpanel.setSize(600, 600);
        cardpanel.setPreferredSize(new Dimension(800, 900));
        scrollpanel.setSize(400, 400);
        scrollpanel.getViewport().add(cardpanel);
        scrollpanel.setPreferredSize(new Dimension(400, 400));
        scrollpanel.revalidate();

        frame.getContentPane().add(scrollpanel);
        frame.setLocationRelativeTo(null);
        frame.setJMenuBar(menubar);
        frame.getContentPane().setBackground(new Color(0, 0, 255));
        frame.setBackground(new Color(100,100,255));
        frame.setBounds(200, 200, 400, 400);
        frame.setPreferredSize(new Dimension(400, 400));
        frame.setVisible(true);
    }

    public static void main(String[] args) throws FileNotFoundException {
        PlayerGui pg = new PlayerGui(182);
    }
}
 
Zuletzt bearbeitet:
Super danke, nun habe ich Scrollbars.
Leider jedoch nicht so wie ich sie haben wollte, denn es kann nicht über alle Karten gescrollt werden.
Ich habe mal einen screenshot angehängt, um zu zeigen, was ich meine.

playerscreen.jpg
 
Danke! Doch trotz der Größenänderung, ändert sich nichts.
Außerdem habe ich es mir anders vorgestellt.
Ich wollte, dass der Grüne Hintergrund statisch bleibt, wenn gescrollt wird.
Die Karten sollten paarweise mittig auf dem Hintergrund platziert werden.
Anschließend soll es nur eine Vertikale Scrollbar geben, mit der über allle Kartenpaare gescrollt werden kann.

ich habe mir dabei gedacht, ich mache mir mehrere Areale, die jeweils ein Panel beinhalten.
Das erste ist das mainpanel, es besitzt ein BorderLayout und stellt also die Wurzel des Objecttrees da.
Das die unterschiedlichen Areale des mainpanels sehen wie folgt aus: center->Karten, south->knöppe.
Daher habe ich im Center das Cardpanel hinzugefügt, welches meinen Hintergrund zeigt.
Davor sollte eigentlich nun eine Komponente liegen, dessen Hintergrund transparent ist und welche die eigentlichen Karten anzeigt, und das zudem scrollbar ist. Um diese Komponente zu realisieren könnte ein JLabel genommen werden, jedoch weiß ich nicht, ob ein JLabel die Kriterien erfüllt, die ich letztlich haben möchte.
 
setSize braucht man "fast nie". Wenn man einen LayoutManager verwendet, sollte alles mit setPreferredSize zu erledigen sein. Insgesamt klingt das, was du beschrieben hast, sehr speziell. Vielleicht würde eine Skizze helfen... :bahnhof:
 
Gute Idee! Aussehen soll es so:

playerscreenshouldbe.jpg


P.S. zudem soll, wie bereits erwähnt, der grüne Hintergrund statisch bleiben.

Update: Ich habe nun den gewünschten Look, jedoch wieder nicht ohne Problem. beim Scrollen und hinzufügen der Karten werden weder das Cardpanel noch der Hintergrund neu gezeichnet. Sprich, es verschwimmt alles.
 
Zuletzt bearbeitet:
OK, zu erreichen, dass dieser Scrollbare Teil in der mitte "schwebt" könnte ein bißchen Fummelig werden - am einfachsen wahrscheinlich durch ein BorderLayout zu erreichen, bei dem das Scroll-Ding im CENTER liegt, und an NORTH, SOUTH, EAST und WEST jeweils ein durchsichtiges JPanel...

Wie hast du das neuzeichnen und so jetzt gemacht, wo du von "verschmieren" redest?
 
Also, ich poste mal die Code ausschnitte, die ich verändert bzw. hinzugefügt habe.

Java:
	private void init() {
		addActionListeners();
		FlowLayout layout = new FlowLayout();
		cardPanel.setLayout(layout);
		cardPanel.setBackground(new Color(100, 100, 100, 0));
		cardPanel.setBorder(null);
		
		scrollpanel.getViewport().add(cardPanel);
		scrollpanel.setBackground(new Color(100, 100, 100, 0));
//		scrollpanel.setViewportBorder(null);
		scrollpanel.setBorder(null);
		scrollpanel.getVerticalScrollBar();
		
		raisamount.setSize(raise.getSize());

		buttons.add(allin);
		buttons.add(flod);
		buttons.add(raise);
		buttons.add(raisamount);
		buttons.add(check);
		
		field.setLayout(new FlowLayout());
		field.add(scrollpanel, BorderLayout.CENTER);
		
		mainpanel.setLayout(new BorderLayout());
		mainpanel.add(field, BorderLayout.CENTER);
		mainpanel.add(buttons, BorderLayout.SOUTH);

		data.add(exit);
		data.setMnemonic('D');
		view.add(show);
		view.setMnemonic('A');
		show.setSelected(true);

		menubar.add(data);
		menubar.add(view);
		menubar.add(help);

		frame.getContentPane().add(mainpanel);
		frame.setLocationRelativeTo(null);
		frame.setIconImage(new ImageIcon(Setup.PATH + "icon.gif").getImage());
		frame.setJMenuBar(menubar);
	}

        @Override
	@Deprecated
	public void run() {
		try {
			init();
			while (isAlive) {
				Card c = cards.take();
				showCard(c);
				updateUI();

			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	private void updateUI(){
		scrollpanel.setHorizontalScrollBar(null);
		FlowLayout layout = (FlowLayout) cardPanel.getLayout();
		cardPanel.setPreferredSize(new Dimension((int) cardSize.getWidth() * 2,
				(int) (cardSize.getHeight() + layout.getVgap())
						* cardPanel.getComponentCount() / 2));
		scrollpanel.setPreferredSize(new Dimension(
				(int) cardSize.getWidth() * 2 + 30,
				(int) cardSize.getHeight() + 10));
		cardPanel.revalidate();
		frame.setVisible(true);
		frame.pack();
	}

sieht dann so aus:


da sieht man auch gut die Schlieren oder das Verschwimmen🙂
 
Ich habe mal auf die schnelle ein KSKB zusammen gerödelt.... nun wenn es mal ein KSKB wäre.
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.util.concurrent.LinkedBlockingQueue;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class Gui extends Thread{
 
	private JFrame frame = null;
	private JScrollPane scroll = null;
	private JPanel componentPanel = null;
	private JImagePanel imagepane= null;
	private LinkedBlockingQueue<JComponent> queue= null; 
	public Gui() {
	}
	
	@Override
	public void run() {
		initGui();
		while(true) {
			JComponent component;
			try {
				component = queue.take();
				showComponent(component);
				updateUI(component);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void initGui() {
		queue = new LinkedBlockingQueue<JComponent>();
		frame = new JFrame("GUI");
		scroll = new JScrollPane();
		componentPanel = new JPanel();
		imagepane = new JImagePanel("./background.png");
		
		FlowLayout layout = new FlowLayout();
		layout.setVgap(50);
		componentPanel.setLayout(layout);
		componentPanel.setBackground(new Color(100, 100, 100, 0));
		componentPanel.setBorder(null);
		
		scroll.getViewport().add(componentPanel);
		scroll.setBackground(new Color(100, 100, 100, 0));
		scroll.setBorder(null);
		
		imagepane.setLayout(new FlowLayout());
		imagepane.setBackground(new Color(100, 100, 100, 0));
		imagepane.add(scroll);
		
		frame.setLayout(new BorderLayout());
		frame.add(imagepane, BorderLayout.CENTER);
		
		
		
		
	}

	public synchronized void showComponent(JComponent component) {
		componentPanel.add(component);
	}
	private void updateUI(JComponent lastcomponent) {
		scroll.setHorizontalScrollBar(null);
		FlowLayout layout = (FlowLayout) componentPanel.getLayout();
		System.out.println(lastcomponent.getPreferredSize().height);
		componentPanel.setPreferredSize(new Dimension(lastcomponent.getPreferredSize().width * 2,
				(int) (lastcomponent.getPreferredSize().height + layout.getVgap())
						* componentPanel.getComponentCount() / 2));
		scroll.setPreferredSize(new Dimension(
				(int) componentPanel.getPreferredSize().width +(layout.getHgap()*2) + scroll.getVerticalScrollBar().getWidth()+2,
				(int) lastcomponent.getPreferredSize().height));
		componentPanel.revalidate();
		frame.setVisible(true);
		frame.pack();
		
	}
	
	public void addComponent(JComponent comp) {
		try {
			this.queue.put(comp);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	
	public class JImagePanel extends JPanel{
		 private Image img;

		  public JImagePanel(String img) {
		    this(new ImageIcon(img).getImage());
		  }

		  public JImagePanel(Image img) {
		    this.img = img;
		    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
		    setPreferredSize(size);
		    setMinimumSize(size);
		    setMaximumSize(size);
		    setSize(size);
		    setLayout(null);
		  }

		  public void paintComponent(Graphics g) {
		    g.drawImage(img, 0, 0, null);
		  }
	}
	
	public static void main(String[] args) {
		Gui g = new Gui();
		g.start();
		for (int i = 0; i < 10; i++) {
			JButton t = new JButton("Button:"+i);
			t.setPreferredSize(new Dimension(100, 100));
			g.addComponent(t);
		}
	}
}

p.S.Was wichtig ist, ist dass der von mir oben beschriebene Effekt auftritt wenn man scrollt.
Die Button verschlirren den Zwischenraum des Layouts.
 
Zuletzt bearbeitet:
Das enthält immernoch den Teil, der bei mir beim "Original" die meisten ???:L :autsch: ???:L 's verursacht hat: Was ist das mit der Queue und dem Thread und dem updateUI denn für ein seltsames Konstrukt? Ich steig' da nicht durch :bahnhof: Sollen die Karten (von einem anderen Thread irgendwie) da reingelegt werden? Was soll der Anlass dafür sein?

Hab mal was gebastelt, vielleicht meinst du ja sowas...?
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.*;
import java.awt.Image;
import java.util.concurrent.LinkedBlockingQueue;

import javax.swing.*;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class GuiBug2 {

    private JPanel cardPairsPanel = null;
    private JScrollPane scrollPane = null;
    private static final int HGAP = 10;
    private static final int VGAP = 10;

    public GuiBug2()
    {
        JFrame frame = new JFrame("GUI");
        frame.setLayout(new BorderLayout());

        JPanel imagePanel = new JImagePanel("image01.png");
        frame.add(imagePanel, BorderLayout.CENTER);

        cardPairsPanel = new JPanel(new GridLayout(0,2,HGAP,VGAP));
        cardPairsPanel.setBorder(
            BorderFactory.createEmptyBorder(0,HGAP,0,HGAP));

        scrollPane = new JScrollPane(cardPairsPanel);
        imagePanel.add(scrollPane);

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

    public void addComponents(JComponent c0, JComponent c1)
    {
        cardPairsPanel.add(c0);
        cardPairsPanel.add(c1);

        int w =
            cardPairsPanel.getPreferredSize().width +
            scrollPane.getVerticalScrollBar().getPreferredSize().width + HGAP;
        int h = Math.max(
            c0.getPreferredSize().height,
            c0.getPreferredSize().height)+VGAP;
        Dimension d = new Dimension(w,h);
        scrollPane.setPreferredSize(d);
        scrollPane.validate();
    }


    public class JImagePanel extends JPanel
    {
         private Image img;

          public JImagePanel(String img)
          {
            this(new ImageIcon(img).getImage());
          }

          public JImagePanel(Image img) {
            this.img = img;
            Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
            setPreferredSize(size);
            setMinimumSize(size);
            setMaximumSize(size);
            setSize(size);
            setLayout(new FlowLayout());
          }

          public void paintComponent(Graphics g)
          {
              super.paintComponent(g);
            g.drawImage(img, 0, 0, null);
          }
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                GuiBug2 g = new GuiBug2();
                for (int i = 0; i < 10; i++)
                {
                    JButton t0 = new JButton("ButtonA:"+i);
                    JButton t1 = new JButton("ButtonB:"+i);
                    t0.setPreferredSize(new Dimension(100, 100));
                    t1.setPreferredSize(new Dimension(100, 100));
                    g.addComponents(t0, t1);
                }
            }
        });
    }
}
 
Ja, ein anderer Thread übergibt der UI die Karten.
Daher ist die UI ein eigenständiger Thread, der selbstständig die Karten in dem Cardpanel anzeigt.

Ich habe mal deinen Code genommen und verändert, wie ich ihn nutzen würde(Hintergrund auf 100% Tranzparenz beim cardPairsPanel und beim scrollPane gesetzt.
Starte den Code, scroll ein wenig rum und du wirst sehen was ich meine.

Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.*;
import java.awt.Image;
 
import javax.swing.*;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
 
public class GuiBug2 {
 
    private JPanel cardPairsPanel = null;
    private JScrollPane scrollPane = null;
    private static final int HGAP = 10;
    private static final int VGAP = 10;
 
    public GuiBug2()
    {
        JFrame frame = new JFrame("GUI");
        frame.setLayout(new BorderLayout());
 
        JPanel imagePanel = new JImagePanel("image01.png");
        frame.add(imagePanel, BorderLayout.CENTER);
 
        cardPairsPanel = new JPanel(new GridLayout(0,2,HGAP,VGAP));
        cardPairsPanel.setBorder(
            BorderFactory.createEmptyBorder(0,HGAP,0,HGAP));
/*Transparenz für cardPairsPanel*/
        cardPairsPanel.setBackground(new Color(100, 100, 100, 0));
        scrollPane = new JScrollPane(cardPairsPanel);
/*Transparenz für scrollPane*/
        scrollPane.setBackground(new Color(100, 100, 100, 0));
        imagePanel.add(scrollPane);
 
        frame.pack();
        frame.setVisible(true);
    }
 
    public void addComponents(JComponent c0, JComponent c1)
    {
        cardPairsPanel.add(c0);
        cardPairsPanel.add(c1);
 
        int w =
            cardPairsPanel.getPreferredSize().width +
            scrollPane.getVerticalScrollBar().getPreferredSize().width + HGAP;
        int h = Math.max(
            c0.getPreferredSize().height,
            c0.getPreferredSize().height)+VGAP;
        Dimension d = new Dimension(w,h);
        scrollPane.setPreferredSize(d);
        scrollPane.validate();
    }
 
 
    public class JImagePanel extends JPanel
    {
         private Image img;
 
          public JImagePanel(String img)
          {
            this(new ImageIcon(img).getImage());
          }
 
          public JImagePanel(Image img) {
            this.img = img;
            Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
            setPreferredSize(size);
            setMinimumSize(size);
            setMaximumSize(size);
            setSize(size);
            setLayout(new FlowLayout());
          }
 
          public void paintComponent(Graphics g)
          {
              super.paintComponent(g);
            g.drawImage(img, 0, 0, null);
          }
    }
 
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                GuiBug2 g = new GuiBug2();
                for (int i = 0; i < 10; i++)
                {
                    JButton t0 = new JButton("ButtonA:"+i);
                    JButton t1 = new JButton("ButtonB:"+i);
                    t0.setPreferredSize(new Dimension(100, 100));
                    t1.setPreferredSize(new Dimension(100, 100));
                    g.addComponents(t0, t1);
                }
            }
        });
    }
}
 
Zuletzt bearbeitet:
Das Hauptproblem mit den Thread ist: ALLE Operationen, die das Aussehen von Swing-Components verändern (oder auf dem Aussehen von Swing-Components basieren) MÜSSEN vom Event-Dispatch-Thread gemacht werden - man kann also nicht mit einem anderen Thread irgendwelche add/remove(Component)-Aufrufe oder LayoutÄnderungen machen. Deswegen hatte ich den Inhalt der main in die SwingUtilities eingewickelt - und die sind auch die Lösung für dieses Problem.

(BTW: Statt mit einer durchsichtigen Farbe zu zeichnen, kann man auch setOpaque(false) machen - vielleicht würde das mit der Farbe aber auch gehen, wenn man sie auch für den ViewPort setzen würde)

Java:
// From [url]http://www.java-forum.org/awt-swing-swt/111447-scrollen-ueber-jpane.html[/url]

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.*;
import java.awt.Image;

import javax.swing.*;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class GuiBug3 {

    private JFrame frame = null;
    private JPanel cardPairsPanel = null;
    private JScrollPane scrollPane = null;
    private static final int HGAP = 10;
    private static final int VGAP = 10;

    public GuiBug3()
    {
        frame = new JFrame("GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());


        JPanel imagePanel = new JImagePanel("bildB.jpg");
        frame.add(imagePanel, BorderLayout.CENTER);

        cardPairsPanel = new JPanel(new GridLayout(0,2,HGAP,VGAP));
        cardPairsPanel.setBorder(
            BorderFactory.createEmptyBorder(0,HGAP,0,HGAP));
        cardPairsPanel.setOpaque(false); /*Transparenz für cardPairsPanel*/
        scrollPane = new JScrollPane(cardPairsPanel);
        scrollPane.setVerticalScrollBarPolicy(
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setOpaque(false); /*Transparenz für scrollPane*/
        scrollPane.getViewport().setOpaque(false); /*Transparenz für scrollPane*/
        scrollPane.setBorder(null);
        imagePanel.add(scrollPane);

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

    public void addComponents(JComponent c0, JComponent c1)
    {
        cardPairsPanel.add(c0);
        cardPairsPanel.add(c1);

        int w =
            cardPairsPanel.getPreferredSize().width +
            scrollPane.getVerticalScrollBar().getPreferredSize().width + HGAP;
        int h = Math.max(
            c0.getPreferredSize().height,
            c0.getPreferredSize().height)+VGAP;
        Dimension d = new Dimension(w,h);
        scrollPane.setPreferredSize(d);
        frame.validate();
        frame.repaint();
    }


    public class JImagePanel extends JPanel
    {
         private Image img;

          public JImagePanel(String img)
          {
            this(new ImageIcon(img).getImage());
          }

          public JImagePanel(Image img) {
            this.img = img;
            Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
            setPreferredSize(size);
            setMinimumSize(size);
            setMaximumSize(size);
            setSize(size);
            setLayout(new FlowLayout());
          }

          public void paintComponent(Graphics g)
          {
              super.paintComponent(g);
            g.drawImage(img, 0, 0, null);
          }
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                createGui();
            }
        });
    }

    // Must be called on EDT
    private static void createGui()
    {
        GuiBug3 g = new GuiBug3();
        startAddingThread(g);
    }

    private static void startAddingThread(final GuiBug3 g)
    {
        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                for (int i = 0; i < 20; i++)
                {
                    addCards(g, i);
                    try
                    {
                        Thread.sleep(500);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
        });
        t.start();
    }

    // May be called from any Thread
    private static void addCards(final GuiBug3 g, final int i)
    {
        System.out.println("Adding "+i);
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                JButton t0 = new JButton("ButtonA:"+i);
                JButton t1 = new JButton("ButtonB:"+i);
                t0.setPreferredSize(new Dimension(100, 100));
                t1.setPreferredSize(new Dimension(100, 100));
                g.addComponents(t0, t1);
            }
        });
    }

}
 
Super! vielen, vielen Dank Marko13. setOpaque(false) statt setBackground(new Color(100, 100, 100, 0)) hat das Problem gelöst.

Danke wirklich!
 

Zurück
Oben