Android Changing Colors with Thread - android

I am a bit frustrated as to how to do this.., Can anyone please help me or guide me in the right direction?, with the code below. I just need to make a circle change colors in 2 second intervals, and i cant find anything out there.. basically if I could understand the following it would be enough
1.I have a class call DrawCircle that Exatends View
2.I have the Activity program where I instantiate the DrawCircle Class.
Questions:
1 - Where Do I create the Thread? in Activity or in the DrawCircle class?, and if I do, what should i put in the run();
2 - Where would I put the "Thread.sleep(2000)"? 3. and Finally, what do i need to make sure I have in the DrawCircle class and what should I make sure I have in the Activity or main program?
I just need to make a circle change colors in intervals of 2 seconds
Thank you very much for all the help ( I have spent 12 hours already trying to make this work and maybe I just shouldnt do it anymore)
Here is the code
public class ColorChanges extends Activity {
DrawCircle dc;
Paint pa = new Paint();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//this line does not work
dc = new DrawCircle(this,pa);
dc.setBackgroundColor(Color.WHITE);
drawCircleToCanvas();
setContentView(dc);
}
void drawCircleToCanvas()
{
final Handler handler = new Handler()
{
public void handleMessage(Message msg) {
pa.setColor(Color.BLUE);
dc.setBackgroundColor(Color.RED);
dc.postInvalidate();
}
};
Thread updateUI = new Thread()
{
public void run() {
try {
for (int i=0;i<20;i++){
Thread.sleep(2000);
handler.sendMessage(handler.obtainMessage());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
updateUI.start();
}
}
That is the Activity and here is my Class
public class DrawCircle extends View {
Paint p1 = new Paint();
Paint p2 = new Paint();
Paint p3 = new Paint();
Paint pAll[] = new Paint[3];
public DrawCircle(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context, Paint p) {
super(context);
p1 = p;
p1.setStyle(Paint.Style.STROKE);
p1.setColor(Color.GREEN);
p1.setStyle(Paint.Style.FILL);
// TODO Auto-generated constructor stub
}
#Override
public void onDraw(Canvas canvas)
{
canvas.drawCircle(200, 200, 100, p1);
}
}

Do it in the UI thread. Instead of Thread.sleep, use Handler.postDelayed() with a two-second delay.

Related

How to pass parameters to SurfaceView from main activity in Android

I need to draw a line diagram using surfaceview so from Main activity i will pass 2 parameters to surfaceview following this [link][1] solution
[1]: Passing arguments to SurfaceView via Constructor but still my passed parameters are 0 inside surfaceview draw method, please help
MySurfaceView.java:
private int len,theta;
public void setParameter(int length, int angle){
this.len = length;
this.theta = angle;
System.out.println("inside setParameter, len: "+len+" ,theta: "+theta);
}
protected void drawSomething(Canvas canvas) {
System.out.println("Inside drawSomething() , len: "+len+" ,theta: "+theta);
canvas.drawColor(Color.WHITE);
}
MainActivity.java
MySurfaceView myView = new MySurfaceView(MainActivity.this);
myView.setParameter(90,30);
myView.invalidate();
Values are printed only inside setParameter() not inside drawSomething(), i need to use those values inside drawSomething(),please help
Edited my code below,
public MySurfaceView(Context context) {
super(context);
init();
}
private void init(){
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback(){
#Override
public void surfaceCreated(SurfaceHolder holder) {
canvas = holder.lockCanvas(null);
drawSomething(canvas);
holder.unlockCanvasAndPost(canvas);
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}});
}
Since drawSomething(canvas) is called in a callback, you cannot know if it will be called earlier or not than your next function setParameter(int, int).
If you want to have the values available for drawSomething(canvas), you have to pass them in the constructor of MySurfaceView, or extend the class SurfaceHolder.Callback and pass the value to those.

Pass data from main activity to SurfaceView thread using a seek bar

I have a main activity class, I've also got a SurfaceView class that starts when my main activity starts.
I've got a seek bar in the main activity. I'd like to send whatever data that the seek bar produces to the SurfaceView to show it, every time it changes.
How can I do that?
Thanks.
Here is my SurfaceView class:
public class SurfaceViewGauge extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public SurfaceViewGauge(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
}
}
And Here is my Thread class:
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private SurfaceViewGauge myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, SurfaceViewGauge surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(myThreadRun){
Canvas c = null;
try{
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder){
myThreadSurfaceView.onDraw(c);
}
sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
in your MainActivity declare a static variable which will hold seekbar value and in your surfaceview code with the help of handler just call that static variable
e.g.
MainClass.seekValue;
In your Code, add Handler..
public Handler mhandler;
public SurfaceViewGauge(Context context, Handler mhandler)
{
super(context);
this.mhandler = mhandler;
// TODO Auto-generated constructor stub
init();
}
In the above code, use the Handler object for sending the code.

Multi-threading in the same Canvas

Well, I'll try to explain exactly what I pretend:
I want to draw a bitmap in a canvas in random positions according to the coordinates of the screen on touch, and I want a message(text) to be displayed everytime the user touches the screen.
So, if a draw the text in the same thread than I do for the bitmap, it will appear and dissapear right after, and I want it to stay in the screen for a few seconds and the dissapear. My first idea was to use Thread.sleep(), but for that I have to create a thread only for the text, or I will mess with the Bitmap too.
I've been trying to use multithreading in the same canvas, but I don't know how. Can someone please explain to me...
That's some of the code i've got so far:
private void init() {
// CREATE SURFACEHOLDER AND ADD THIS CLASS AS HIS CALLBACK
enemyHolder = getHolder();
enemyHolder.addCallback(this);
scoreHolder = getHolder();
scoreHolder.addCallback(this);
hasSurface = false;
}
public void resume() {
if (surfaceViewThread == null) {
surfaceViewThread = new SurfaceViewThread(); // CREATE A NEW
// THREAD
if (hasSurface)
surfaceViewThread.start(); // START OUR THREAD
}
if (secondThread == null) {
secondThread = new SecondThread();
if (hasSurface)
secondThread.start();
}
}
public void surfaceCreated(SurfaceHolder holder) {
hasSurface = true;
if (surfaceViewThread != null)
surfaceViewThread.start();
if (scoreShow == 1) {
if (secondThread != null)
secondThread.start();
}
}
// THREAD
private final class SurfaceViewThread extends Thread {
private boolean done;
SurfaceViewThread() {
super();
done = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
SurfaceHolder surfaceHolder = enemyHolder;
while (!done) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(enemy1, enemy1X, enemy1Y, null); // DRAW
// FIRST
// ENEMY
// SECOND THREAD
private final class SecondThread extends Thread {
private boolean done;
SecondThread() {
super();
done = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
SurfaceHolder surfaceHolder = scoreHolder;
while (!done) {
Canvas canvas = surfaceHolder.lockCanvas();
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawText("xD", 50, 50, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
scoreShow = 0;
}
}
Do you need to use a SurfaceView? It seems like a hard work way of doing things.
I've just done something similar by creating a custom view class and overriding the onDraw method. Then use canvas.save() and canvas.restore(). Here's the relevant bits of my onDraw.
#Override
public void onDraw(Canvas canvas) {
canvas.save();
// scale the canvas
canvas.scale(scaleFactor, scaleFactor); //, mid.x, mid.y);
// and translate...
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
super.onDraw(canvas);
// draw the lights
for(Light light:lights){
if (light.isOn){
canvas.drawCircle(light.getX(),light.getY(), light.getDiameter() / scaleFactor,light.paint);
}
}
canvas.restore();
}
The lights are turned on and off by a separate thread back in the activity which has inflated the view. They stay on screen as long as they are on.
Cheers
Here's some incomplete pseudo code to do what you've described. There are plenty of good examples around for each of these elements to help you fill in the blanks.
public class MyCustomView extends View {
int touchPointX;
int touchPointY;
private String mText;
public MyCustomView(Context context) {
// do initialisation stuff
}
public setText(String text){
mText = text;
this.invalidate();
}
#Override
public void onDraw(Canvas canvas) {
canvas.save();
super.onDraw(canvas);
canvas.drawBitmap(touchPointX, touchPointY, bitmap)
if (!mText.equals(""){
canvas.drawText(touchPointX, touchPointY + 10, mText)
}
canvas.restore();
}
}
public class MyActivity extends Activity implements OnTouchListener{
private Handler mHandler = new Handler();
private MyCustomView mCustomView;
#Override
protected void onCreate(Bundle savedInstanceState) {
mCustomView = (MyCustomView) findViewById(r.id.myCustomView);
}
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
// get x and y of touch
mCustomview.touchPointX = x;
mCustomview.touchPointY = y;
mCustomView.setText("Screen touched");
// clear the text after 5 seconds
mHandler.postDelayed(clearText, 5000);
// redraw the view
mCustomView.invalidate();
}
private void clearText(){mCustomView.setText("");}
}

Seamless background as custom view component , onDraw is not get called by invalidate()

Friends,
i want to make a seamless background as a custom view component.
the problem i figured out during debugging,
the first time i call invalidate() within the thread my onDraw callback method is called.
The other times my thread is calling invalidate() the onDraw callback method is not called.
so its just running over the invalidate() method , like it would not even exist.
The application displays the seamlessbackground png. But as static. it not gets updated.
I post all my code because the bug might be outside of the thread, where invalidate() is located or outside the onDraw method.
apprechate any kind of help! so THX
public class MyBringBackSurface extends View implements Runnable {
Bitmap bitmapResource;
int leftFrameX, rightFrameX, startX, stopX, bitmapPixelWidth,
bitmapPixelHight;
int pixelPerFrame = 10;
int framerate = 100;
int threadSleepTime;
int offsetYInPixel = 200;
Thread ourthread = null;
boolean isrunning = false;
Canvas c;
public MyBringBackSurface(Context context) {
super(context);
init();
}
public MyBringBackSurface(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyBringBackSurface(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// Set up Bitmap Resource
bitmapResource = BitmapFactory.decodeResource(getResources(),
R.drawable.simelessbackground);
// c = new Canvas(bitmapResource);
// Implementing leftFrameX and rightFrameX
leftFrameX = 0;
rightFrameX = bitmapResource.getWidth();
// Calculating the Thread sleep time
threadSleepTime = 1000 / framerate;
}
public void pause() { // destroy the currently running thread because
// anyways in the on resume will be created a
// new one again
isrunning = false;
while (true) {
try { // goes through this thread until our thread died
ourthread.join(); // Blocks the current Thread
// (Thread.currentThread()) until the
// receiver finishes its execution and
// dies.
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume() {
isrunning = true;
ourthread = new Thread(this);
ourthread.start();
}
public void run() {
while (isrunning) {
try {
Thread.sleep(threadSleepTime);
// formula is 1000/ sleep time (here 5) = frame rate
} catch (InterruptedException e) {
e.printStackTrace();
}
invalidate();
// Add pixelPerFrame and draw again
leftFrameX = leftFrameX - pixelPerFrame;
rightFrameX = rightFrameX - pixelPerFrame;
// if picture is completely out of the screen, start over again
if (leftFrameX <= -bitmapResource.getWidth()) {
leftFrameX = 0;
rightFrameX = bitmapResource.getWidth();
}
}
}
/**
* Render the text
*
* #see android.view.View#onDraw(android.graphics.Canvas)
*/
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
// Draw Rectangle 1250 pixel
Rect rect1000 = new Rect();
rect1000.set(0, 0, 1250, 20);
Paint blue = new Paint();
blue.setColor(Color.BLUE);
canvas.drawRect(rect1000, blue);
// Draw first Bitmap
Rect rectBitmapSource = new Rect(0, 0, bitmapResource.getWidth(),
bitmapResource.getHeight());
Rect rectBitmapDestinationFirst = new Rect(leftFrameX, offsetYInPixel,
rightFrameX, offsetYInPixel + bitmapResource.getHeight());
canvas.drawBitmap(bitmapResource, rectBitmapSource,
rectBitmapDestinationFirst, null);
// Draw second Bitmap
Rect rectBitmapDestinationSecond = new Rect(
(leftFrameX + bitmapResource.getWidth()), offsetYInPixel,
(rightFrameX + bitmapResource.getWidth()), offsetYInPixel
+ bitmapResource.getHeight());
canvas.drawBitmap(bitmapResource, rectBitmapSource,
rectBitmapDestinationSecond, null);
}
}
I figured out the answer after going throught the googledocs.
if you want to invalidate a View from outside of the UI-Thread you have to use the
postinvalidate() command instead of invalidate().
Thats it. It will work like charme!!!

Android Drawing

I am learning how to code with Android but I am still confused bby the way it works, I am able to create simple draws like circles and stuff but now i want to paint the circle multiple times with a delay of 2 seconds.. I would appreciatge if you experts can help me improve my code and to put the stuff in the correct place
public class ColorChanges extends Activity {
DrawCircle dc;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawCircleToCanvas()
}
void drawCircleToCanvas()
{
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dc.postInvalidate();
}
};
Thread updateUI = new Thread()
{
public void run() {
dc = new DrawCircle(this); //this line does not work
dc.setBackgroundColor(Color.WHITE);
setContentView(dc);
handler.sendEmptyMessage(0);
}
};
updateUI.start();
}
}
public class DrawCircle extends View {
Paint p1 = new Paint();
Paint p2 = new Paint();
Paint p3 = new Paint();
Paint pAll[] = new Paint[3];
public DrawCircle(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context) {
super(context);
p1.setStyle(Paint.Style.STROKE);
p1.setColor(Color.GREEN);
p1.setStyle(Paint.Style.FILL);
p2.setStyle(Paint.Style.STROKE);
p2.setColor(Color.BLUE);
p2.setStyle(Paint.Style.FILL);
p3.setStyle(Paint.Style.STROKE);
p3.setColor(Color.YELLOW);
p3.setStyle(Paint.Style.FILL);
pAll[1] = p1;
pAll[2] = p2;
pAll[3] = p3;
// TODO Auto-generated constructor stub
}
#Override
public void onDraw(Canvas canvas)
{
for (int i = 0; i < pAll.length;i++)
{
canvas.drawCircle(200, 200, 100, pAll[i]);
}
}
}
If you want to draw the same circle with its color changing over the time (each 2 seconds as you mentionned) you should use an Handler
in order to create a timer and to switch the paint at each time it is called.
Do not forget to call the invalidate function inside your custom view, as this function ask the system to redraw the screen.

Categories

Resources