Android canvas drawRect() also redraws previous draws - java

I've spent my whole day trying to figure out, how to draw squares with random colors, filling the whole screen. What i think happens is that, when drawRect() is called, it redraws previous draws, which doesnt make any sense, but its all i got. This is the code and i dont know what else to do, to fix this problem, here is the result.
http://i.imgur.com/a083U0a.png
public class MyView extends View {
public MyView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int numberPerRow = 10;
int x = getWidth()/numberPerRow;
int y = getHeight();
for(int i = 0; i < 50; i++){
for (int j = 0; i <= numberPerRow; j++){
Paint paintTopRight = new Paint();
int randColor = randomColor();
paintTopRight.setColor(randColor);
canvas.drawRect(j*x,i*x,x,x,paintTopRight);
}
}
}
public int randomColor() {
int r = (int) (0xff * Math.random());
int g = (int) (0xff * Math.random());
int b = (int) (0xff * Math.random());
return Color.rgb(r, g, b);
}
}

Your for loop appears to have a typo; you use i when you should be using `j.
Change the new onDraw(Canvas canvas) method to
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int numberPerRow = 10;
int x = getWidth()/numberPerRow;
int y = getHeight();
for(int i = 0; i < 50; i++){
for (int j = 0; j <= numberPerRow; j++){
Paint paintTopRight = new Paint();
int randColor = randomColor();
paintTopRight.setColor(randColor);
canvas.drawRect(j*x,i*x,x,x,paintTopRight);
}
}
}

Related

Processing - Rough pixel sorting algorithm stops after a part of the image

I wrote a code for processing and had formerly sorted pixels with selection sort. I have to hand it in and the teacher said it is taking to long like this, so I decided to divide the pixels brightness into parts of 50 and just sort it very roughly. The image that comes out isn't completely sorted though and I really don't know where it went wrong.
I doesn't have to be sorted perfectly - it's really just about having a cool-looking image as a result.
I hope some can help me and it is understandable what I mean!
Thanks in advance
PImage img;
PImage two;
PImage sorted;
int j = 0;
int x = j;
int y = x;
int u = y;
int h = u;
int d = 1;
void setup() {
size(736,1051);
img = loadImage("guy.png");
two = loadImage("guy2.png");
background(two);
}
void draw() {
loadPixels();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int loc = x + y*width;
float r = red(img.pixels[loc]);
float g = green(img.pixels[loc]);
float b = blue(img.pixels[loc]);
float av = ((r+g+b)/3.0);
pixels[loc] = color(g,b,r, 17); //I know r, g, b are switched here
}
}
updatePixels();
save("guy_coloured.png");
}
void keyPressed(){
sorted = loadImage("guy_coloured.png");
sorted.loadPixels();
image(sorted, 0, 0);
System.out.print("doing it");
for (int i = 0; i < sorted.pixels.length; i++){
color colours = sorted.pixels[i];
float b = brightness(colours);
if(b<50){
sorted.pixels[j] = sorted.pixels[i];
j++;}
}
for (int f = 0; f < img.pixels.length; f++){
color colours = sorted.pixels[f];
float b = brightness(colours);
if(b<100 && b>50){
sorted.pixels[x] = sorted.pixels[f];
x++;}
}
for (int k = 0; k < img.pixels.length; k++){
color colours = sorted.pixels[k];
float b = brightness(colours);
if(b<150 && b>100){
sorted.pixels[y] = sorted.pixels[k];
y++;}
}
for (int t = 0; t < img.pixels.length; t++){
color colours = sorted.pixels[t];
float b = brightness(colours);
if(b<200 && b>150){
sorted.pixels[u] = sorted.pixels[t];
u++;}
}
for (int o = 0; o < img.pixels.length; o++){
color colours = sorted.pixels[o];
float b = brightness(colours);
if(b>200){
sorted.pixels[h] = sorted.pixels[o];
h++;}
}
System.out.print("done");
sorted.updatePixels();
image(sorted, 0, 0);
save("guy_sorted.png");
noLoop();
}
I want the whole image to be sorted, but it gives me back the normal image with about 1/4 sorted from the top.
This is the current result:
https://imgur.com/kHffIpm
Full code including irrelevant parts: https://docs.google.com/document/d/1YC97YMq9fKcbCAn3_RvLIm1bNo72FrNnHT3obc9pp7U/edit?usp=sharing
You do not sort the pixels. What you actually do is to arrange the dark pixel at the begin of the image and overwrite the pixels which are there. If you want to sort the pixels, then you've to swap them.
Write a function which can swap 2 pixel:
void Swap(PImage toSort, int i1, int i2) {
color c = toSort.pixels[i1];
toSort.pixels[i1] = toSort.pixels[i2];
toSort.pixels[i2] = c;
}
Once some pixels have been sorted, and are arranged at the begin of the image, this area doesn't need to be investigated further.
Write a function which sorts pixels dependent on a brightness range [b_min, b_max] and start at a certain index start:
int Sort(PImage toSort, int start, float b_min, float b_max) {
for (int i = start; i < toSort.pixels.length; i++) {
float b = brightness(toSort.pixels[i]);
if (b >= b_min && b < b_max) {
Swap(toSort, i, start);
start ++;
}
}
return start;
}
Sort the image by ascending brightness. e.g:
PImage img, two, sorted;
void setup() {
size(736,1051);
img = loadImage("guy.png");
two = loadImage("guy2.png");
background(two);
}
void draw() {
loadPixels();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int loc = x + y*width;
float r = red(img.pixels[loc]), g = green(img.pixels[loc]), b = blue(img.pixels[loc]);
pixels[loc] = color(g,b,r, 17); //I know r, g, b are switched here
}
}
updatePixels();
save("guy_coloured.png");
}
void Swap(PImage toSort, int i1, int i2) {
color c = toSort.pixels[i1];
toSort.pixels[i1] = toSort.pixels[i2];
toSort.pixels[i2] = c;
}
int Sort(PImage toSort, int start, float b_min, float b_max) {
for (int i = start; i < toSort.pixels.length; i++) {
float b = brightness(toSort.pixels[i]);
if (b >= b_min && b < b_max) {
Swap(toSort, i, start);
start ++;
}
}
return start;
}
void keyPressed(){
sorted = loadImage("guy_coloured.png");
sorted.loadPixels();
image(sorted, 0, 0);
System.out.print("doing it");
int j = 0;
j = Sort(sorted, j, 0.0, 50.0);
j = Sort(sorted, j, 0.50, 100.0);
j = Sort(sorted, j, 0.100, 150.0);
j = Sort(sorted, j, 0.150, 200.0);
j = Sort(sorted, j, 0.200, 256.0);
System.out.print("done");
sorted.updatePixels();
image(sorted, 0, 0);
save("guy_sorted.png");
noLoop();
}

Converting image to 2d array gets only top left quadrant

I am making a procedural animation in Android that is supposed to just take a 720x720 image, convert in into a 2d array of colors and then draw every pixel individually. The problem with my code is that it takes only the top left quadrant and displays it as if it were the whole image and I can't figure out how to fix it.
The code, source image and result here:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawPixels(this, 720, 720));
}
}
public class DrawPixels extends View {
public int[][] image_array;
Bitmap frame;
Bitmap photo;
Canvas frameDrawer;
Rect bounds;
Paint lp;
int width , height;
int x = 0;
int y = 0;
int radius = 3;
public DrawPixels(Context context , int width, int height) {
super(context);
photo = BitmapFactory.decodeResource(context.getResources(), R.drawable.marilyn2);
image_array = imageTo2dArray(photo);
this.width = width;
this.height = height;
frame = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
frameDrawer = new Canvas(frame);
bounds = new Rect(0 , 0, width,height);
lp = new Paint();
lp.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
if (x < 720 && y < 720) {
lp.setColor(image_array[x][y]);
frameDrawer.drawCircle(x, y, radius, lp);
}
canvas.drawBitmap(frame, null, bounds , null);
//sampling every 5th pixel
if (x < 720){
if(y < 720){
y += 5;
}else{
y = 0;
x += 5;
}
invalidate();
}
}
public int[][] imageTo2dArray(Bitmap bm){
int[][] arr = new int[720][720];
int p, a, r, g, b, avg;
for(int i = 0; i < 720; i++) {
for (int j = 0; j < 720; j++) {
arr[i][j] = bm.getPixel(i, j);
}
}
return arr;
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="d.androidnewcomer.drawing.MainActivity">
</android.support.constraint.ConstraintLayout>
marilyn2.png:
result:
The most likely reason is that BitmapFactory.decodeResource scales the bitmap so that it is no longer 720x720 but rather 1440x1440.
See: BitmapFactory.decodeResource Bitmap not original size in pixels

How to fill 2D array with randm colors in java?

I've been trying to generate a grid of randomly colored boxes for a brick-breaker game. However given this code, the colors keep changing. I'd like them to be randomly set and stay that way.
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map [0].length; j++) {
if(map[i][j] > 0) { //make brick if greater than 0, else don't
int color = (int) (Math.random() * 256);
g.setColor(new Color(color, color, color));
g.fillRect(j * brickWidth + 80, i * brickHeight + 50, brickWidth, brickHeight);
g.setStroke(new BasicStroke(3));
g.setColor(Color.black);
g.drawRect(j * brickWidth + 80, i * brickHeight + 50, brickWidth, brickHeight);
}
}
}
Each time your component need to be resized or moved, repaint() method is being called to update it's state. So if you are generating colors in paintComponent like in following example:
public class MyComponent extends JComponent {
#Override
protected void paintComponent(Graphics g) {
// generate colors and draw grid
}
}
then colors will change on resize event or other event that lead to repaint call, since repaint invokes paintComponent method. If you want to display the same colors, just move generate-colors code out of this method:
public class MyComponent extends JComponent {
private final Color[][] gridColors = randomGridColors(5, 5);
private Color[][] randomGridColors(int rows, int columns) {
Color[][] gridColors = new Color[rows][columns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
gridColors [i][j] = randomColor();
}
}
}
private Color randomColor() {
int rgbValue = (int) (Math.random() * 256);
return new Color(rgbValue, rgbValue, rgbValue);
}
#Override
protected void paintComponent(Graphics g) {
// draw grid
}
}
You currently create the random color every time you draw your bricks, which can be many times per second.
Create some brick class and generate the color for each brick only once.
Something like this:
public class TryThis {
private static final Logger LOG = Logger.getLogger(TryThis.class.getName());
public static void main(String[] args) {
SwingComponent panel = new SwingComponent();
JFrame frame = new JFrame("try me");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.setVisible(true);
}
static class SwingComponent extends JPanel {
int W = 10;
int H = 10;
int recwidth = 20;
int recheight = 10;
Brick[][] bricks = new Brick[H][W];
public SwingComponent() {
super();
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
bricks[y][x] = new Brick(createRandomColor(), new Rectangle(x * recwidth, y * recheight, recwidth,
recheight));
}
}
}
#Override
public void paint(Graphics g) {
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
bricks[y][x].draw(g);
}
}
}
Color createRandomColor() {
return new Color((int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256));
}
}
static class Brick {
Color col;
Rectangle rec;
public Brick(Color col, Rectangle rec) {
this.col = col;
this.rec = rec;
}
public void draw(Graphics g) {
g.setColor(col);
g.fillRect(rec.x, rec.y, rec.width, rec.height);
}
}
}

JFrame showing a copy of contents inside of itself...?

I have a strange problem, I can figure it out.
here is my program running:
the clock on the right shouldn't even be there, it should just be string that displays the time. I create two different objects and add them to a content panel, then add the content panel to the JFrame. I also have a menu bar that I add to the JFrame and it shows up on the right side of the content pane. Here is my main class:
class DigitalClock3DialsView extends DigitalClockView {
private static int caps[] = { BasicStroke.CAP_BUTT,
BasicStroke.CAP_SQUARE, BasicStroke.CAP_ROUND};
private static int joins[] = { BasicStroke.JOIN_MITER,
BasicStroke.JOIN_BEVEL, BasicStroke.JOIN_ROUND};
private static Color colors[] = {Color.gray, Color.pink, Color.lightGray};
private static BasicStroke bs1 = new BasicStroke(1.0f);
// three arms of clock
private Line2D lines[] = new Line2D[3];
private int rAmt[] = new int[lines.length];
private int speed[] = new int[lines.length];
private BasicStroke strokes[] = new BasicStroke[lines.length];
private GeneralPath path;
private Point2D[] pts;
private float size;
private Ellipse2D ellipse = new Ellipse2D.Double();
private BufferedImage bimg;
//variables to keep track if minutes or hours increased
private int oldMinute;
private int oldHour;
/**
* init background
*/
public void init() {
setBackground(Color.white);
}
/**
* reset view: the shape of arms, etc
*/
public void reset(int w, int h)
{
oldMinute = 0;
oldHour = 0;
size = (w > h) ? h/6f : w/6f;
for (int i = 0; i < lines.length; i++) {
lines[i] = new Line2D.Float(0,0,size,0);
strokes[i] = new BasicStroke(size/3, caps[i], joins[i]);
rAmt[i] = 270; // vertical
}
//speed of the 3 arms
speed[0] = 6;
speed[1] = 6;
speed[2] = 6;
path = new GeneralPath();
path.moveTo(size, -size/2);
path.lineTo(size+size/2, 0);
path.lineTo(size, +size/2);
// YW: do not know how to show the regular clock view
// with inc of 5 mins on the contour
// can you help to fix this?
ellipse.setFrame(w/2-size*2-4.5f,h/2-size*2-4.5f,size*4,size*4);
double linApproxLen = 0.75 * size * 0.258819; // sin(15 degree)
PathIterator pi = ellipse.getPathIterator(null, linApproxLen);
Point2D[] points = new Point2D[100];
int num_pts = 0;
while ( !pi.isDone() )
{
float[] pt = new float[6];
switch ( pi.currentSegment(pt) ) {
case FlatteningPathIterator.SEG_MOVETO:
case FlatteningPathIterator.SEG_LINETO:
points[num_pts] = new Point2D.Float(pt[0], pt[1]);
num_pts++;
}
pi.next();
}
pts = new Point2D[num_pts];
System.arraycopy(points, 0, pts, 0, num_pts);
}
private Point2D[] computePoints(double w, double h, int n)
{
Point2D points[] = new Point2D[n];
double angleDeltaRad = Math.PI * 2 / n;
for (int i=0; i<n; i++)
{
double angleRad = i * angleDeltaRad;
double ca = Math.cos(angleRad);
double sa = Math.sin(angleRad);
double x = sa * w/2;
double y = ca * h/2;
points[i] = new Point2D.Double(x,y);
}
return points;
}
public void paint(Graphics g)
{
System.out.printf("seconds: %s, minutes: %d \n", second, minute);
Dimension d = getSize();
updateSecond(d.width, d.height);
if(oldMinute < minute || (oldMinute==59 && minute==0))
{
oldMinute = minute;
updateMinute(d.width, d.height);
}
if(oldHour < hour || (oldHour==12 && hour == 1) )
{
oldHour = hour;
updateHour(d.width, d.height);
}
Graphics2D g2 = createGraphics2D(d.width, d.height);
drawClockArms(d.width, d.height, g2);
g2.dispose();
g.drawImage(bimg, 0, 0, this);
}
public Graphics2D createGraphics2D(int w, int h) {
// standard Java 2D code
Graphics2D g2 = null;
if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) {
bimg = (BufferedImage) createImage(w, h);
reset(w, h);
}
g2 = bimg.createGraphics();
g2.setBackground(getBackground());
g2.clearRect(0, 0, w, h);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return g2;
}
private void drawClockArms(int w, int h, Graphics2D g2) {
ellipse.setFrame(w/2-size,h/2-size,size*2,size*2);
g2.setColor(Color.black);
g2.draw(ellipse);
for (int i = 0; i < lines.length; i++) {
AffineTransform at = AffineTransform.getTranslateInstance(w/2,h/2);
at.rotate(Math.toRadians(rAmt[i]));
g2.setStroke(strokes[i]);
g2.setColor(colors[i]);
g2.draw(at.createTransformedShape(lines[i]));
g2.draw(at.createTransformedShape(path));
}
g2.setStroke(bs1);
g2.setColor(Color.black);
for (int i = 0; i < pts.length; i++) {
ellipse.setFrame(pts[i].getX(), pts[i].getY(), 9, 9);
g2.draw(ellipse);
}
}
/**
* step forward on the display: move arm forward
*/
public void step(int w, int h) {
for (int i = 0; i < lines.length; i++)
{
rAmt[i] += speed[i];
System.out.println(rAmt[i]);
if (rAmt[i] == 360) {
rAmt[i] = 0;
}
}
}
public void updateSecond(int w, int h) {
rAmt[0] += speed[0];
if (rAmt[0] == 360) {
rAmt[0] = 0;
}
}
public void updateMinute(int w, int h) {
rAmt[1] += speed[1];
if (rAmt[1] == 360) {
rAmt[1] = 0;
}
}
public void updateHour(int w, int h) {
rAmt[2] += speed[2];
if (rAmt[2] == 360) {
rAmt[2] = 0;
}
}
}
and here is the parent class that extends JPanel:
/**
* Digital Clock view base classes
*/
abstract class DigitalClockView extends JPanel
{
protected int second = 0;
protected int minute = 0;
protected int hour = 0;
public void draw()
{
this.repaint();
}
public void updateTime(int second, int minute, int hour)
{
this.second = second;
this.minute = minute;
this.hour = hour;
}
public abstract void paint(Graphics g);
}
my menu buttons are showing on the right side when I use the menu bar. It's almost as if it is just cloning the view on the left side and showing it on the right side again. Why is this?
super.repaint()
Don't do that, as calling repaint from within a paint method has potential for danger. Call the super.paint(g) method inside of a paint(Graphics g) override.
Or even better yet, don't override paint but instead override your JPanel's paintComponent(Graphics g) method and call super.paintComponent(g). For graphics you must call the same super method as the overridden method, and you're not doing that.
Also and again, you should avoid use of null layout as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.

Cannot draw canvas with desired Bitmap after OnTouchEvent

I am making a tictactoe android application . After making on customview called TicTacToeGFX I tried to make an onTouchEvent which (after taking into account) the coordinates of the touch , it would fill the corresponding rectangle with the bitmap circle or cross. The Problem is that in the onTouchEvent I cannot redraw the canvas with the desired Bitmap. So my question is How to I re-draw a canvas after an onTouchEvent?
public class NewGame extends Activity {
TicTacToeGFX Game;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Game = new TicTacToeGFX(this);
setContentView(Game);
}
}
public class TicTacToeGFX extends View {
int x, y;
int rectanglescounter = 0;
public Rect[] rectangles = new Rect[9];
// BitMap
Bitmap cross = BitmapFactory.decodeResource(getResources(),
R.drawable.cross1);
Bitmap circle = BitmapFactory.decodeResource(getResources(),
R.drawable.circle1);
Bitmap empty = BitmapFactory.decodeResource(getResources(),
R.drawable.empty1);
Paint paint = new Paint();
Canvas canvas = new Canvas();
public TicTacToeGFX(Context context) {
super(context);
setFocusable(true);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// -------------------------------------------calculate
// screen------------------------------------------------------
x = (int) ((getWidth()) / 3);
y = (int) ((getHeight()) / 3);
// //------------------------------------------- calculate rectangle
// positions on
// screen------------------------------------------------------
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
rectangles[rectanglescounter] = new Rect((x * j), (y * i),
((x * j) + x), ((y * i) + y));
if (rectanglescounter < 8)
rectanglescounter++;
else
break;
}
}
// ------------------------------------------- draw the canvas with
// empty Bitmap
// ------------------------------------------------------
int counter = 0;
canvas.drawRGB(0, 0, 0);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
canvas.drawBitmap(empty, null, rectangles[counter], null);
counter++;
}
}
// ------------------------------------------- draw
// LinesS------------------------------------------------------
paint.setColor(Color.WHITE);
canvas.drawLine(x, 0, x, 3 * y, paint);// 1h
canvas.drawLine(2 * x, 0, 2 * x, 3 * y, paint);// 2h
canvas.drawLine(0, y, 3 * x, y, paint);// 3h
canvas.drawLine(0, 2 * y, 3 * x, 2 * y, paint);// 4h
}
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
x = (int) event.getX();
y = (int) event.getY();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
Toast.makeText(getContext(), "Hello", 1).show();
canvas.drawRGB(0, 0, 0);
invalidate();
break;
case MotionEvent.ACTION_MOVE: // touch drag with the ball
// move the balls the same as the finger
break;
}
return true;
}
}

Categories