PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Hintergrundfarbe einer einfachen Komponente



McFraggle
16-12-2005, 18:08
Hallo zusammen!
Ich habe eine Minimal-Komponente gebaut indem ich einfach von JComponent abgeleitet habe. Im Konstruktor habe ich mit setBackground(Color) versucht eine Farbe für die Fläche zu setzen. Geht nit. Gleiches habe ich aus einer Testanwendung heraus probiert. Geht auch nicht. Hätte ich nicht die Paint-Methode überschrieben und da einen Strich gezeichnet, würde man das Ding gar nicht sehen!

Wie kann ich für eine eigene Komponente, die direkt von JComponent erbt, eine Hintergrundfarbe setzen???

Danke für jegliche Inspiration!

mwanaheri
16-12-2005, 19:37
Poste doch mal ein Minimalbeispiel

Caveman
16-12-2005, 20:34
setBackground(Color) ist an sich schon richtig, man sollte nur dann darauf achten, dies nicht mit einem JPanel zu überdecken oder man gibt auch diesem eine Hintergrundfarbe.
Auch JLabel, JList usw. überdecken den Hintergrund.

McFraggle
16-12-2005, 21:53
Die kleinste Komponente der Welt:


public class EmptyComponent extends JComponent {
public EmptyComponent(){
super();
setBackground(Color.RED);
setPreferredSize(new Dimension(300,300));
}
}

Und eine kleine Testanwendung:

public class MainFrame extends JFrame{

private JScrollPane sp = null;
private EmptyComponent comp = null;
private JSlider slider = null;

public MainFrame() {

comp = new EmptyComponent();
sp = new JScrollPane(comp);
getContentPane().add(sp, BorderLayout.CENTER);

slider = new JSlider(JSlider.HORIZONTAL,100, 800, 200);
getContentPane().add(slider, BorderLayout.NORTH);

pack();
}

public static void main(String[] args) {
MainFrame mainFrame = new MainFrame();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_ CLOSE);
mainFrame.setVisible(true);
}
}

Wo ist der Denkfehler?:rolleyes:

Caveman
16-12-2005, 22:22
Füge in MainFrame() diese Zeile ein (aus EmptyComponent kann sie dann raus):


sp.setBackground(Color.RED);
und in EmptyComponent() das:


setOpaque(true);

McFraggle
16-12-2005, 23:29
Danke Caveman!

Ich nun jedoch seltsame Erscheinungen beim Scrollen. "Reste" des Randes werden beim Scrollen der Komponente "mitgezogen". Ist jedoch nicht so wichtig, da diese Lösung leider nicht hinreichend für mein Problem ist. Mein Ziel ist ja nicht diese kleine Anwendung (habt ihr euch hoffentlich schon gedacht), sondern eine Komponente, die auch als solche flexibel überall eingesetzt werden soll. Und wenn der Hintergrund der Komponente rot sein soll, dann muss das die Komponent schon selbst erledigen und kann nicht den darüberliegenden Container bzw. Panel dafür heranziehen. Den sollte die Komponente gar nicht kennen müssen.

Noch mehr Ideen? :confused:

Caveman
17-12-2005, 00:40
Das Problem beim Scrollen lässt sich z.B. damit beheben, dass man einen EventListener einbaut und folgende Zeile dort aufruft:

sp.repaint(); Für das andere Problem habe ich gerade auch keine Idee. In der API von SUN gibt es aber ein nettes Tutorial; vielleicht hilft das weiter (hab's selbst nicht gelesen): http://java.sun.com/docs/books/tutorial/uiswing/components/scrollpane.html

Ansonsten könnte es auch damit zusammenhängen, dass die JScrollPane nur leichtgewichtig ist.
Zitat aus der API: "Note that JScrollPane does not support heavyweight components."

McFraggle
17-12-2005, 15:55
Hm, also das Problem ist von JScrollPane ja vollkommen unabhängig. Die Komponente soll prinzipiell beliebig untergebracht werden können. Es geht nur darum eine direkt von JComponent abgeleitete Komponente direkt einzufärben.
Wegen Leichtgewichtigkeit: Meine Komponente ist ja leichtgewichtig! ist ja von JComponent abgeleitet! Wo soll da ein Problem mit Schwergewichtigkeit auftreten?

Caveman
18-12-2005, 18:50
Wegen Leichtgewichtigkeit: Meine Komponente ist ja leichtgewichtig! ist ja von JComponent abgeleitet! Wo soll da ein Problem mit Schwergewichtigkeit auftreten?Hab nicht genauer darüber nachgedacht.

Zum eigentlichen Problem:
Es sollen also JComponenten geschaffen werden, die selbst ihre Farbe bestimmen.
Ich schreibe hier mal den verbesserten Code im Ganzen von EmptyComponent:

package test;

import java.awt.*;
import javax.swing.*;

public class EmptyComponent extends JComponent
{
public EmptyComponent()
{
super();
setBackground(Color.RED);
setPreferredSize(new Dimension(300,300));
setOpaque(true);
}
}
Leider bewirkt die Zeile "setBackground(Color.RED);" nichts :(

:confused: Mir gehen nun selbst die Ideen aus, aber vielleicht kann jemand anderes was dazu sagen. Die Lösung interessiert mich auch.

mwanaheri
19-12-2005, 10:05
Hm, ganz so einfach wird das wohl nichts. Ich zitiere mal aus "Handbuch der Java-Programmierung":

"[...] Für die Darstellung der eigenen Komponente ist dagegen paintComponent zuständig.

protected void paintComponent(Graphics g)

In JComponent wird jeder Aufruf von paintComponent and das ComponentUI der Komponente delegiert. Instanzen dieser im Paket javax.swing.plaf liegenden Klasse spielen in dem von jeder Swing-Komponente implementierten Model-View-Controller-Konzept die Rolle des Views, sond also für die graphische Darstellung der Komponente zuständig. Jede Swing-Komponente besitzt ein ComponentUI, das je nach Looka-and-Feel untershiedlich sein kann. Eine selbstdefinierte Komponente muss also entweder für jedes unterstützte Look-and-Feel ein passendes ComponentUI zur Verfügung stellen oder für die Bildschirmdarstellung durch Überlagern von paintComponent selbst erledigen."

Also: die Komponente selber malen. Dass der Farbwechsel angekommen ist, sieht man übrigens, wenn man die Komponente mit einer Border ausrüstest, z.B.
this.setBorder(BorderFactory.createEtchedBorder()) ;
Dann ist die Farbe plötzlich da, aber eben nur im Rahmen.

McFraggle
19-12-2005, 10:16
Cool! Beim UI war ich mittlerweile auch angekommen. Habe in O'Reillys Swing Buch gerade über den Bau eigener Komponenten gelesen und wollte nachher mal ein Beispiel implementieren. Sollten mir noch Erkenntnisse aufsteigen, melde ich mich... ;)

mwanaheri
19-12-2005, 10:23
Das wäre schön. Wie man nämlich paintComponent am besten überschreibt, habe ich keine Ahnung. Hätte ich aber gern.

McFraggle
19-12-2005, 15:36
Also, ich habe mich heute mehrere Stunden mit dem Kram rumgeschlagen. Ich habe ein etwas umfanfreicheres Beispiel aus genanntem Buch implementiert. Saubere Trennung nach MVC und die UI-Klasse schön brav von ComponentUI abgeleitet. Auch hierbei gilt: setBackground hatte zuerst keinen Effekt. Nachdem hier jedoch nun die Opaque-Eigenschaft auf true gesetzt wurde, ließ sich der Hintergrund durch Setzen von setBackground einfärben.
Langsam erscheint mir das alles durchaus logisch:

- In Swing gilt das MVC-Modell und NICHT die Komponente ist für das Zeichnen zuständig, sondern die der Komponente zugehörige und von ComponentUI abgeleitete UI-Klasse.

- Die Funktionalität des Hintergrund-Malen ist also in ComponentUI implementiert und nicht in JComponent. Möchte man also eine ordentliche Swing-Komponente bauen, sollte man sich an das MVC-Modell halten.

- Das bedeutet wiederum, dass man zum Zeichnen der Komponente weder die paint-Methode noch die paintComponent-Methode von JComponent überschreiben sollte, sondern die paint-Methode der korrespondierenden UI-Klasse! Diese registriert sich in der überschriebenen "installUI"-Methode bei der Komponenten-Klasse als Listener für die relevanten Events, handelt diese und modifiziert das Modell. Die Komponente ist wiederum Listener für das ChangeEvent, welches das Modell dann auslöst. Hier ruft die Komponente "redraw()" auf. Die bei der Komponente gemeldete UI-Klasse wird daraufhin automatisch veranlasst, die Komponente neu zu zeichnen, also die paint()-Methode auszuführen.


War das halbwegs verständlich? Ich bin etwas breiig im Kopf....

Nachtrag:
Der Hintergrund einer Komponente wird in der Methode ComponentUI.update() gezeichnet, falls wenn opaque = false gilt. Diese Methode wird von JComponent.paintComponent() aufgerufen und ruft ihrerseits ComponentUI.paint() auf.