# hintergrundbild für jtable als jscrollpane



## Flaming_Ace (30. Mrz 2010)

Hi,
habe folgendes Problem:
ich hab eine jtable die auf einem jscrollpane liegt. jetzt wollte ich ein hintergrundbild einfügen.
Da die Tabellenzeilen das bild nach und nach (je nachdem wieviel zeilen es gibt) verdecken soll, habe
ich das bild durch die methode paint der klasse jscrollpane eingefügt:

```
public class TableScrollPaneBackground extends JScrollPane{
	// The Image to store the background image in.
    Image img;
    Frm_Main main;
    public TableScrollPaneBackground(Frm_Main main)
    {
        // Loads the background image and stores in img object.
        img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/grafiken/Logo.png"));
        this.main = main;
    }

    public void paint(Graphics g)
    {
        // Draws the img to the BackgroundPanel.
    	Dimension d = getSize();
		for( int x = 0; x < d.width; x += img.getWidth(null))
			for( int y = 0; y < d.height; y += img.getHeight(null) )
				g.drawImage( img, x, y, null, null );
//        super.paint(g);//dann geht nichts mehr
//        this.main.validate();//bringt nix
    }
}
```

die jtable füge ich dann auf das jscrollpane hinzu:

```
scrollPane = new TableScrollPaneBackground(this);
scrollPane.setViewportView(getTableMain());//getTableMain() erstellt eine neue Tabelle
```

Das Bild wird gezeichnet, aber die Tabelle wird zu beginn nicht angezeigt. erst wenn man auf ihr herumklickt.:autsch:
und dabei auch nur die entsprechenden zeilen..
die Scrollbalken werden auch nicht korrekt angezeigt.

hat jemand ne lösung :rtfm: oder eine alternative? danke im vorraus..


----------



## Michael... (30. Mrz 2010)

Mal abgesehen davon, dass man bei Swingkomponenten paintComponent anstelle von paint überschreibt, würde ich mich hüten sowas bei JScrollPane zu machen. JScrollPane ist doch eine relativ komplexe Komponente.
Ich würde ein Überschreiben des Viewports (denn da soll schliesslich das Bild erscheinen) bevorzugen.
Wobei ich mir sicher bin, ob folgendes Bsp nicht doch irgendwie Probleme verursachen kann.

```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;

public class ScrollBackgroundDemo extends JFrame {
	private BufferedImage image;
	public ScrollBackgroundDemo() {	
		JTable table = new JTable(new Object[][] {{"Test"}, {"Test"}}, new String[] {"Titel"});
		image = ScrollBackgroundDemo.createImage();
		JScrollPane scroll = new JScrollPane();
		JViewport view = new JViewport() {
			public void paintComponent(Graphics g) {
				g.drawImage(image, 0, 0, this);
			}
		};
		view.add(table);
		scroll.setViewport(view);
		this.getContentPane().add(scroll);
	}
	
	public static BufferedImage createImage() {
		BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		g.setColor(Color.RED);
		g.fillRect(20, 20, 160, 160);
		g.dispose();
		return image;
	}

	public static void main(String[] args) {
		JFrame frame = new ScrollBackgroundDemo();
		frame.setBounds(0, 0, 250, 150);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
```


----------



## Flaming_Ace (31. Mrz 2010)

viewport oder scrollpane ergeben keine änderung.
jedoch weiß ich jetzt warum das scrollpane das bild nicht angezeigt hat. viewport ist default opaque:
deswegen habe ich folgende änderungen gemacht:

```
public class TableScrollPaneBackground extends JScrollPane{
    private Image img;
    private Dimension d;
    
    public TableScrollPaneBackground()
    {
    	img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/grafiken/HintergrundTabelle.png"));//Bild laden

        getViewport().setOpaque(false);//den Viewport auf durchsichtig stellen

        Dimension dim = new Dimension(img.getHeight(null), img.getWidth(null));//Dimension des bildes holen
        setSize(dim);//panel an bild anpassen
    }

    @Override
    public void paintComponent(Graphics g)
    {
    		//Bildzeichnen
        	d = getSize();
    		for( int x = 0; x < d.width; x += img.getWidth(null))
    			for( int y = 0; y < d.height; y += img.getHeight(null) )//Kachel-Modus.. so dass kein leerer raum entsteht
    				g.drawImage( img, x, y, null );

		//Componenten über das Bildzeichnen
		super.paintComponents(g);
    }
}
```
die einbindung habe ich nicht geändert.
allerdings wird das bild beim ersten anzeigen des fensters nicht gezeigt, erst sobald man die fenstergröße ändert oder ein anderes fenster über das programm gezogen hat.
setze ich den ImageObserver auf "this".. wird das bild beim ersten laden zwar angezeigt, aber nicht korrekt, die komponenten "überlappen"..soll heißen man sieht die oberen komponenten (buttons, menü) nach unten gespiegelt.. ;(


----------



## Michael... (31. Mrz 2010)

Mein Bsp. funktioniert doch. Warum orientierst Du Dich nicht daran?
Mit einer überschrieben paintComponent in der JScrollPane wirst Du vermutlich nie glücklich werden.


----------



## Flaming_Ace (31. Mrz 2010)

ich habs auch mit einem viewport versucht, so wie in deinem beispiel.
dies hat allerdings keine änderungen ergeben, genau die gleichen effekte:

```
public class TableViewPort extends JViewport{
    
	private Image img;
    private Dimension d;
    
    public TableViewPort()
    {
    	img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/grafiken/HintergrundTabelle.png"));//Bild laden
        Dimension dim = new Dimension(img.getHeight(null), img.getWidth(null));//Dimension des bildes holen
        setSize(dim);//viewport an bild anpassen
    }

    @Override
    public void paintComponent(Graphics g)
    {
    		//Bildzeichnen
        	d = getSize();
    		for( int x = 0; x < d.width; x += img.getWidth(this))
    			for( int y = 0; y < d.height; y += img.getHeight(this) )//Kachel-Modus.. so dass kein leerer raum entsteht
    				g.drawImage( img, x, y, this );
		//Componenten über das Bildzeichnen
		super.paintComponents(g);
    }
}
```
Die einbindung hab ich so gemacht:

```
TableViewPort view = new TableViewPort();//
view.add(getTableMain());//liefert die tabelle
scrollPane.setViewportView(view);//
```
wie gesagt: auch mit dieser variante habe ich die gleichen probleme.
außerdem wird dann der tabellenkopf nichtmehr angezeigt.

*update*
wenn ich das bild im viewport zeichne, entsteht der überlappen effekt "nur" bei ungefähr 50% aller programmstarts???:L:shock:


----------



## Michael... (31. Mrz 2010)

wieso rufst Du eigentlich paintComponents(g) auf? Das wird doch eh von der paint() der Komponente aufgerufen.

Hier mal ein Bsp. mit "gekacheltem" Hintergrund, bei mir wird alles - auch der Tabellenkopf - gezeichnet.
Poste vielleicht mal ein KSKB, damit man erkennen kann woran es liegen könnte.

```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;

public class ScrollBackgroundDemo extends JFrame {
	private BufferedImage image;
	public ScrollBackgroundDemo() {	
		JTable table = new JTable(new Object[][] {{"Test"}, {"Test"}}, new String[] {"Titel"});
		image = ScrollBackgroundDemo.createImage();
		JScrollPane scroll = new JScrollPane();
		JViewport view = new JViewport() {
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
				int w = image.getWidth(), h = image.getHeight();
				for (int x=0; x<this.getWidth(); x += w)
					for (int y=0; y<this.getHeight(); y += h)
						g.drawImage(image, x, y, this);
			}
		};
		view.add(table);
		scroll.setViewport(view);
		this.getContentPane().add(scroll);
	}
	
	public static BufferedImage createImage() {
		BufferedImage image = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		g.setColor(Color.RED);
		g.fillRect(5, 5, 10, 10);
		g.dispose();
		return image;
	}

	public static void main(String[] args) {
		JFrame frame = new ScrollBackgroundDemo();
		frame.setBounds(0, 0, 250, 150);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
```


----------



## Flaming_Ace (31. Mrz 2010)

Michael... hat gesagt.:


> wieso rufst Du eigentlich paintComponents(g) auf? Das wird doch eh von der paint() der Komponente aufgerufen.


Wo ruf ich das auf? Zeilennummer im Code?
Den einzigsten unterschied den ich sehe ist das BufferedImage..
werde versuchen ein KSKB zu posten.


----------



## Michael... (31. Mrz 2010)

Flaming_Ace hat gesagt.:


> Wo ruf ich das auf? Zeilennummer im Code?


Zeile 22 in der Klasse TableViewPort


----------



## Flaming_Ace (31. Mrz 2010)

In Zeile 19 von ScrollBackgroundDemo rufst du doch auch super.paintComponents() auf..
allerdings am anfang der methode..
wenn ich diesen aufruf rausnehme hat es keine auswirkungen... ;(

ich habe gerade versucht ein JPanel mit einem hintergrundbild zu erstellen.
auf dieses panel habe ich dann das scrollPane und darauf dann durch viewport die tabelle.
das scrollpane und viewport habe ich auf opaque(false) gesetzt.

die anzeige funktioniert auch, jedoch habe ich wieder den überlappungseffekt. der hängt irgendwie mit ImageObserver zusammen.. wenn ich statt "this" "null" verwende habe ich den überlappungseffekt nicht, aber er zeichnete das bild in diesem fall auch ab und zu nicht.


----------



## Michael... (31. Mrz 2010)

Ich rufe 
	
	
	
	





```
super.paintComponent(g);
```
 auf (ohne *s*), das ist ein kleiner aber feiner Unterschied ;-)
Läuft den mein Bsp. bei Dir? Ansonsten wie gesagt, wäre ein KSKB nicht schlecht.


----------



## Flaming_Ace (31. Mrz 2010)

dein beispiel läuft einwandfrei!

und jetzt hab ich auch den fehler.. Ich habe paintComponent mit paintComponent*s* verwechselt
:lol:

:applaus::applaus::applaus::applaus::applaus::applaus::applaus::applaus:

jetzt funktionieren alle 3 varianten (hintergrundbild im panel/viewport/scrollpane)

für alle, die nicht wissen, wo der unterschied zwischen den zeichenmethoden sind.
Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 17 Grafikprogrammierung



> Grundsätzlich ließe sich auch von JFrame  eine Unterklasse bilden und paint() überschreiben, doch ist das nicht der übliche Weg.
> Stattdessen wählen wir einen anderen Ansatz, der sogar unter AWT eine gute Lösung ist.
> Wir bilden eine eigene Komponente, eine Unterklasse von JPanel (unter AWT Panel, was wir aber nicht mehr weiter verfolgen wollen),
> und setzen diese auf das Fenster.
> ...




 aus javadoc für paintComponents():


> Paints each of the components in this container.


 
 hier noch der korrekte code für das hintergrundBildPanel:

```
public class TablePanelHintergrundbild extends JPanel{
    
	private Image img;
    private Dimension d;
    
    public TablePanelHintergrundbild()
    {
    	img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/grafiken/HintergrundTabelle.png"));//Bild laden
        Dimension dim = new Dimension(img.getHeight(null), img.getWidth(null));//Dimension des bildes holen
        setSize(dim);//panel an bild anpassen
    }

    @Override
    protected void paintComponent(Graphics g)
    {
    	super.paintComponent(g);
    	//Bildzeichnen
        d = getSize();
    	for( int x = 0; x < d.width; x += img.getWidth(this))
    		for( int y = 0; y < d.height; y += img.getHeight(this) )//Kachel-Modus.. so dass kein leerer raum entsteht
    			g.drawImage( img, x, y, this );
    }
}
```
wie gesagt alle Elemente die darüber liegen auf opaque(false) stellen (das wären bei mir scrollPane und ViewPort)

 Vielen vielen Dank an: Michael... !!!


----------

