Swing JColorChooser verstehen

beastofchaos

Bekanntes Mitglied
Hallo Leute,
Ich hab mal wieder ein Problem ( was auch sonst :D ). Und zwar bau ich zur Zeit ein Zeichenprogramm. Um Farben auszuwählen, benutze ich im Moment einen JColorChooser, der im Fenster am rechten Rand liegt, mit einer eigenen Preview, über die ich zwei verschiedene Farben einstellen kann. Im Moment arbeitet das ganze in einem SplitPane, damit ich diese große Vorschau auch ausblenden lassen kann.

Jetzt will ich das Problem eleganter lösen udn einfach selber einen Farbauswähler zusammenbasteln, damit ich es leicht hinkriege, das ganze in der unteren Hälfte als einen kleinen Balken einzubauen.
Grundmodel für die Idee: 1 Klasse "ColorPanel"(extends JPanel), 2 abstrakte Klassen "CChooserModel", "CPreviewModel"(extends JPanel). Und für den Fall, dass keine eigenen Klassen erstellt werden 2 Standard-Klassen "DefaultCChooser", "DefaultCPreview". Auf meinem CChooser will ich nun eine Vorschau von mehreren Farben haben, dafür kamen mir mehrere Fragen:

- (Für den Fall, dass ich einfach ein Bild einfüge: ) Wie ermittle ich die Farbe an einer Position in Graphics? (beantwortet -> new Robot().getPixelColor(x, y);

- (Wenn ich JColorChooser teilweise kopieren will: ) Was meint ihr, wo finde ich den Aufbau von deren "Chooser". Ich hab mir mehrere Klassen durchgeschaut(UIManager, LookAndFeel, JColorChooser, etc.). Auf LookAndFeel kam ich, da bei einem LookAndFeel, das an meinem Laptop-Standard ist, einen anderen Chooser-Aufbau habe, wie ich ihn von meinem Computer-LookAndFeel kenne. Ich hab gehofft, dass ich in LookAndFeels den Chooser finde, was nebenbei warsch. nur zur Laufzeit geht... :/ (also die System-LookAndFeels ermitteln)

- Was bliebe mir noch für eine Variante, um zwischen mehreren Farben wählen lassen zu können ? (viele JButtons wären wohl zu aufwendig...:/)

- Gibt es ein Layout, mit dem ich auf einem (J)Panel zwei Objekte(z.B. noch zwei (J)Panels) so plazieren kann, dass das eine z.B. 2 Drittel einnimmt und das andere das letzte Drittel? Sonst müsste ich das mit Layout null basteln und bei einem WindowResize-Event immer korrigieren lassen müssen :(


Hoffe, ihr könnt mir helfen. Wenn ich zuhause bin, kann ich euch auch gerne das Package rüberschieben, da es noch nicht "viel" Programmcode ist ;)

Gruß, Thomas
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Jetzt will ich das Problem eleganter lösen udn einfach selber einen Farbauswähler zusammenbasteln, damit ich es leicht hinkriege, das ganze in der unteren Hälfte als einen kleinen Balken einzubauen.
Grundmodel für die Idee: 1 Klasse "ColorPanel"(extends JPanel), 2 abstrakte Klassen "CChooserModel", "CPreviewModel"(extends JPanel). Und für den Fall, dass keine eigenen Klassen erstellt werden 2 Standard-Klassen "DefaultCChooser", "DefaultCPreview". Auf meinem CChooser will ich nun eine Vorschau von mehreren Farben haben, dafür kamen mir mehrere Fragen:

Jo, hab' ich auch mal irgendwann gemacht ... mal schauen, ob ich das noch finde, ich glaub das ist auf'm anderen Rechner... So mit ColorPicker und ColorSelectionModel und ColorSelectionListener und so...


- (Für den Fall, dass ich einfach ein Bild einfüge: ) Wie ermittle ich die Farbe an einer Position in Graphics? (beantwortet -> new Robot().getPixelColor(x, y);

NEIN!!! bufferedImage.getRGB(x,y) !!!




- (Wenn ich JColorChooser teilweise kopieren will: ) Was meint ihr, wo finde ich den Aufbau von deren "Chooser".

Das meiste steckt in javax.swing.JColorChooser...



- Was bliebe mir noch für eine Variante, um zwischen mehreren Farben wählen lassen zu können ? (viele JButtons wären wohl zu aufwendig...:/)


Anderen wäre es schon zu aufwändig, einen eigenen ColorChooser zu schreiben ... ;)


- Gibt es ein Layout, mit dem ich auf einem (J)Panel zwei Objekte(z.B. noch zwei (J)Panels) so plazieren kann, dass das eine z.B. 2 Drittel einnimmt und das andere das letzte Drittel? Sonst müsste ich das mit Layout null basteln und bei einem WindowResize-Event immer korrigieren lassen müssen :(

Da kann man oft die "kleinere" Component mit einer passenden PreferredSize in ein BorderLayout.EAST, und die Hauptkomponente ins CENTER. Ansonsten gibt's tausende LayoutManager, die das grundsätzlich könn"t"en...
 

beastofchaos

Bekanntes Mitglied
NEIN!!! bufferedImage.getRGB(x,y) !!!
Um bei Graphics die Farbe an Position zu ermitteln, soll ich also das ganze in ein Bild einbauen und dann per getRGB(x, y) ermitteln? Weder Graphics noch Graphics2D kennen die Methode... :/ Im Moment funktioniert es super mit getPixelColor().

Das meiste steckt in javax.swing.JColorChooser...
Hättest du genauer hingeschaut, hättest du gemerkt, dass ich auch da geschaut habe :p Da es sich bei "jedem" LookAndFeel unterscheidet, wird sich der Aufbau des "Chooser"s / "Picker"s wohl im LookAndFeel verstecken. Und da komm ich wohl nicht ran, oder? Wenn es noch eine Möglichkeit gäbe, das als Quelltext einzusehen, sagt mir bitte Bescheid ;)

Anderen wäre es schon zu aufwändig, einen eigenen ColorChooser zu schreiben ...
Es gibt solche Blödel, die immer bei egal welchem Projekt zu sagen pflegen, ich wolle "das Rad neu erfinden". Dabei gibt es auch heute noch viele Hersteller von Bikes / Fahrrädern, die logischerweise ihre eigenen Fahrräder bauen. Und genauso ist das auch beim Programmieren.
Ich erfinde nicht neu - ich will es bloß besser als die anderen machen ;)

Da kann man oft die "kleinere" Component mit einer passenden PreferredSize in ein BorderLayout.EAST, und die Hauptkomponente ins CENTER. Ansonsten gibt's tausende LayoutManager, die das grundsätzlich könn"t"en...
Naja, das Verhältnis stimmt beim BorderLayout nicht und auch sonst weiß ich nur von ca. 6 Grund-Layouts Bescheid. Also hab ich mir auf die Schnelle ein eigenes Layout gebastelt. In dem kann ich nun perfekt die Proportionen abschätzen und Sachen hinzufügen. Es ist noch nicht fertig, aber im Anhang mal ein Bild, wie das ins Programm dann passen soll :D


Und das Konzept mit den abstrakten Klassen als Grundbausatz ist viel zu mühsam. Lieber schreib ich meinen ColorChooser jedesmal um, anstatt dass ich diesen so anpassungsfähig mache, damit ich ihn öfters gebrauchen kann :p


Jetzt noch eine Frage. Im Bild (im Anhang) werdet ihr sehen, dass ich sogar per Button-Druck einen Dialog aufrufen kann, der ein größeres Farbensprektrum enthält. Eigentlich will ich, dass dieser immer im über dem Grundfenster bleibt, wie es sich für einen Dialog gehört :p Ich hab schon versucht per windowLostFocus() das abzufangen und dann in den Vordergrund zu schieben - ohne Erfolg. Gibt es dafür vll. eine extra Eigenschaft, die das steuert?

Gruß, Thomas
 

Anhänge

  • ColorPanelDemo.jpg
    ColorPanelDemo.jpg
    51,2 KB · Aufrufe: 68
G

Gast2

Gast
Jetzt noch eine Frage. Im Bild (im Anhang) werdet ihr sehen, dass ich sogar per Button-Druck einen Dialog aufrufen kann, der ein größeres Farbensprektrum enthält. Eigentlich will ich, dass dieser immer im über dem Grundfenster bleibt, wie es sich für einen Dialog gehört :p Ich hab schon versucht per windowLostFocus() das abzufangen und dann in den Vordergrund zu schieben - ohne Erfolg. Gibt es dafür vll. eine extra Eigenschaft, die das steuert?

Gruß, Thomas
Der kleine Dialog sollte modal sein und als parent den großen dialog gesetzt haben.
 

Marco13

Top Contributor
NEIN!!! bufferedImage.getRGB(x,y) !!!
Um bei Graphics die Farbe an Position zu ermitteln, soll ich also das ganze in ein Bild einbauen und dann per getRGB(x, y) ermitteln? Weder Graphics noch Graphics2D kennen die Methode... :/ Im Moment funktioniert es super mit getPixelColor().

Du hattest schon von einem Bild geredet. Und BufferedImage kennt "getRGB(x,y)". Ansonsten poste mal ein bißchen Code.



Wenn es noch eine Möglichkeit gäbe, das als Quelltext einzusehen, sagt mir bitte Bescheid ;)


Im "src.zip" vom JDK sollte das alles liegen. Wenn du's nicht findest (oder der Code zu konfus wirkt, was gut sein kann) schau' ich bei Gelegenheit nochmal
 

beastofchaos

Bekanntes Mitglied
@Eike:
Ok, dankeschön - mit "setModel(true)" funktioniert es. Nebenbei, was meinst du mit Parent?


@Marco:
Ich kann über NetBeans zwar den Quelltext von JColorChooser sehen*, aber der enthält nicht den Aufbau des Choosers. Wenn ich zum Beispiel nach dem WindowsLookAndFeel suchen würde... Der liegt in der JDK nicht drinnen.
*(bloß bei Eclipse kann ich iwie solche Klassen nicht einsehen - iwas muss ich da noch einstellen(?))

Und mit Bild meine ich, dass ich jetzt nicht mit Buttons arbeite, sondern am Anfang aus einem Bild lade und das halt in einem JPanel zeichnen lasse. Und aus diesem will ich bei mousePressed lesen.

Hier das Event:
Java:
private class ReadColorMouseAction extends MouseAdapter{
        @Override
        public void mousePressed(MouseEvent evt){
            Point p= new Point(evt.getX(), evt.getY());
            if ((p.x <= chooser.getX() || p.x >= chooser.getX() + chooser.getWidth() - 1 ||
                p.y <= chooser.getY() || p.y >= chooser.getY() + chooser.getHeight() - 1) &&
                   (p.x <= preview.getX() || p.x >= preview.getX() + preview.getWidth() - 1||
                    p.y <= preview.getY() || p.y >= preview.getY() + preview.getHeight() - 1)){
                       return;
            }  // Das Muss ich abfragen, weil er nicht nur im CChooser arbeiten soll, sondern damit das auch bei der CPreview funktioniert.

            Color selectedColor;
            selectedColor = chooser.readColor(evt);
            if (evt.getButton() == MouseEvent.BUTTON1){
                ColorPanel.this.setFirstColor(selectedColor);
            }
            else if (evt.getButton() == MouseEvent.BUTTON3){
                ColorPanel.this.setSecondColor(selectedColor);
            }
        }
    }

Im CChooser liegt diese Methode:
Java:
protected Color readColor(MouseEvent evt) {
        Color colorAtCursorPos = Color.black;
        try{
            colorAtCursorPos = new Robot().getPixelColor(evt.getXOnScreen(), evt.getYOnScreen());
        } finally{
            return colorAtCursorPos;
        }
    }
 

Marco13

Top Contributor
Wenn man bei Eclispe draufklickt, und er es nicht findet, ist da ein Button "Change source location" oder so. Da kann man dann "External file" auswählen, und zur "src.zip" aus dem JDK-Verzeichnis browsen. Dann sollte er den finden.

Ist im CChoser nicht das Bild bekannt? Dann könnte man da sowas machen wie
Code:
protected Color readColor(MouseEvent evt) {
{
    return new Color(bufferedImage.getRGB(evt.getX(), evt.getY()));
}
 

beastofchaos

Bekanntes Mitglied
Ok, bei Eclipse funkts nun auch :p danke

Und ich lade es am Anfang, aber zeichne das einmal in die Graphics und dispose es dann. Ein Image ist doch nebenbei auch ressourcenverschwenderischer, als dass ich einfach das in den Graphics habe.
Und was ist eigentlich das falsche daran, wenn ich getPixelOnScreen, benutze?
 

Marco13

Top Contributor
"Disposen"? Das Bild muss doch ohnehin bei jedem neuzeichnen nue gezeichnet werden, da kann man es ja sowieso nicht wegwerfen!?

Aus Robot (Java Platform SE 6) :
This class is used to generate native system input events for the purposes of test automation, self-running demos, and other applications where control of the mouse and keyboard is needed. The primary purpose of Robot is to facilitate automated testing of Java platform implementations.

Nirgendwo ein Satz wie "... and to obtain the Pixel Color for a custom Color-Chooser" :D

Im Ernst: Robot ist für sowas einfach nicht gedacht, das als "Hack" zu beichnen wäre noch sehr zurückhaltend...
 

beastofchaos

Bekanntes Mitglied
Ich zeichne es nur einmal und nie wieder, weil repaint() nie aufgerufen wird (warum auch :p )

Aber ich habe noch ein paar Ideen für den Chooser und da müsste ich den auch öfters repainten... Also ja ich werd das Bild lassen und von dort die Farbe auslesen.

Aber ich hab ja noch die Preview, in der ich zwei JLabels für die beiden ausgewählten Farben habe. Aber ich wollte das "Feature" einbauen, dass man auch da draufklicken kann, auuch wenn es vll. nicht viel bringt. Vll mach ich es auch wieder zurück, aber wie soll ich das da auslesen? In dem ich schau (per if-Abfrage), auf welchem JLabel die Maus gerade ist und dann mit getBackground() auslesen?

Rein theoretisch ist es also nicht möglich die Farbe an einer Position in Graphics(2D) auszulesen - schade??
 

Fu3L

Top Contributor
Rein theoretisch ist es also nicht möglich die Farbe an einer Position in Graphics(2D) auszulesen - schade??

Nein, denn das Graphics Object ist metaphorisch gesehen nur der Pinsel.

Ich zeichne es nur einmal und nie wieder, weil repaint() nie aufgerufen wird (warum auch :p )

Was sit, wenn dein Fenster von einem anderen Fenster teilweise verdeckt oder verschoben wird?

Aber ich hab ja noch die Preview, in der ich zwei JLabels für die beiden ausgewählten Farben habe. Aber ich wollte das "Feature" einbauen, dass man auch da draufklicken kann, auuch wenn es vll. nicht viel bringt. Vll mach ich es auch wieder zurück, aber wie soll ich das da auslesen? In dem ich schau (per if-Abfrage), auf welchem JLabel die Maus gerade ist und dann mit getBackground() auslesen?

Wie wäre es mit einem addMouseListener() ? Irgendwie wird dein Label ja auch wissen müssen, welche Farbe es anzeigt, also sollte man da auch rankommen können.. (zB mit MouseEvent.getSource())
 

beastofchaos

Bekanntes Mitglied
Du hast gewonnen :D er zeichnet es immer neu^^

Naja, der MouseListener ist im ColorPanel, das heißt (wenn ihr euch mal das bild kurz anschaut), dass es auf die ganze untere Leiste reagiert. Ob die Maus im Chooser ist, frag ich dann halt per if-Abfrage ab und, ehrlich gesagt, möchte ich es lieber so umständlich, als für beide bzw. alle drei(2 JLabels) Objekte jeweils einen MouseListener zu machen. Das Problem sollte weiterhin kein Problem mehr sein.

btw: Ich bin gerade auf das Problem gestoßen, wie ich aus einem Image ein rundes SubImage ermittle ("Bufferd.getRoundSubImage(x, y, width, height)"? :/ )

btw²: In meinem Layout, hab ich nun die beiden Preview-Labels übereinander gesetzt, wie man es von Paint/Gimp usw. kennt. Das sekundäre Label soll immer im Hintergrund sein und wenn man draufklickt, soll seine Farbe mit dem vorderen getauschten werden. Leider schummelt sich das Label dabei immer vor das andere. Das selbe passiert auch, wenn ich mit einem Rechtsklick auf den Chooser klicke. Offensichtlich wird, wenn ich die Farbe ändere, das Teil fokussiert. Kann ich iwie das eine Label vor dem anderen im Vordergrund halten?
 
Zuletzt bearbeitet:

Fu3L

Top Contributor
Ist dieses runde Subimage unbedingt nötig? Vllt ein Rechteck nehmen und dann später davon nur einen Kreis anzeigen?

Zu deinem zweiten Problem kann ich leider nichts sagen.. Mir fiele nur requestFocus() ein, aber das würde sich ja GUI-weit auswirken und nich nur zwischen den beiden für "Rangordnung" sorgen^^
 

Michael...

Top Contributor
btw: Ich bin gerade auf das Problem gestoßen, wie ich aus einem Image ein rundes SubImage ermittle ("Bufferd.getRoundSubImage(x, y, width, height)"? :/ )
Ein Image ist immer rechteckig, aber man kann mit Hilfe der AlphaComposites den Kreisausschnitt eines Bildes zeichnen.
btw²: In meinem Layout, hab ich nun die beiden Preview-Labels übereinander gesetzt, wie man es von Paint/Gimp usw. kennt. Das sekundäre Label soll immer im Hintergrund sein und wenn man draufklickt, soll seine Farbe mit dem vorderen getauschten werden. Leider schummelt sich das Label dabei immer vor das andere. Das selbe passiert auch, wenn ich mit einem Rechtsklick auf den Chooser klicke. Offensichtlich wird, wenn ich die Farbe ändere, das Teil fokussiert. Kann ich iwie das eine Label vor dem anderen im Vordergrund halten?
Warum die Krücke mittels Label und Layout warum nicht eine eigene Komponente verwenden und das selbst zeichnen?
Ansonsten: Was soll man ohne Quellcode dazu sagen?
 

beastofchaos

Bekanntes Mitglied
@Fu3L:
"requestFocus()" bewirkt da leider gar nichts :/

@Michael:
1. Ich denke mit AlphaComposite kann ich nur über etwas drüber malen. Das wäre, wie wenn man mit einem Bleistift ohne Mine, versucht bei einem Bild nur einen Kreis rauszumalen... Kanns du mir dafür ein Beispiel geben(Quellcode)?

2. Das Layout ist wohl ganz das Gegenteil einer Krüke. Schließlich läasst sich das Fenster beliebige verändern und ich hab kein Problem. Aber offensichtlich muss ich wohl bei meinem ColorPanel einiges wieder löschen(1,5 Wochen Arbeit...). Damt ich aus den beiden Labels nur eines mache, bei dem ich zwei Rechtecke male. Muss ich halt wieder eine neue Klasse erstelle :/

edit: So, ich hab jetzt ohne viele Veränderungen es geschafft, dass in meiner Preview(in der eigentlich die beiden Labels für die beiden Farben liegen) einfach Rechtecke gezeichnet werden mit den entsprechenden Farben. Ein Problem gäbe es jetzt aber schon wieder... :/ Und zwar wird der Hitnergrund jetzt weiß (siehe Bild). Das passiert auch, wenn ich nicht am Anfang von paintComponent() clearRect benutze. Wie schaffe ich es, dass er dich wirklich durchsichtig macht?
 

Anhänge

  • colorPanelPreviewError.png
    colorPanelPreviewError.png
    3,4 KB · Aufrufe: 37
Zuletzt bearbeitet:

Michael...

Top Contributor
Und zwar wird der Hitnergrund jetzt weiß (siehe Bild). Das passiert auch, wenn ich nicht am Anfang von paintComponent() clearRect benutze. Wie schaffe ich es, dass er dich wirklich durchsichtig macht?
Was verwendest Du als Basis Komponente? JPanel und JComponent sind im Standard transparent und es reicht ein Aufruf von super.paintComponent(...) oder clearRect(...) am Anfang der paintComponent
@Michael:
1. Ich denke mit AlphaComposite kann ich nur über etwas drüber malen. Das wäre, wie wenn man mit einem Bleistift ohne Mine, versucht bei einem Bild nur einen Kreis rauszumalen... Kanns du mir dafür ein Beispiel geben(Quellcode)?
Ja. So ganz grob beschrieben, kann man mit den AlphaComposites festlegen, wie Farbwerte beim "übermalen" miteinander verrechnet - quasi gemischt - werden.
Um ein rundes Bild zu malen zeichnet man auf ein transparentes (rechteckiges) Bild einen Kreis.
Nun kann man - mit entsprechend gesetzen Composites - das eigentliche Bild über den Kreis malen und der transparente Bereich bleibt transparent und der Kreis wird durch das Bild übermalt.
Hier ein Bsp dazu. Damit es per Copy&Paste ausführbar ist wird statt ein Bild zu laden mit
Code:
createSimpleImage(int w, int h)
ein Dummy Bild erzeugt. Das erstellen des "runden" Bildes passiert in
Code:
createDemoImage(Image img, boolean round)
Java:
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class RoundImageDemo extends JFrame {
	private Image image;
	private Image paintedImage;

	public RoundImageDemo() {
		image = RoundImageDemo.createSimpleImage(100, 100);
		paintedImage = createDemoImage(image, false);
		final JPanel panel = new JPanel() {
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
				//Zur Demo, damit man sieht, dass tatsächlich ein rundes Bild gemalt wird
				Graphics2D g2 = (Graphics2D)g.create();
				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				for (int y=10; y<this.getHeight(); y+=15)
					g2.drawString("Dies ist ein Test! Dies ist ein Test!", 10, y);
				g2.dispose();
				//Demo Ende
				
				g.drawImage(paintedImage, 30, 30, null);
			}
		};

		final JCheckBox check = new JCheckBox("round image");
		this.getContentPane().add(panel, BorderLayout.CENTER);
		this.getContentPane().add(check, BorderLayout.SOUTH);

		check.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				paintedImage = createDemoImage(image, check.isSelected());
				panel.repaint();
			}
		});
	}

	private BufferedImage createDemoImage(Image img, boolean round) {
		int w = img.getWidth(null);
		int h = img.getHeight(null);
		BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = newImage.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		if (round) {
			g.fillOval(0, 0, w, h);
			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN));
		}
		g.drawImage(img, 0, 0, null);
		g.dispose();
		return newImage;
	}

	public static BufferedImage createSimpleImage(int w, int h) {
		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		g.setColor(Color.BLUE);
		g.fillRect(0, 0, w, h);
		g.setColor(Color.YELLOW);
		g.setStroke(new BasicStroke(10));
		g.drawLine(0, 0, w, h);
		g.drawLine(w, 0, 0, h);
		g.dispose();
		return image;
	}

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

beastofchaos

Bekanntes Mitglied
Also ich benutze ein JPanel für die Preview. Hier mal die paintComponent()-Methode davon:

Java:
    private JLabel colorA;
    private JLabel colorB;

    ... //Konstruktor, etc.

    @Override
    public void paintComponent(Graphics g){
        g.clearRect(0, 0, getWidth(), getHeight());
        Dimension d = this.getSize();
        
        Rectangle rectA = new Rectangle(d.width / 4, 0 , d.width / 4 * 3 - 1, d.height / 4 * 3);
        colorA.setBounds(rectA);
        Rectangle rectB = new Rectangle(0, d.height / 4, d.width / 4 * 3 - 1, d.height / 4 * 3);
        colorB.setBounds(rectB);
        
        g.setColor(colorB.getBackground());
        g.fillRect(rectB.x, rectB.y, rectB.width, rectB.height);
        g.setColor(Color.black);
        g.drawRect(rectB.x, rectB.y, rectB.width, rectB.height);
        
        g.setColor(colorA.getBackground());
        g.fillRect(rectA.x, rectA.y, rectA.width, rectA.height);
        g.setColor(Color.black);
        g.drawRect(rectA.x, rectA.y, rectA.width, rectA.height);
    }

Und dankeschön schonmal für den Queeltext, werd ihn mir dann "morgen" anschaun, wenn ich meine Augen wieder richtig aufbekomm :p
 

Marco13

Top Contributor
clearRect sollte man nicht verwenden. Dort sollte stattdessen nur
super.paintComponent(g);
stehen. Ggf. mal
this.setOpaque(false);
im Konstruktor dieser Klasse aufrufen.

BTW: label.setBounds(x,y,w,h) IN der paintComponent aufrufen ist ganz, ganz schlecht: Ein setBounds bewirkt u.U. wieder ein neuzeichnen, d.h. einen erneuten Aufruf von paintComponent. Das setBounds ist eine Layout-Sache, und sollte woanders (ggf. von einem LayoutManager) gemacht werden.
 

Michael...

Top Contributor
Was wäre, wenn ich die beiden Labels unsichtbar mache(Visible = false). Dann sollten die paintComponent doch cniht wieder aufrufen?
Versteh nicht, was damit gemeint ist?

Da Du ja sowieso selbst zeichnest, werden die zwei Labels doch garnicht mehr benötigt (abgesehen davon dass sie auch nicht dargestellt werden) nimm Doch direkt Color Objekte zum Speichern der Farben.
 

beastofchaos

Bekanntes Mitglied
Ein Image ist immer rechteckig, aber man kann mit Hilfe der AlphaComposites den Kreisausschnitt eines Bildes zeichnen.

So, ich hab jetzt mal deine Demo angeschaut. Funktioneirt super - Großes Dankeschön ;)

Bloß wozu ist diese Zeile?
[JAVA=56]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
[/code]
Wenn ich das auskommentiere, verändert sich im Gesamtbild nichts. Aber zumindest hab ich schonmal verstanden, wie das andere geht...

Du zeichnest erst mit einer belieigen Farbe(deswegen nicht gesetzt) auf ein "leeres" Bild einen Kreis. Durch die Composite-Einstellung wird eine Eigenschaft gesetzt, dass wenn jetzt nochwas drauf gemalt wird, die leeren Stellen(um den Kreis herum) leer bleiben, der Rest aber wird bemalt.
Wenn man bei der Composite-Setzung "AlphaComposite.SRC_OUT", funktioniert das ganze andersrum :D

Richtig verstanden? ^-^

Gruß, Thomas
 

Michael...

Top Contributor
[JAVA=56]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
[/code]
Wenn ich das auskommentiere, verändert sich im Gesamtbild nichts.
Hiermit wird die Kantenglättung aktiviert. Das wird in dem Bsp. Code zweimal gemacht einmal beim Erzeugen des Bildes (Zeile 56) und beim Zeichnen in der Komponente (Zeile 29). Wenn Du beides auskommentierst (eigentlich sollte auch nur Zeile 56 ausreichen) und eventuell den Text im Hintergrund weglässt, sollte man den Unterschied sehen.
Du zeichnest erst mit einer belieigen Farbe(deswegen nicht gesetzt) auf ein "leeres" Bild einen Kreis. Durch die Composite-Einstellung wird eine Eigenschaft gesetzt, dass wenn jetzt nochwas drauf gemalt wird, die leeren Stellen(um den Kreis herum) leer bleiben, der Rest aber wird bemalt.
Wenn man bei der Composite-Setzung "AlphaComposite.SRC_OUT", funktioniert das ganze andersrum :D

Richtig verstanden? ^-^
Ja, SRC_OUT wirst Du ja sicherlich ausprobiert haben.
Bei den Farbermittlung/definition per Composite, werden ursprüngliche Farbe(1) und hinzugefügte Farbe(2) per Gewichtung miteinander verrechnet:
FarbeNeu = Farbe1*Alpha1*Gewichtung1 + Farbe2*Alpha2*Gewichtung2
AlphaNeu = Alpha1*Gewichtung1 + Alpha2*Gewichtung2

Bei SRC_IN ist Gewichtung2=Alpha1 und Gewichtung1=0
==> FarbeNeu = 0 + Farbe2*Alpha2*Alpha1
==> AlphaNeu = 0 + Alpha2*Alpha1
Bei Hinzufügen eines komplett nicht transparenten Bildes ist Alpha2 konstant 1
==> FarbeNeu = Farbe2*Alpha1
==> AlphaNeu = Alpha1
Damit bleibt das neu gezeichnete Bild überall wo das ursprünglich Bild transparent war transparent und an den bereits "belegten" Pixeln wird die neue Darstellung entsprechend des "neuen" Farbwertes und der "alten" Transparenz berechnet.
 

beastofchaos

Bekanntes Mitglied
So, jetzt hab ich wieder einen Fehler gefunden. Da ich in meinem Programm alles auf ein einziges Bild male, zeichne ich nur das immer neu. Um die letzte gemacht Zeichnung auch ändern zu können, hab ich aber auch noch ein Objekt(Design) namens 'actual', welches Linien, Kreise oder Rechtecke zeichnen kann. Sobal etwas neues gezeichnet wird, wird 'actual' dem Bild hinzugefügt und entsprechend dem neuen Objekt verändert...jetzt hab ich euch shconmal Hintergründe geben können:

Leider funktioniert das Glätten aber nicht, wenn ich auf das Image zeichne... Hier mal die "add()"-Methode der Klasse ImageDesign, mit der 'actual' dem Image hinzugefügt wird:

Java:
    public void add(Design newDesign){
	    try {
		    newDesign.draw(getImage().getGraphics());
	    } catch (NullPointerException e){
		    System.out.println("NullPointerException at  /ImageDesign - add(Design newDesign)/ ");
	    }
	}

Design ist eine Überklasse. Von ihr stammen "LineDesign", "ShapeDesign" und "ImageDesign" ab.

Die draw-Methode vom LineDesign als Beispiel sieht dann so aus:
Java:
@Override
	public void draw(Graphics g) {
		super.draw(g);
		g.setColor(getColor());
		g.drawLine(getLocation().x, getLocation().y, 
				   getLocation().x + getSize().x, getLocation().y + getSize().y);
	}

Im ImageDesign.draw(...) steht dann nur "drawImage(...)"... Die Graphics, die da übergeben werden, kommen von dem JPanel, auf dem ich zeichne. In paintComponent() wird das ImageDesign und actual auf die Weise gezeichnet. Bevor ich das zeichne, kommt dann deine tolle Methode "g.setRenderingHint(...)". Bloß wieso wirkt sich das nur auf 'actual' aus?
Ich dachte, ich müsste dann, bevor ich 'actual' dem Image hinzufüge die Methode auch benutzen, da ich da die Graphics des Images benutze... Aber auch dann funktioniet das ganze nicht... :/


Edit: Vergesst die ganze Sache - liegt nicht an Java. Hab zumindest rausgefunden, dass iwo in meine Quelltext der Fehler liegen muss. Aber danke für eure Aufmerksamkeit :p
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Habs jetzt nicht so gaaanz nachvollzogen, aber bei
newDesign.draw(getImage().getGraphics());
wird ein "neues" Graphics erstellt. Das sollte man i.a. explizit machen, und auch wieder disposen. Eine NullPointerException abzufangen ist übrigens allgemein eher Unfug. Eine NPE ist ein Programmierfehler. (Aber vielleicht war's ja nur für's debugging).

Java:
public void add(Design newDesign){
    Graphics2D g = getImage().createGraphics();
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    try {
        newDesign.draw(g);
    } finally {
        g.dispose();
    }
}
 

Michael...

Top Contributor
Die Graphics, die da übergeben werden, kommen von dem JPanel, auf dem ich zeichne.
Meinst Du hier wirklich JPanel? Niemals versuchen über getGraphics() an das Graphics Objekt einer Komponente zu kommen. Bei Komponenent nutzt man nur das Graphics Objekt in der überschriebenen paintComponent.
Auf Images ruft createGraphics um auf diese zu Zeichnen.
Bevor ich das zeichne, kommt dann deine tolle Methode "g.setRenderingHint(...)". Bloß wieso wirkt sich das nur auf 'actual' aus?
Ich dachte, ich müsste dann, bevor ich 'actual' dem Image hinzufüge die Methode auch benutzen, da ich da die Graphics des Images benutze... Aber auch dann funktioniet das ganze nicht... :/
Das verstehe ich nicht so ganz? Graphics ist ein simples Hilfsobjekt mit dem man zeichnen kann - wie und was das muss man definieren. Das Bild ist bereits gezeichnet ob mit oder ohne Kantenglättung ist egal, wenn man sich ein Graphics zum Zeichnen auf dem Bild holt. Das Bild hat ja in dem Sinne kein Gedächtnis.
 

beastofchaos

Bekanntes Mitglied
@Michael: Das ist mir klar, deswegen hab ich den Fehler darin vermutet, dass die "Zeichenobjekte" nicht geglättet auf das Image gezeichnet werden.

@Marco: Danke. Das könnte der Fehler sein. Werde das mal ausprobieren... Und ja, es war nur wegen Debugging ;) Meine "Fehelrmeldung" ist schließlich nur Quatsch^^

edit: Danke Marco - es funktioniert einwandfrei so wie ich es mir gewünscht habe :D
 
Zuletzt bearbeitet:

beastofchaos

Bekanntes Mitglied
Jetzt muss ich darauf zurück kommen, wie man eine Farbe an einer Position eines Bildes ausliest.
So wird am Anfang das Bild initialisiert:
Java:
        Image img = new ImageIcon(getClass().getResource("shortView.png")).getImage();
        imgColors = new BufferedImage(img.getWidth(this),img.getHeight(this), BufferedImage.TYPE_INT_RGB);
        imgColors.createGraphics().drawImage(img, 0, 0, null);

Und zum Auslesen sieht das dann bei mir aus, weil ich keine Ahnung habe, wie ich aus dem Integer eine Farbe bastle:

Java:
@SuppressWarnings("finally")
	protected Color readColor(MouseEvent evt) {
        Color colorAtCursorPos = Color.black;
        try{
            colorAtCursorPos = new Color(imgColors.getRGB(evt.getX(), evt.getY()));
        } finally{
            return colorAtCursorPos;
        }
    }

Wie funktioniert das mit dem getRGB? Denn im Moment bekomme ich nur eine schwarze Farbe als Antwort :/

Gruß, Thomas
 

beastofchaos

Bekanntes Mitglied
Nein, denn das fang ich doch mit try-finally ab, oder fängt finally sowas gar nicht ab?
ich kommentier das mal aus und probiers nochmal

..

Okay, deiner bzw. auch mein Verdacht haben sich bestätigt: Das Bild sitzt schließlich nicht an den Koords (0,0), weshalb sich eine kleine Veränderung einschiebt und eine Exception geworfen wird :/

Danke :D


edit: Hatte jetzt immer noch ein paar Probleme, bis mir auffiel, dass das Image ja ne ganz andere Größe, als das Panel hat, aber ich es in paintComponent immer nur passend zu zeichne. Jetzt habe ich ein zweites Image erzeugt, aus dem ich die Farbe auslese und auch auf dem ich das Bild zeichne. In paintComponent, muss ich dann bloß die Größe von dem Bild ändern, damit es so grß wie das Panel ist.

->
Java:
 @Override
    public void paintComponent(Graphics g){
        Graphics2D g2d = (Graphics2D)g;
        contentImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        contentImage.createGraphics().drawImage(imgColors, 0, 0, contentImage.getWidth(), contentImage.getHeight(), null);
        g2d.drawImage(imgColors, 0, 0, CChooser.this.getWidth(), CChooser.this.getHeight(), null);
    }

Gruß, Thomas
 
Zuletzt bearbeitet:

beastofchaos

Bekanntes Mitglied
dispose()! - mach ich noch ;)

Aber das mit dem Bild. Anders gehts nicht. Schließlich verändert sich die Größe des Bildes beim Vergößern/Verkleinern des Fenster auch. Hab überlegt, aber weißt du vll. sonst, wie ich bei einem Image die Größe veränder, ohne Konstruktor aufzurufen und den Inhalt dabei zu zerstören... :/

Habe jetzt alles letztenendes (zum Verständnis) zwei Bilder - das anfangs geladene Bild und einmal das Bild, dass bei jeder repaint() die Größe des Panels annimmt und das Originalbild in "sich" zeichnet.
 

Marco13

Top Contributor
Ein übliches Muster für diesen Fall (das früher für double buffering verwendet wurde) ist sowas wie
Code:
private BufferedImage image = null;
void paintComponent(...)
{
    if (image==null || (image.getWidth() != getWidth() || image.getHeight() != getHeight())
    {
        image = new BufferedImage(getWidth(), getHeight(), ...);
    }
    paintStuffInto(image);
}
Also das Bild NUR erstellen, wenn es noch nicht erstellt wurde oder sich die Größe geändert hat. Neu gezeichnet wird potentiell VIIIEEEL öfter, als das Fenster skaliert wird...

Unabhängig davon bin ich mir nicht sicher, ob das mit den zwei Bildern dort überhaupt Sinn macht. Aber das kann ich mangels Übersicht über das Problem und die "übergeordnete" Struktur nicht auf die Schnelle wirklich beurteilen.
 

beastofchaos

Bekanntes Mitglied
Ok, dasmit der If-Abfrage wird sicher einiges einsparen, aber auc hwenn du den ganzen Hitnergrund nicht weißt:
Es ist nicht anders möglich, als ein Original-Bild und eine immer von der Größe angepasste Version davon zu haben.

edit: noch ein Problem - wie kann ich an einer Stelle Zeichnungen löschen. Soll heißen, eine Art Radiergummi. Habe mal einen brauchbaren Thread gefunden: www.tutorials.de
Bloß leider funktioniert die Lösung dort nicht:

Java:
	g2d.drawLine(0, 0, 200, 200); //zeichne Linie
	g2d.setColor(new Color(0x000000,true));
	g2d.setComposite(AlphaComposite.Src);
	g2d.drawLine(0, 0, 200, 200); //Linie wird wieder transparent

Bei mir sieht man dann eine schwarze Linien :/
 
Zuletzt bearbeitet:

beastofchaos

Bekanntes Mitglied
Weiß denn keiner hier, wie ich eine Stelle meines JPanel unsichtbar machen kann?
Es handlet sich dabei um zwei gleichgroße JPanels. Das oberere ist 'opaque = false' und zeichnet ein Bild, welches die Größe des Panels enthält. Wenn ich nun in meinem Programm eine Radiererfunktion basteln will, die per "drawLine()" Stellen unsichtbar macht, wie muss ich die Composite/ Farbe/ etc. verändern?
 

Marco13

Top Contributor
Ein paar Stack-Level weiter hoch: Du willst einen ColorChooser schreiben. Was (zur H*lle) du da mit BufferedImages in verschiedenen Größen und Radiergumis und Alpha und so machen willst, kann keiner nachvollziehen. Wenn du eine konkrete Frage hast, schreibe einen Beitrag, klicke dann auf "Vorschau", lies' dir durch, was du da geschrieben hast, und überlege dann, ob jemand, der diesen Beitrag liest, verstehen könnte, was du damit meinst.
 

beastofchaos

Bekanntes Mitglied
Mir ist in den letzten Post auch immer mehr bewusst geworden, dass von dem Thema "ColorChooser" gar nicht mehr die rede ist. Das soltle nur eine Komponente meines Programms sein. Da ich immer wieder Problem und Fragen bei meinem Programm habe: Sollte ich vll. NOCH einen Thread erstellen, in dem ich alle weiteren Fragen zusammenpacke?
Da entferne ich mich wenigstens nicht vom Thema :)
 

beastofchaos

Bekanntes Mitglied
Doch :p
Bevor ich überhaupt meinen Radiergummi machen wollte, wollte ich es schaffen, dass ich eine Stelle per "Delete" oder über Ausschneiden(Strg-X) unsichtbar machen kann. Hatte gestern noch rumprobiert und es dann selbst hinbekommen.
Ich glaube aber, dass, wenn ich bei meinem Radiergummi gleich vorgehe, wie bei der da vorgestellten Lösung, wird das sehr Performanz aufwendig. Denn im Grunde genommen kann man gar nicht mit so einem Modus zeichnen. In Wahrheit wird ein neues Bild erstellt vom Type "TYPE_INT_ARGB" erstellt. Auf dem zeichne ich dann eine Fläche, was verschwinden soll. Dann setze ich die Composite entsprechend und zeichne vom alten Bild alles drüber.
Java:
    	BufferedImage oldImg = main.centerPanel.paints.getImage();
    	BufferedImage newImg = new BufferedImage(oldImg.getWidth(), oldImg.getHeight(), BufferedImage.TYPE_INT_ARGB);
    	
    	Graphics2D g2d = newImg.createGraphics();
    	try{
	      g2d.fillRect(10, 10, 50, 50);                               // Stelle die unsichtbar werden soll
	      g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT));

	      main.centerPanel.paints.draw(g2d);                // das alte Bild drüber malen
    	} finally { 
    		g2d.dispose();
    	}

Besseren Vorschlag?

Edit: Nur noch diese Frage, dann schließe ich das Thema und es geht dann im anderen Tread weiter
 

Marco13

Top Contributor
Ich kapier' halt immernoch nicht, welche Funktionen diese (mehreren!) Bilder alle erfüllen sollen. Wenn alles in EIN Bild gemalt wird, kann man da einen Bereich löschen, indem man mit passenden AlphaComposite und Color(0,0,0,0) was malt. Wenn es mehrere Bilder gibt, sollen die vermutlich "Layers" sein, aber dann müßtest du die Abläufe genauer beschreiben (welche Layer soll gelöscht werden und so...)
 

beastofchaos

Bekanntes Mitglied
OMG - wie geil ist das denn: Die Lösung ist ganz simpel:


Code:
 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT));

Ich wieß nicht, wie ich das bisher übersehen konnte oder wieso es bisher nicht funktioniert hat... aber das reicht :D
Danke, ich close den Thread jetzt. Nächste Probleme folgen im anderen Thread
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Swing JColorChooser für die JToggleButtons AWT, Swing, JavaFX & SWT 5
M Ausgabe der HSL oder RGB Zusammensetzung einer Farbe (JColorChooser AWT, Swing, JavaFX & SWT 1
M Swing JColorchooser anpassen - custom style? AWT, Swing, JavaFX & SWT 0
F 2D-Grafik Grafikproblem nach Aufruf von JColorChooser-Dialog AWT, Swing, JavaFX & SWT 6
A Swing JColorChooser's Icon will nicht getauscht werden. AWT, Swing, JavaFX & SWT 10
S Swing JColorChooser Font ändern AWT, Swing, JavaFX & SWT 2
J Swing Farbe wählen ohne JColorChooser 2 AWT, Swing, JavaFX & SWT 23
B JColorChooser - Locale setzen AWT, Swing, JavaFX & SWT 3
Burny91 Swing Swatches vom JColorChooser als Icon für JButton benutzen AWT, Swing, JavaFX & SWT 4
Y JColorChooser verwenden AWT, Swing, JavaFX & SWT 8
F JColorChooser NICHT im Dialog AWT, Swing, JavaFX & SWT 12
T JColorChooser abbrechen... AWT, Swing, JavaFX & SWT 2
D "JFontDialog" analog JColorChooser AWT, Swing, JavaFX & SWT 4
C open source JColorChooser? AWT, Swing, JavaFX & SWT 2
DeeDee0815 JColorChooser PreviewComponent AWT, Swing, JavaFX & SWT 6
T mouse-event auf jcolorchooser AWT, Swing, JavaFX & SWT 2
S JColorChooser Prob mit Ok/Abbr. AWT, Swing, JavaFX & SWT 3
G Thread und JColorChooser? AWT, Swing, JavaFX & SWT 11
B Event bei JColorChooser AWT, Swing, JavaFX & SWT 3
D jcolorchooser - lost focus AWT, Swing, JavaFX & SWT 2
G Alternative zum JColorChooser AWT, Swing, JavaFX & SWT 4
C GridbagLayout verstehen lernen AWT, Swing, JavaFX & SWT 1
L Eclipse Fehler besser zu verstehen!!! AWT, Swing, JavaFX & SWT 4
MiMa GUI Anfänge und verstehen AWT, Swing, JavaFX & SWT 8
G Verstehen sich Swing und AWT nicht? AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen


Oben