Negative Schrift

Tach,

ich zeichne Sachen (mit Farbverlauf, der sich bewegt) auf eine JComponent. Jetzt würde ich gerne in der paint-Methode über meinen Farbverlauf ein, zwei Worte schreiben. Diese können unterschiedlich lang sein. Mein Ziel ist es jetzt den angezeigten Text (bzw. Buchstaben) negativ zum Hintergrund zu setzen. Wie mach ich das am dümmsten?

Das ganze ist Teil eines eigenen JSliders bzw. JProgressbar. Code sieht bis jetzt so aus:


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

public class MyProgress extends JComponent {

	private static final long serialVersionUID = 1L;
	
	private int value = 0;
	private int start = 0;
	private int end = 1;
	private int prozent = 0;

	private Font font = null;
	private Color background = Color.white;
	private Color foreground = Color.black;
	private Color schrift = Color.red;
	private GradientPaint grad = null;
	private GradientPaint krum = null;

	private String paint = "";

	public MyProgress(int start, int end, int value) {

		setMinimum(start);
		setMaximum(end);
		setValue(value);
		startup();
	}

	public MyProgress(int start, int end) {

		setMinimum(start);
		setMaximum(end);
		startup();
	}

	public MyProgress() {

		startup();
	}

	private void startup() {

		addMouseListener(new MouseAdapter() {

			public void mousePressed(MouseEvent mou) {
				if (isEnabled()) {
					setValue((int) (((float) mou.getX() / (float) getWidth()) * (end - start) + start));
				}
			}
		});
		addMouseMotionListener(new MouseMotionAdapter() {

			public void mouseDragged(MouseEvent mou) {
				if (isEnabled()) {
					if (mou.getX() <= 0) {
						setValue(start);
					} else if (mou.getX() >= getWidth()) {
						setValue(end);
					} else {
						setValue((int) (((float) mou.getX() / (float) getWidth()) * (end - start) + start));
					}
				}
			}
		});
		setPreferredSize(new Dimension(300, 8));
		setMinimumSize(new Dimension(50, 8));
		font = new Font("dialog", Font.PLAIN, 10);
	}

	private void aktGradientPaint() {
		krum = new GradientPaint(0, 15, foreground, getWidth() * prozent / 100,
				getHeight(), background);
		grad = new GradientPaint(0, 2, background, getWidth() * prozent / 100,
				getHeight() - 4, foreground);
	}

	private void aktProzent() {
		prozent = (int) ((((float) value - (float) start) / ((float) end - (float) start)) * 100);
	}

	public void paintComponent(Graphics g) {

		Graphics2D g2d = (Graphics2D) g;
		aktGradientPaint();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		if (prozent == 0) {
			g2d.setColor(background);
		} else {
			g2d.setPaint(krum);
		}
		g2d.setFont(font);
		g2d.fillRect(0, getHeight() / 2 - 8 / 2, getWidth(), 8);
		g2d.setPaint(grad);
		g2d.fillRect(0, getHeight() / 2 - 6 / 2, getWidth() * prozent / 100 - 10, 6);
		g2d.fillArc(getWidth() * prozent / 100 - 20, getHeight() / 2 - 6 / 2, 20, 6, 0, 360);
		g2d.setColor(schrift);
		g2d.drawString(paint, getWidth() / 2 - g2d.getFontMetrics().stringWidth(paint) / 2, getHeight() / 2 - 6 / 2 + g2d.getFontMetrics().getHeight() / 2);
	}

	public void setValue(int value) {
		this.value = value;
		aktProzent();
		repaint();
	}

	public void setMinimum(int start) {
		this.start = start;
		aktProzent();
		repaint();
	}

	public void setMaximum(int end) {
		this.end = end;
		aktProzent();
		repaint();
	}

	public void setForeground(Color foreground) {
		this.foreground = foreground;
		repaint();
	}

	public void setBackground(Color background) {
		this.background = background;
		repaint();
	}
	
	public void setSchrift(Color schrift) {
		this.schrift = schrift;
		repaint();
	}

	public void setText(String paint) {
		this.paint = paint;
		repaint();
	}

	public int getValue() {
		return value;
	}

	public int getMinimum() {
		return start;
	}

	public int getMaximum() {
		return end;
	}

	public Color getForeground() {
		return foreground;
	}

	public Color getBackground() {
		return background;
	}
	
	public Color getSchrift() {
		return schrift;
	}

	public String getText() {
		return paint;
	}
}```

Danke für eure Tipps :)

also erstmal würd ich nen Label nehmen wo du die Schrift drauf packst, so hab ichs bei meiner einen auch gemacht.
Und mit dem Invertieren probier doch mal da einfach immer 255 drauf addieren oder abziehen was da rauskommt (nur sone Idee)

Hm? Drauf addieren? Wo drauf?

thx

Sry, das war ich und net angemeldet :o)

na du nimmst einfach die Farbe vom Hintergrund und nimmst dir die RGB Werte mit denen arbeitest du dann

Das Prob ist wie gesagt, dass ich nen Farbverlauf hab und sich somit die Hintergrundfarbe variiert. :frowning: Ansonsten wärs ja kein Thema …

[edit] also der Farbverlauf bewegt sich auch mit Fortschritt des Sliders … da liegt die Natur des Problems :wink: .

Ich hab eine gute und eine schlechte Nachricht.

Die gute: es ist möglich.
Die schlechte: es ist mühsam und nicht eben schnell.


import java.awt.*;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.LookupOp;
import java.awt.image.ShortLookupTable;

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

public class Paint extends JPanel{
    public static void main( String[] args ) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new Paint() );
        frame.setSize( 400, 300 );
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }
    
    public Paint() {
        setFont( new Font( "Helvetica", Font.BOLD, 128 ));
    }
    
    @Override
    protected void paintComponent( Graphics g ) {
        int w = getWidth();
        int h = getHeight();
        
        Graphics2D g2 = (Graphics2D)g;
        g2 = (Graphics2D)g2.create();
        
        BufferedImage background = createBackground( w, h );
        g.drawImage( background, 0, 0, this );
        
        TextLayout layout = new TextLayout( "TEST", getFont(), g2.getFontRenderContext() );
        Rectangle2D bounds = layout.getBounds();
        
        AffineTransform translation = new AffineTransform();
        translation.translate( w/2-bounds.getWidth()/2-bounds.getX(), h/2-bounds.getHeight()/2-bounds.getY() );
        
        Shape shape = layout.getOutline( translation );
        g2.setClip( shape );
        
        BufferedImageOp inverter = createInverter();
        g2.drawImage( background, inverter, 0, 0 );
        
        g2.dispose();
    }
    
    private BufferedImageOp createInverter(){
        short[] invert = new short[256];
        for (int i = 0; i < 256; i++)
            invert** = (short)(255 - i);
        BufferedImageOp invertOp = new LookupOp(
                new ShortLookupTable(0, invert), null);
        
        return invertOp;
    }
    
    private BufferedImage createBackground( int w, int h ){
        BufferedImage image = new BufferedImage( w, h, BufferedImage.TYPE_INT_RGB );
        Graphics2D g2 = image.createGraphics();
        
        GradientPaint gradient = new GradientPaint( w/4, 0, Color.BLUE, w-w/4, h/2, Color.RED );
        g2.setPaint( gradient );
        g2.fillRect( 0, 0, w, h/2 );
        
        gradient = new GradientPaint( w/4, h/2, Color.GREEN, w-w/4, h, Color.WHITE );
        g2.setPaint( gradient );
        g2.fillRect( 0, h/2, w, h/2 );
        
        g2.dispose();
        return image;
    }
}```

Ob und wie man das beschleunigen kann? Wenn du einen einfachen Farbverlauf hast, ist das Bild vielleicht nicht notwendig - und du kannst die invertierte Farbe direkt als Farbverlauf angeben.

Quellen:
http://www.javaworld.com/javaworld/jw-09-1998/jw-09-media.html?page=3
Die API ;P

OK, thx. Werd ich mir bei Gelegenheit mal anschauen. Mal gucken ob ma da noch ein bisschen Performance rauskitzeln kann :slight_smile:

So, hab das Ganze jetzt mal ausprobiert (hab nur n bisschen mit copy&paste gearbeitet und mir erstmal keine großartigen Gedanken gemacht „WIE“ das Ganze funktioniert). Das sieht jetzt so aus:

http://nopaste.coding-community.net/view.php?id=126

Funktioniert und auch die Performance passt (zumindest auf meinem Arbeitsrechner :smiley: ), aber mir sind zwei Sachen aufgefallen

  1. Wenn der Text so klein ist, wie ich ihn benötige wird er äußerst pixelig bis unmöglich zu lesen dargestellt. Durch was kommt das (Shape!?) und wie kann ich das umgehen?

  2. Hab ich in der ganzen Sache einen Denkfehler, weil wenn ich z. B. so wie in meinem Beispiel die Farben schwarz und weiß für den Farbverlauf nehme, bin ich auch irgendwann bei Grau mit einem Wert von 127, 127, 127 oder so ähnlich. Folglich bringt mir ein negativ der Schrift nicht viel. Jemand eine Idee, wie ich das gestallten kann, so das es immer gut gelesen werden kann? Ansonsten nehm ich halt wieder meine feste Schrift (find ich aber nicht so schön).

Danke!

Evtl mit Graphics#setXorMode

Wenn ich das richtig sehe, kann ich dort ja nur eine einzige Farbe als Gegenstück angeben oder? Hab aber nen Farbverlauf … von daher wäre es schick, wenn die Farbe mitverläuft.

Wow Bert, du bist genial :slight_smile:

Dann wird das ganz einfach:


import java.awt.*;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;

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

public class Paint extends JPanel{
    public static void main( String[] args ) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new Paint() );
        frame.setSize( 400, 300 );
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }
    
    public Paint() {
        setFont( new Font( "Helvetica", Font.BOLD, 128 ));
    }
    
    @Override
    protected void paintComponent( Graphics g ) {
        int w = getWidth();
        int h = getHeight();
        
        Graphics2D g2 = (Graphics2D)g;
        g2 = (Graphics2D)g2.create();
        
        GradientPaint gradient = new GradientPaint( w/4, 0, Color.BLUE, w-w/4, h/2, Color.RED );
        g2.setPaint( gradient );
        g2.fillRect( 0, 0, w, h/2 );
        
        gradient = new GradientPaint( w/4, h/2, Color.GREEN, w-w/4, h, Color.WHITE );
        g2.setPaint( gradient );
        g2.fillRect( 0, h/2, w, h/2 );
        
        g2.setFont( g2.getFont().deriveFont( 12f ));

        // >><< Ab hier wird die Invertierung eingeschaltet
        g2.setColor( Color.BLACK );
        g2.setXORMode( Color.WHITE );
        // >><< Jetzt ist die Invertierung gesetzt

        for( int i = 0; i < w; i += 40 )
            for( int j = 0; j < h; j += 40 )
                g2.drawString( "java", i, j );
        
        TextLayout layout = new TextLayout( "TEST", getFont(), g2.getFontRenderContext() );
        Rectangle2D bounds = layout.getBounds();
        layout.draw( g2, (float)(w/2-bounds.getWidth()/2), (float)(h/2-bounds.getHeight()/2-bounds.getY()) );
        
        
        g2.dispose();
    }
}```

[Edit]
Das sollte Problem 1 lösen, Problem 2 bleibt.

Ok, ich teste das heute Abend mal und schau ob ich mein Prob nr. 2 auch irgendwie in den Griff bekomme.

btw: @admins. Wenn ich aus den Code-Tags Code kopiere und irgendwo einfüge verschwinden die Zeilenumbrüche (und das nicht nur bei notepad sondern z. B. auch beim JCreator oder bei Eclipse …).

Ist bei mir nicht so. Welchen Browser verwendest du nochmal?

Opera 9.01 unter Windows XP

Bei mir wird in jeder zweiten Zeile ein # geschrieben…

Firefox, 1.0.7

also bei mir passt es auch

ja gut, bringt uns jetzt aber net wirklich weiter oder? Also ich hab praktisch eine lange zeile code ^^

Ja schon nur wenn das keiner hier nochmal hat kann man da nicht soviel machen, sieh mal nach ob das bei dir im Nopaste auch ist.
Hast du bei deinem Opera irgendwas geändert?

Also Beni@Work ( :wink: ) hat ja auch ein ähnliches Prob. Am Opera hab ich nichts verändert und NoPaste funktioniert wunderbar.