Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich als Anfanger schreibe auch seit geraumer Zeit an einem Zeichenprogramm das fast den selben Aufbau hat.
Nun habe ich ein Problem. Ich habe einen Button der eine Ellipse zeichnen lässt und anschliessend die Koordinaten in einer Arraylist <Vector> abspeichert. Ich versuchte heute auch die Funktion fillOval einzubauen. Ich mache also in der Klasse Ellipse eine Schleife die erkennt ob bei der JCheckbox "fill" ausgewählt wurde oder nicht.
Wenn ich aber das ganze zu zeichnen versuche werden immer die alten Ellipsen auch wieder nicht ausgefüllt wenn ich an der Checkbox den haken wieder entferne.
Kann mir jemand weiterhelfen?
In einer Klasse "Ellipse" irgendwelche GUI-Elemente abzufragen klingt nach Bogus. Poste ggf. mal mehr code, damit man sich darunter was vorstellen kann - und auch eher sehen kann, wo der Fehler herkommt
Methodennamen kleinSchreiben.
Der Name "Vector" ist schon belegt, etwas unglückliche Wahl....
Was soll der String "gefuellt" denn da?
Der eigentliche Punkt:
public boolean filled = Gui.filled;
das wird einmal am Anfang gesetzt. Danach kann man im GUI das 'filled' hin- und her schalten, da kriegt die Ellipse nichts davon mit. Die Ellipse sollte ggf. eine Methode "setFilled(boolean)" haben, die man von außen aufrufen kann. Und im GUI sollte an der CheckBox ein Item- oder ActionListener hängen, der der Ellipse (welcher auch immer) sagt, ob sie gefüllt sein soll, oder nicht.
Methodennamen kleinSchreiben.
Der Name "Vector" ist schon belegt, etwas unglückliche Wahl....
Was soll der String "gefuellt" denn da?
Der eigentliche Punkt:
public boolean filled = Gui.filled;
das wird einmal am Anfang gesetzt. Danach kann man im GUI das 'filled' hin- und her schalten, da kriegt die Ellipse nichts davon mit. Die Ellipse sollte ggf. eine Methode "setFilled(boolean)" haben, die man von außen aufrufen kann. Und im GUI sollte an der CheckBox ein Item- oder ActionListener hängen, der der Ellipse (welcher auch immer) sagt, ob sie gefüllt sein soll, oder nicht.
Vielen Dank für die Antwort.
Das mit den Methodenname habe ich geändert
Der Name Vector ist schon belegt da es eine Klasse Vector gibt.
Das mit diesen Strings habe ich gelöscht ist irgend wirres Zeug.
bei Gui.filled ist bereits ein ActionListener der einstellt Gui.filled = true sobald die Checkbox ausgewählt ist.
Die Frage ich erstelle in der Klasse Ellipse eine Methode setFilled(boolean Fill). Diese Methode kann aber nicht g.fillOval verwendet da die zeichenmethode weiterunten ist.
class Ellipse ...
{
private boolean filled = false;
public void setFilled(boolean f)
{
this.filled = f;
}
public void paint(Graphics g){
....
if (filled){
g.fillOval(x, y, width, height);
}else{
g.drawOval(x, y, width, height);
}
}
Das "Problem" ist, dass diese Methode setFilled(true) dort aufgerufen werden muss, wo du bisher GUI.filled auf 'true' setzt - also z.B. im actionListener. Wo speicherst du denn die Ellipse-Objekte, die du so erstellst? In einer Liste? Sollen bei einer Änderung an der CheckBox ALLE Ellipsen gefüllt/nicht gefüllt sein? Poste am besten mal mehr code.
class Ellipse ...
{
private boolean filled = false;
public void setFilled(boolean f)
{
this.filled = f;
}
public void paint(Graphics g){
....
if (filled){
g.fillOval(x, y, width, height);
}else{
g.drawOval(x, y, width, height);
}
}
Das "Problem" ist, dass diese Methode setFilled(true) dort aufgerufen werden muss, wo du bisher GUI.filled auf 'true' setzt - also z.B. im actionListener. Wo speicherst du denn die Ellipse-Objekte, die du so erstellst? In einer Liste? Sollen bei einer Änderung an der CheckBox ALLE Ellipsen gefüllt/nicht gefüllt sein? Poste am besten mal mehr code.
hmm. genau so wie in diesem Code siehts im Moment bei mir aus. Ich möchte eben dass nicht alle Ellipsen gefüllt/nicht gefüllt werden bei einer Checkbox Änderung. Im Moment werden sie immer geändert.
Die Ellipsen-Objekte werden in einer anderen Klasse in private ArrayList<Vector> objekte; gesichert.
Hmja, und WELCHE Ellipse muss durch die CheckBox verändert werden? Genau DIE muss nämlich, auf die eine oder andere Weise, bei der CheckBox bekannt sein...
Es soll immer Die Ellipse "verändert" werden welche gerade interaktiv gezeichnet wird. Die anderen sind bereits gesetzt und sollen nicht mehr verändert werden können.
Muss ich also die setFilled() Methode bei dem zeichnen der Ellipse aufrufen?
@ Beni
Ich schaffe es immer noch nicht dass die Ellipsen als gefüllt oder nicht-gefüllt gezeichnet werden.
In meinem GUI schaut der Code so aus:
Java:
public class Gui extends JFrame implements ActionListener ... {
JCheckBox fillcheck = new JCheckBox("fill", false);
public static boolean filled;
fillcheck.addActionListener(this);
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
...
}else if(source == fillcheck){
filled = fillcheck.getModel().isSelected();
//System.out.println(filled);
}
Wie ist es nun möglich dass in der Ellipse Klasse immer true, oder false verwendet wird. Es funktioniert zwar aber es werden immer die alten Ellipsen auch verändert.
Java:
if(Gui.filled){
g.fillOval(x, y, width, height);
}else{
g.drawOval(x, y, width, height);
}
das wird einmal am Anfang gesetzt. Danach kann man im GUI das 'filled' hin- und her schalten, da kriegt die Ellipse nichts davon mit. Die Ellipse sollte ggf. eine Methode "setFilled(boolean)" haben, die man von außen aufrufen kann. Und im GUI sollte an der CheckBox ein Item- oder ActionListener hängen, der der Ellipse (welcher auch immer) sagt, ob sie gefüllt sein soll, oder nicht.
Genau das bringe ich irgendwie nicht zustande. An der Checkbox hängt ja ein Actionlistener der true und false ausgibt. Von wo muss ich die setFilled methode aufrufen?
Java:
public void setFilled(boolean checkboxSelected) {
if (drawEllipse != null){
drawEllipse.setFilled(checkboxSelected);
}
}
if(wasKommtHier?){
g.fillOval(x, y, width, height);
}else{
g.drawOval(x, y, width, height);
}
Du hast ja die Instanzvariable filled (nach Marcos Vorschlag)
Und wenn du dann eine neue Ellipse malst, dann speicherst du die in deiner Ellipsenliste und rufst vorher noch eben e.setFilled(fillcheck.getModel().isSelected()); auf (Dabei sei e die gerade erzeugte Ellipse)
Du hast ja die Instanzvariable filled (nach Marcos Vorschlag)
Und wenn du dann eine neue Ellipse malst, dann speicherst du die in deiner Ellipsenliste und rufst vorher noch eben e.setFilled(fillcheck.getModel().isSelected()); auf (Dabei sei e die gerade erzeugte Ellipse)
Ich habe es nun genau so umgesetzt. In der der Klasse mit den ArrayListen habe ich auch eine vom Typ Boolean erstellt. Dort soll gespeichert werden.
Aber es passiert noch genau das gleiche wie vorher (
bei den Farben und den Strichdicken hat es genau so funktioniert.
Natürlich, das wird dir auch der Compiler so sagen. Du greifst ja statisch auf die nicht-statische Methode zu (und die MUSS auch nicht statisch bleiben!).. Dir fehlen doch einige Grundlagen, ums mal direkt zu sagen...
Hast du ein Java Buch? Wenn nicht, empfehle ich wie imemr: Die Insel
Natürlich, das wird dir auch der Compiler so sagen. Du greifst ja statisch auf die nicht-statische Methode zu (und die MUSS auch nicht statisch bleiben!).. Dir fehlen doch einige Grundlagen, ums mal direkt zu sagen...
Hast du ein Java Buch? Wenn nicht, empfehle ich wie imemr: Die Insel
Ja ich weiss dass mir einige Grundlagen fehlen. Ich arbeite gerade das Buch "Jetzt lerne ich Java 6" durch.
da der Compiler einen Fehler meldete habe ich die Methode eben statisch gemacht. Jedoch werden diese
Ellipsen immer noch verändert wenn die checkbox verändert wird.
import java.awt.Graphics;
public class Ellipse extends Vector{
private int width;
private int height;
public static boolean filled = false;
public Ellipse(int x, int y, int width, int height){
super(x,y);
this.width = width;
this.width = width;
}
public void setWidth(int width){
this.width = width;
}
public void setHeight(int height){
this.height = height;
}
public static void setFilled(boolean filled) {
Ellipse.filled = filled;
}
public void Paint(Graphics g){
int width = this.width;
int height = this.height;
int x = this.GetX();
int y = this.GetY();
if(width<0){
width = -width;
x-=width;
}
if(height<0){
height = -height;
y-=height;
}
if(filled){
g.fillOval(x, y, width, height);
}else{
g.drawOval(x, y, width, height);
}
}
}
Die Klasse Painter (zeichnet die Objekte neu). Ich weiss dass ich diese Anders aufbauen sollte. Lasse ich im Moment aber noch so.
Java:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Painter extends Thread{ // Painter für Nebenaktivität -> repaint graphics objekt immer neu holen und neu zeichnen
// Thread ist die Nebenaktivität
static JPanel fenster;
private ArrayList<Vector> objekte; // Liste von Vektoren dynamisch
private ArrayList<BasicStroke> strokes; // Liste mit den Strichdicken
private ArrayList<Color> colors; // Liste mit den Malfarben
private ArrayList<Boolean> fill; // Liste mit gefüllt/nichtgefüllt
public Painter(JPanel f){
fenster = f;
objekte = new ArrayList<Vector>();
strokes = new ArrayList<BasicStroke>();
colors = new ArrayList<Color>();
fill = new ArrayList<Boolean>();
}
public void addToPaint(BasicStroke stroke, Color color, Boolean filled){
strokes.add(stroke);
colors.add(color);
fill.add(filled);
}
public void run() {
while(true){
try{
Graphics g = fenster.getGraphics();
g.clearRect(0, 0, fenster.getWidth(), fenster.getHeight());
for(int i=0; i<objekte.size(); i++){ // alle gezeichnete Objekte durchgehen
Vector v = objekte.get(i); // hole aus Liste Element an Position i
BasicStroke stroke = strokes.get(i);
Color color = colors.get(i);
Boolean filled = fill.get(i);
((Graphics2D) g).setStroke(stroke);
g.setColor(color);
Ellipse.setFilled(Gui.fillcheck.getModel().isSelected());
v.Paint(g);
}}
catch(Exception e){}
try {
Thread.currentThread();
Thread.sleep(1000/24);
} catch (InterruptedException e) {
e.printStackTrace();
} // 1000/24 24 tausendstel sekunden bis warten... Zahl aus Flashprogrammierung
}
}
public void takeSnapShot(JPanel fenster){
try {
java.awt.Robot robot = new java.awt.Robot();
BufferedImage img = robot.createScreenCapture(new Rectangle(fenster.getLocationOnScreen().x,fenster.getLocationOnScreen().y,
fenster.getWidth(),fenster.getHeight()));
ImageIO.write(img, "png", Gui.file);
}
catch (Exception ex) {System.out.println(ex);
}
}
public void addVector(Vector v, float thickness, Color color, Boolean filled){
objekte.add(v);
if( Gui.mode == "FreiHand"){
strokes.add(new BasicStroke(Gui.thickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // Freihand runde Ecken
}else{
strokes.add(new BasicStroke(Gui.thickness));
}
colors.add(Gui.color);
fill.add(Gui.fillcheck.getModel().isSelected());
}
public void clearVector(){
objekte.clear();
strokes.clear();
colors.clear();
fill.clear();
}
}
Die Klasse Gui
Java:
public class Gui extends JFrame implements ActionListener ... {
JCheckBox fillcheck = new JCheckBox("fill", false);
public static boolean filled;
...
fillcheck.addActionListener(this);
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
...
}else if(source == fillcheck){
fillcheck.getModel().isSelected();
//System.out.println(fillcheck.getModel().isSelected());
}
Die vielen üblichen Kritikpunkte, die es nicht gäbe, wenn du ein bißchen lesen würdest, können andere korrigieren (getGraphics, public static Fields & Co). Relevant sei jetzt erstmal: Wo werden die Objekte (d.h. new Ellipse) erstellt?
Eigentlich poste ich nicht mehr gerne ganze Programme, aber in diesem Fall kann ein Beispiel wie es richtiger gemacht wird vielleich helfen.
Schau dir das Programm an:
- Die Ellipse Klasse hat ein Feld "filled". Es ist nicht static weil jedes Ellipse Objekt einen anderen Wert haben könnte. Mit "setFilled" kann das Feld verändert werden.
- Die Ellipsen werden von der EllipseFactory hergestellt. Und solange du noch nicht auf den "Commit" Knopf gedrückt hast, weiss diese Factory an welcher Ellipse du rumspielst. Deshalb kann die Factory auch jederzeit "setFilled" aufrufen und so eine Ellipse abändern.
- Der Wert der JCheckBox wird einmal abgerufen und der EllipseFactory gesagt. Die Factory muss nicht selbst rumfragen sondern wird beliefert. Das ist ein erster Schritt in Richtung Kapselung: jedes Objekt weiss genau soviel wie es braucht um zu funktionieren, und nicht mehr.
In deinem Programm solltest du ein paar Dinge dringend verbessern:
- Color, Strokes, "Filled", etc. Das alles sind Werte die zu jeweils genau einem Objekt gehören. Und deshalb muss Ellipse (oder "Vector") auch Felder haben wie "Color color", "boolean filled", etc. Deine "Painter" Klasse hat sich nicht im geringsten zu interessieren, was die Farben dieser Objekte sind. Um genauer zu sein: wenn deine Painter-Klasse grösser ist als meine Painter-Klasse, dann ist sie zu gross.
- Vergiss mal das Zeugs mit den Threads. Schreib erstmal ein Programm ohne Threads. Wenn dir das gelingt, kannst du immernoch ein neues Programm mit Threads schreiben.
- Vergiss "static". In einem Programm sollte es ein static geben: das "public static void main". Jedes weitere "static" ist höchstwahrscheinlich ein "static" zuviel.
- Achja, "getGraphics" kannst du auch gleich aus deinem Vokabular streichen (oder als Schimpfwort behalten). Die korrekte Art auf ein JPanel zu zeichnen ist immer "paintComponent" zu überschreiben.
Java:
package forum;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class EllipseTest {
public static void main( String[] args ){
JFrame frame = new JFrame( "Test" );
Painter painter = new Painter();
final EllipseFactory factory = new EllipseFactory( painter );
JButton commit = new JButton( "Commit" );
commit.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ){
factory.commit();
}
} );
final JCheckBox filled = new JCheckBox( "Filled" );
filled.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ){
factory.setFilled( filled.isSelected() );
}
} );
JPanel toolbar = new JPanel( new FlowLayout() );
toolbar.add( commit );
toolbar.add( filled );
frame.add( toolbar, BorderLayout.NORTH );
frame.add( painter, BorderLayout.CENTER );
frame.setBounds( 20, 20, 400, 400 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
public static class EllipseFactory extends MouseAdapter implements MouseListener, MouseMotionListener {
private Ellipse newEllipse = null;
private Painter painter;
private boolean filled = false;
public EllipseFactory( Painter painter ){
this.painter = painter;
painter.addMouseListener( this );
painter.addMouseMotionListener( this );
}
@Override
public void mousePressed( MouseEvent e ){
if (newEllipse == null) {
newEllipse = new Ellipse( e.getX(), e.getY(), 0, 0 );
newEllipse.setFilled( filled );
painter.add( newEllipse );
} else {
mouseDragged( e );
}
}
@Override
public void mouseDragged( MouseEvent e ){
newEllipse.setWidth( e.getX() - newEllipse.getX() );
newEllipse.setHeight( e.getY() - newEllipse.getY() );
painter.repaint();
}
public void setFilled( boolean filled ){
this.filled = filled;
if (newEllipse != null) {
newEllipse.setFilled( filled );
painter.repaint();
}
}
public void commit(){
newEllipse = null;
}
}
public static class Painter extends JPanel {
private List<Ellipse> figures = new ArrayList<Ellipse>();
public void add( Ellipse figure ){
figures.add( figure );
}
@Override
protected void paintComponent( Graphics g ){
super.paintComponent( g );
g.setColor( Color.WHITE );
g.fillRect( 0, 0, getWidth(), getHeight() );
g.setColor( Color.BLACK );
for (Ellipse figure : figures) {
figure.paint( g );
}
}
}
public static class Ellipse {
private int x;
private int y;
private int width;
private int height;
private boolean filled = false;
public Ellipse( int x, int y, int width, int height ){
this.x = x;
this.y = y;
this.width = width;
this.width = width;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setWidth( int width ){
this.width = width;
}
public void setHeight( int height ){
this.height = height;
}
public void setFilled( boolean filled ){
this.filled = filled;
}
public void paint( Graphics g ){
int x = this.x;
int y = this.y;
int width = this.width;
int height = this.height;
if (width < 0) {
width = -width;
x -= width;
}
if (height < 0) {
height = -height;
y -= height;
}
if (filled) {
g.fillOval( x, y, width, height );
} else {
g.drawOval( x, y, width, height );
}
}
}
}
Das ich echt ein super Job den du hier machst. Auch danke an alle anderen die mir geholfen haben dieses Problem zu bädigen.
Mir ist klar dass es noch andere Fehler gibt die ich nach und nach ausmerzen will
Die Überlegung die ich nicht gemacht habe war:
Java:
currentobject = new Ellipse(e.getX(), e.getY(),0,0);
((Ellipse) currentobject).setFilled( filled ); <<<<<<<