title image


Smiley Re: Button drehen
Hi



Mit Bordmitteln ist das scheinbar nicht so leicht. Ich bin zwar auch kein Graphik-Experte, aber daß ich jetzt ca. 7 Stunden gebraucht habe, um sowas ansatzweise hinzubekommen hätte ich vorher auch nicht gedacht. Jörg2's Idee mit dem Überschreiben der paint-Methode klingt eigentlich nicht schlecht (... das hätte ich vielleicht probiert, aber dazu hätte es dir eher einfallen müssen ... grummel ;-), aber ich befürchte, da gäbe es sowieso Probleme: Der Graphics-Kontext eines Buttons ist nur so groß wie der Button selbst - und spätestens, wenn der Button um einen Punkt gedreht werden soll, der außerhalb des Buttons liegt, wird er warscheinlich garnicht gezeichnet. Daher dachte ich mir gleich, daß sich die übergeordnete Komponente um das Zeichnen kümmern muß. Aber auch das ist nicht so leicht, wie man meinen könnte: Nur weil der Button woanders gemalt wird, heißt das nicht, daß er auch woanders ist: Ich hing eine ganze Weile daran, daß der Button zwar schön gedreht gemalt wurde, man aber immernoch da hinklicken mußte, wo er eigentlich liegen würde, um ihn zu aktivieren!



Jedenfalls habe ich mich mal durch die Tiefen der Event-Dokus gewühlt und fleißig rumprobiert, und jetzt scheint es weitgehend zu funktioneren. Wie das mit anderen Eltern-Komponenten als JFrame aussehen würde, müßtest du dir selbst überlegen, und daß man damit beim Layouten ein heilloses Durcheinander anrichten kann ist auch klar, aber jetzt (wo es "fertig" ist) sieht es garnichtmehr sooo kompliziert aus - da hätte man auch schneller drauf kommen können. Zumindest von der Idee her könnte es dir als Anhaltspunkt dienen.



Ein bißchen schade fand ich, daß man so wenig davon in einer eigenen Klasse unterbringen konnte, und mich stört auch die Notwendigkeit einer Übergabe des Button-"Owners" an den Button selbst, aber weil man den Button (wie gesagt) ums Verrecken nicht drehen, sondern nur gedreht zeichnen kann, müssen da einige Events hin- und hergereicht werden, um sicherzustellen, daß der Button dann und nur dann aktiviert wird, wenn wirkich sein gedrehtes Abbild angeklickt wurde.



Hier mal der Quellcode:



import java.awt.*;

import java.awt.event.*;

import javax.swing.*;



//=============================================== class RotatedJButton =====//

class RotatedJButton extends JButton {



// Diese Variable wird von der paint-Methode der Komponente, in der

// sich der gedrehte Button befindet, auf "true" gesetzt -

// NUR diese Komponente hat das Recht, in ihrem (gedrehten)

// Graphics2D-Kontext den Button zu zeichnen!

volatile boolean reallyPaint=false;



// Diese Variable gibt an, ob der zu verarbeitende MouseEvent

// "von außen" kommt, und wirklich verarbeitet wird, oder vom

// UNgedrehten Button selbst (dann wird er NICHT verarbeitet,

// sondern nur an die Elternkomponente weitergereicht)

volatile boolean reallyProcess=false;



// Leider, leider notwendig: Die Parent-Klasse, die aber nur eine

// Component sein muß, die die Methode "processLocalMouseEvent"

// anbietet. (siehe unten)

ButtonRotateTest owner;



//--------------------------------------------- constructor --------------//

public RotatedJButton(String s, ButtonRotateTest owner) {

super(s);

this.owner=owner;

}



//--------------------------------------------- paint --------------------//

public void paint(Graphics g) {

if (reallyPaint) super.paint(g);

}



//--------------------------------------------- processMouseEvent --------//

// Wenn der MouseEvent von außen kommt und wirklich

// verarbeitet werden soll, wird das auch getan.

// Wenn nicht, wird er zur weiteren Überprüfung

// an den owner weitergereicht

public void processMouseEvent(MouseEvent e) {

if (reallyProcess) super.processMouseEvent(e);

else owner.processLocalMouseEvent(e);

}



//--------------------------------------------- modifiedEvent ------------//

// Wenn eine der MouseEvent-Methoden (weiter unten) aufgerufen wird,

// bekommt diese Methode den MouseEvent übergeben, und wandelt ihn so um,

// daß es aussieht, als würde der Event von DIESEM Button stammen.

// Danach wird er ganz normal weiterProcessed.

private MouseEvent modifiedEvent(MouseEvent e) {

return new MouseEvent(this, e.getID(),

e.getWhen(),

e.getModifiers(),

1,1,

e.getClickCount(),

e.isPopupTrigger());

}



//--------------------------------------------- mouseEvents --------------//

// Diese Methoden reichen nur die modifizierten

// MouseEvents an die Superklasse weiter

public void mouseClicked( MouseEvent me ) {

reallyProcess=true;

processEvent(modifiedEvent(me));

reallyProcess=false;

}

public void mousePressed( MouseEvent me ) {

reallyProcess=true;

processEvent(modifiedEvent(me));

reallyProcess=false;

}

public void mouseReleased( MouseEvent me ) {

reallyProcess=true;

processEvent(modifiedEvent(me));

reallyProcess=false;

}

public void mouseEntered( MouseEvent me ) {}

public void mouseExited( MouseEvent me ) {}

}









//=============================================== class ButtonRotateTest ===//

class ButtonRotateTest extends JFrame implements MouseListener,

ActionListener {



public static void main(String args[]) {

ButtonRotateTest t = new ButtonRotateTest();

}



RotatedJButton b;

Polygon buttonShape;

Rectangle buttonRect;



// Der Winkel und der Punkt, um den gedreht wird.

double angle = Math.PI/3.0;

int centerX = 50;

int centerY = 50;



//--------------------------------------------- constructor --------------//

public ButtonRotateTest() {

setSize(300,300);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

addMouseListener(this);

getContentPane().setLayout(new FlowLayout());



// RotatedJButton erstellen und (zum Testen)

// einen actionListener dranhängen.

b=new RotatedJButton("Test", this);

b.addActionListener(this);



getContentPane().add(b);

setVisible(true);



// Hier werden Arrays mit den x- und y-Koordinaten der

// Eckpunkte des UNgedrehten Buttons erstellt.

buttonRect = b.getBounds();

buttonRect.x += getInsets().left;

buttonRect.y += getInsets().top;



int x[] = new int[]{ buttonRect.x,

buttonRect.x,

buttonRect.x+buttonRect.width,

buttonRect.x+buttonRect.width };



int y[] = new int[]{ buttonRect.y,

buttonRect.y+buttonRect.height,

buttonRect.y+buttonRect.height,

buttonRect.y };





// Diese Punkte werden nun alle um den vorgegebenen

// Punkt und den gegebenen Winkel gedreht.

double c=Math.cos(angle);

double s=Math.sin(angle);



for (int i=0; i<4; i++) {

x[i]-=centerX;

y[i]-=centerY;

int xi = x[i];

int yi = y[i];

x[i] = (int)(c*xi-s*yi);

y[i] = (int)(s*xi+c*yi);

x[i]+=centerX;

y[i]+=centerY;

}



// Aus den gedrehten Punkten wird ein Polygon erstellt,

// das die genaue Lage des Buttons beschreibt.

// (Wird benötigt, um zu testen, ob ein Mausklick

// innerhalb des gedrehten Buttons lag)

buttonShape=new Polygon(x,y,4);

repaint();

}



//--------------------------------------------- actionPerformed ----------//

// Zum Testen

public void actionPerformed(ActionEvent e) {

System.out.println("Click!");

}



//--------------------------------------------- processLocalMouseEvent ---//

// Hier werden die MouseEvents verarbeitet, die vom

// UNgedrehten Buttons stammen. Die Events werden so

// modifiziert, daß es so aussieht, als würden sie nicht

// vom UNgedrehten Button, sondern von DIESEM Objekt stammen.

// Dann werden sie weitergereicht. Eventuell wieder an den Button :-)

public void processLocalMouseEvent(MouseEvent e) {

MouseEvent global = new MouseEvent(this, e.getID(),

e.getWhen(),

e.getModifiers(),

e.getX()+buttonRect.x,

e.getY()+buttonRect.y,

e.getClickCount(),

e.isPopupTrigger());

super.processMouseEvent(global);

}



//--------------------------------------------- mouseEvents --------------//

// Wenn die MouseEvents innerhalb des gedrehten Buttons liegen, wird

// der Event an den Button weitergereicht. Dort wird er dann so

// modifiziert, daß es so aussieht, als stamme der Event vom Button.

public void mouseClicked( MouseEvent me ) {

if (buttonShape.contains(me.getPoint())) {

b.mouseClicked(me);

repaint();

}

}

public void mousePressed( MouseEvent me ) {

if (buttonShape.contains(me.getPoint())) {

b.mousePressed(me);

repaint();

}

}

public void mouseReleased( MouseEvent me ) {

b.mouseReleased(me);

repaint();

}

public void mouseEntered( MouseEvent me ) {}

public void mouseExited( MouseEvent me ) {}



//--------------------------------------------- paint --------------------//

public void paint(Graphics g) {

if (buttonShape==null) return;

Graphics2D g2d = (Graphics2D)g;



// Es wird um den Bezugspunkt gedreht

g2d.translate(centerX,centerY);

g2d.rotate(angle);

g2d.translate(-centerX,-centerY);

g2d.translate(buttonRect.x,buttonRect.y);



// Und dann wird (wirklich) der gedrehte Button gezeichnet.

b.reallyPaint=true;

b.paint(g);

b.reallyPaint=false;

}

}





Wie man sieht waren einige Verrenkungen notwendig, aber jetzt bin ich schon fast ein bißchen stolz, das hinbekommen zu haben *freu* (wenn du's woanders veröffentlichst: Mein Copyright nicht vergessen! ;-) Aber wie ich mich kenne postet morgen hier jemand sowas wie "Warum verwendest du nicht 'createRotatedJButton' aus javax.swing.obscure.seldomly-used.utils; ???" - NEIINNN! ;-)



Ich hoffe, das hilft dir weiter. Aber wenn nicht, ist mir das ehrlich gesagt auch egal. Hat Spaß gemacht.



bye





geschrieben von

Login

E-Mail:
  

Passwort:
  

Beitrag anfügen

Symbol:
 
 
 
 
 
 
 
 
 
 
 
 
 

Überschrift: