automatischer Farbwechsel

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • automatischer Farbwechsel

    Hallo Leute,

    ich würde gerne einen Kreis erstellen, welcher ständig die Farbe wechselt. Solange bis ein Button geklickt wird.
    Die Erstellung eines Kreises ist kein Problem, der Farbwechsel an sich auch nicht - nur wird dies nicht angezeigt, wenn ich es beispielsweise in eine Schleife packe und laufen lassen.

    In meinem Kopf habe ich eine "Endlosschleife" welche die Farbe des Kreises ändert und der Benutzer dies auch sieht. Sobald er den Button drückt, hört diese "Endlosschleife" auf zu laufen. Wie kann man soetwas realisieren?
    Mir ist gerade die Idee von Threads gekommen, dazu habe ich leider noch kein Wissen. Ist dies der richtige Weg?

    Ich hoffe jemand hat einen guten Tipp für mich :)

    Danke
  • Hi,

    von Farbe wechseln und irgendwelchen Animationen hab ich keine Ahnung, dafür fehlt mir das Gefühl :D. Aber ohne Threads o.ä. gehts nicht, da sich die UI nicht aktualisiert, wenn du irgendwelche Endlosschleifen in den Main-Thread der App packst, da bist du schon auf dem richtigen Weg.

    Das absolute Grundgerüst

    Java-Quellcode

    1. Thread t = new Thread({
    2. public void run() {
    3. // Endlosschleife, die die Farbe wechselt
    4. }
    5. });
    6. t.start();

    dürfte relativ klar sein, denke ich. In der run-Methode packst du dann dein Endloses konstrukt rein und mit einem Thread.sleep kannst du immer wieder pausen einbauen.

    Wahrscheinlich meldet sich hier aber auch noch der ein oder andere, der vll. auch mal ein Game gebaut hat und somit etwas mehr Gefühl und Erfahrung mit solchen Animationen mit bringt ;)

    Gruß,
    matze
  • Danke für den Hinweis, ich habe es mir ja fast gedacht. Leider klappt der Versuch nicht, die Anwendung bricht mit einem Fehler ab.
    Ich habe in einer Subactivity einen Kreis, beim Klick auf einen Button soll dieser anfangen die Farbe zu wechseln.

    An dieser Stelle etwas Quellcode:

    Java-Quellcode

    1. public class game extends Activity {
    2. private int pointPlayer1 = 0;
    3. private int pointPlayer2 = 0;
    4. private Circle gameCircle;
    5. private FrameLayout gameField;
    6. private Thread changeColor;
    7. @Override
    8. protected void onCreate(Bundle savedInstanceState) {
    9. // TODO Auto-generated method stub
    10. super.onCreate(savedInstanceState);
    11. setContentView(R.layout.game);
    12. gameField = (FrameLayout) findViewById(R.id.circle_view);
    13. Display display = getWindowManager().getDefaultDisplay();
    14. gameCircle = new Circle(this,
    15. display.getWidth(),
    16. display.getHeight(),
    17. Circle.getColor());
    18. gameField.addView(gameCircle);
    19. // nebenläufiger Prozess für den Farbwechsel
    20. changeColor = new Thread(){
    21. public void run(){
    22. try {
    23. while(true){
    24. // Wartezeit zwischen den Farben
    25. sleep((int)((Math.random()*2500)+1000));
    26. gameCircle.chanceColor(Circle.getColor());
    27. // TODO: FrameLayout aktualisieren verbessern
    28. gameField.removeAllViews();
    29. gameField.addView(gameCircle);
    30. }
    31. } catch (InterruptedException e) {
    32. // TODO Auto-generated catch block
    33. e.printStackTrace();
    34. }
    35. finally{
    36. finish();
    37. }
    38. }
    39. };
    40. }
    Alles anzeigen

    Nachdem der Button geklickt wurde, soll der Thread gestartet werden, sobald es dazu kommt, stürzt das Programm sofort ab.
    Führe ich es nicht parallel aus, also wie folgt klappt alles:

    Java-Quellcode

    1. // Wartezeit zwischen den Farben
    2. try {
    3. Thread.sleep((int)((Math.random()*2500)+1000));
    4. } catch (InterruptedException e) {
    5. // TODO Auto-generated catch block
    6. e.printStackTrace();
    7. }
    8. gameCircle.chanceColor(Circle.getColor());
    9. // FrameLayout aktualisieren
    10. gameField.removeAllViews();
    11. gameField.addView(gameCircle);
    Alles anzeigen


    Kann mir jemand meinen Fehler beschreiben?
    Ich habe das Gefühl der Thread startet in der falschen Activity (im Menü vor dieser game-Activity), sprich er ist gar nicht am richtigen Ort, aber dies kann ja nicht sein oder?
  • steusi schrieb:

    Ich habe in einer Subactivity einen Kreis, beim Klick auf einen Button soll dieser anfangen die Farbe zu wechseln.


    Also dein Button und dein Kreis befinden sich in unterschiedlichen Activitys? Soweit ich weiß sind alle Elemente ausserhalb der gerade aktiven Activity null.
    Du könntest zum besseren Verständnis vll auch den Output vom LogCat anhängen.

    Gruß,
    matze
  • Oh nein, Button und Kreis befinden sich natürlich in einer Activity.
    Die Fehler entstehen bei der 1. Zeile, nehme ich diese weg bei der 2. Zeile im Folgenden:

    Java-Quellcode

    1. gameField.removeAllViews();
    2. gameField.addView(gameCircle);


    Wie zeichnet man etwas neu? .repaint() oder .refresh() existiert leider nicht. Gern würde ich daher das FrameLayout neu zeichnen, was ich nur angelegt habe, damit der Kreis einem kleinen Bereich zugeordnet ist.
    Der Kreis ist ein Canvas-Objekt. Ich ändere beim Kreis die Eigenschaft der Farbe, doch da dieser bereits gezeichnet ist sieht man dies natürlich nicht. Da der Kreis dem FrameLayout zugeordnet ist, würde ein neues zeichnen des Kreises dazu führen, dass alles korrekt ist.

    Mein Versuch war nun alle Views innerhalb des FrameLayout zu löschen und wieder diesen neuen View (den Canvas-Kreis) hinzuzufügen.

    //edit:
    Mir ist gerade eingefallen, dass ich das Canvas-Objekt je refreshen kann:

    Java-Quellcode

    1. gameCircle.refreshDrawableState();
    2. gameCircle.invalidate();

    Leider stützt das Programm bei invalidate() ab :(
    Wie macht man es richtig?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von steusi ()

  • Hallo block_,
    eine richtige Fehlermeldung bekomme ich leider nicht :( Es steht nur da, das der Prozess beendet wird.

    meine Kreis-Klasse sieht wie folgt aus:

    Java-Quellcode

    1. public class Circle extends View {
    2. private final float x;
    3. private final float y;
    4. private final int r;
    5. private static final int WININDEX = 4;
    6. private static int tmpindex = 0;
    7. private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    8. public Circle(Context context, int width, int hight, int color) {
    9. super(context);
    10. mPaint.setColor(color);
    11. this.x = width/2;
    12. this.y = hight/2;
    13. this.r = (int) ((Math.min(width, hight)*0.8)/2);
    14. }
    15. @Override
    16. protected void onDraw(Canvas canvas) {
    17. super.onDraw(canvas);
    18. canvas.drawCircle(x, y, r, mPaint);
    19. }
    20. public void chanceColor(int color){
    21. mPaint.setColor(color);
    22. }
    23. public boolean isWinColor(){
    24. return tmpindex == WININDEX;
    25. }
    26. // Klassenmethoden:
    27. // gibt eine zufällige Farbe zurück
    28. public static int getColor(){
    29. int arrColor[] = new int[10];
    30. arrColor[0] = Color.rgb(47,79,79);
    31. arrColor[1] = Color.rgb(0,0,128);
    32. arrColor[2] = Color.rgb(0,191,255);
    33. arrColor[3] = Color.rgb(0,255,255);
    34. arrColor[4] = Color.rgb(0,100,0); // win
    35. arrColor[5] = Color.rgb(255,255,0);
    36. arrColor[6] = Color.rgb(184,134,11);
    37. arrColor[7] = Color.rgb(178,34,34);
    38. arrColor[8] = Color.rgb(255,69,0);
    39. arrColor[9] = Color.rgb(255,20,147);
    40. tmpindex = (int)(Math.random()*arrColor.length);
    41. return arrColor[tmpindex];
    42. }
    43. }
    Alles anzeigen


    Im Spiel wird der Kreis wie folgt erstellt:

    Java-Quellcode

    1. gameCircle = new Circle(this,
    2. display.getWidth(),
    3. display.getHeight(),
    4. Circle.getColor());

    Nun möchte ich gern im Thread die Farbe wechseln:

    Java-Quellcode

    1. gameCircle.chanceColor(Circle.getColor());
    2. gameCircle.refreshDrawableState();


    getColor sollte natürlich nicht von außen aufrufbar sein, sondern nur private in der Kreis-Klasse selbst!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von steusi ()

  • Hallo Steusi,

    Du darfst aus einem anderen Thread nichts an der UI ändern, das darf nur der UI-Thread, deswegen stürzts bei .invalidate() ab. Probier mal stattdessen .postInvalidate(), dies zeigt dem UI Thread an das er dein View neu zeichnen soll. Gibt auch andere Lösungen wie Activity.runOnUiThread() aber eigentlich sollte es so klappen.

    Gruss antifish
  • Danke antifish,

    ich verstehe - macht natürlich Sinn. Wenn es so läuft, würde mich eins noch brennend interessieren. Kann man in einem Thread auch auf ein View-Element zugreifen um zu prüfen, ob ein Button geklickt wurde als Beispiel?

    Muss ich eine Thread-Klasse erstellen, welche vom Thread erbt und dann überschreibe ich die run-Methode um ein View-Element zu übergeben oder gibt es einen Trick?
  • steusi schrieb:

    Danke antifish,

    ich verstehe - macht natürlich Sinn. Wenn es so läuft, würde mich eins noch brennend interessieren. Kann man in einem Thread auch auf ein View-Element zugreifen um zu prüfen, ob ein Button geklickt wurde als Beispiel?

    Muss ich eine Thread-Klasse erstellen, welche vom Thread erbt und dann überschreibe ich die run-Methode um ein View-Element zu übergeben oder gibt es einen Trick?
    Du kannst aus einem Thread auf ein View element zugreifen, solange du eine Refernez dazu hast.
    Allerdingst ist die Android UI ja Event basiert, also muss du nicht den Button abfragen ob er gedrückt ist, sonder der Button sagt dir wenn er gedrückt wird.
    Dazu kannst du einen "Listener" kreieren und beim Button setzen, somit weiss der Button wem er Bescheid sagen muss wenn er gedrückt wird.
    In Code für dein Beispiel etwas so:

    Button button = (Button)findViewById(R.id.button1);
    button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    changeColor.stop();
    }
    });