I'm attempting to use notification badges as described HERE
It works flawlessly on my 4.4.2 device, but on my 4.0.4 device I get a crash on open.
I am getting this error and a force close even inside a try/catch.
Here is the offending code:
try {
Utils.setBadgeCount(this, ordersIcon, ordersCount, getResources().getColor(R.color.red_text));
Utils.setBadgeCount(this, balancesIcon, balancesCount, getResources().getColor(R.color.green_text));
} catch (Exception e) {
Toast.makeText(this, "Dynamic menu icons not available on this device.", Toast.LENGTH_LONG).show();
}
Commenting out the two lines inside the try block stops the fatal exception from being thrown.
Here's the setBadgeCount method.
public static void setBadgeCount(Context context, LayerDrawable icon, int count, int color) {
BadgeDrawable badge;
Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge);
if (reuse != null && reuse instanceof BadgeDrawable) {
badge = (BadgeDrawable) reuse;
} else {
badge = new BadgeDrawable(context, color);
}
badge.setCount(count);
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge, badge);
}
And the BadgeDrawable class:
public class BadgeDrawable extends Drawable {
private float mTextSize;
private Paint mBadgePaint;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();
private String mCount = "";
private boolean mWillDraw = false;
public BadgeDrawable(Context context, int color) {
mTextSize = context.getResources().getDimension(R.dimen.badge_text_size);
mBadgePaint = new Paint();
mBadgePaint.setColor(color);
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
mTextPaint = new Paint();
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
#Override
public void draw(Canvas canvas) {
if (!mWillDraw) {
return;
}
Rect bounds = getBounds();
float width = bounds.right - bounds.left;
float height = bounds.bottom - bounds.top;
// Position the badge in the top-right quadrant of the icon.
float radius = ((Math.min(width, height) / 2) - 1) / 2;
float centerX = width - radius - 1;
float centerY = radius + 1;
// Draw badge circle.
canvas.drawCircle(centerX, centerY, radius, mBadgePaint);
// Draw badge count text inside the circle.
mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
float textHeight = mTxtRect.bottom - mTxtRect.top;
float textY = centerY + (textHeight / 2f);
canvas.drawText(mCount, centerX, textY, mTextPaint);
}
/*
* Sets the count (i.e notifications) to display.
*/
public void setCount(int count) {
mCount = Integer.toString(count);
// Only draw a badge if there are notifications.
mWillDraw = count > 0;
invalidateSelf();
}
#Override
public void setAlpha(int alpha) {
// do nothing
}
#Override
public void setColorFilter(ColorFilter cf) {
// do nothing
}
#Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
Any ideas?
Use throwable instead of Exception
try {
Utils.setBadgeCount(this, ordersIcon, ordersCount, getResources().getColor(R.color.red_text));
Utils.setBadgeCount(this, balancesIcon, balancesCount, getResources().getColor(R.color.green_text));
} catch (**Throwable** e) {
Toast.makeText(this, "Dynamic menu icons not available on this device.", Toast.LENGTH_LONG).show();
}
Related
Is there some easy way to create a Button in LibGDX that contains several polygon drawables inside.
For example when the simple Button can be pictured like:
and advanced expected button like that:
And in my case following conditions must be met:
The Object must extends Button class.
Separated polygons (circle and triangle in pic) must have one common behavior - same up, down, hover styles, same click listeners ect. (for example when user hover circle the triangle and circle change color to green)
Actually it must have the absolutely same behavior as button with one polygon, just imagine that circle and triangle is one polygon, instead of separated ones.
The one way I figured out is to extend PolygonRegionDrawable, but to make it drawn correctly I need to override almost all methods from Drawable and TransformDrawable, is there any easier way to do that?
Maybe there can be found some DrawableGroup or something like that?
I dont think theres an easy way to make this work, here are some options.
Button is a Table, you can add stuff to it.
Button button = new Button(skin);
Image img = new Image(...); // insert polygon 1 here
img.setPostion(...); // offset so its in correct position in the button
button.addActor(img);
// add more stuff
Sadly this doesnt handle various state changes, like over etc. You would need to keep track of the added stuff and change them as button changes.
Other option is to make the polygons into single image.
Thats quite tricky, you would draw them into FrameBufferObject in correct places and make a textures out of that. Then use that texture for Drawable for the button style. Reapet for each state you want to handle. Packing them into and atlas would be optimal for perfomace reasons. A ton of texture switches is not great.
In order to reach such functionality I have implemented two additional classes that may assume a list of Drawables to draw it like only one.
So I just mention it here, I hope it may be useful for people who want to implement the same behavior.
An abstract class that assumes list of drawables and related coordinates in format:
[drawable1X, drawable1Y, drawable2X, drawable2Y, ..., drawableNX, drawableNY]
BulkBaseDrawable:
abstract class BulkBaseDrawable implements Drawable {
Array<Drawable> drawables;
private float leftWidth, rightWidth, topHeight, bottomHeight, minWidth, minHeight, leftX, bottomY, rightX, topY;
BulkBaseDrawable(Drawable[] drawables,
float... vertices) {
this.infos = new Array<>(drawables.length);
init(drawables, vertices);
}
#Override
public float getLeftWidth() {
return leftWidth;
}
#Override
public void setLeftWidth(float leftWidth) {
this.leftWidth = leftWidth;
}
#Override
public float getRightWidth() {
return rightWidth;
}
#Override
public void setRightWidth(float rightWidth) {
this.rightWidth = rightWidth;
}
#Override
public float getTopHeight() {
return topHeight;
}
#Override
public void setTopHeight(float topHeight) {
this.topHeight = topHeight;
}
#Override
public float getBottomHeight() {
return bottomHeight;
}
#Override
public void setBottomHeight(float bottomHeight) {
this.bottomHeight = bottomHeight;
}
#Override
public float getMinWidth() {
return minWidth;
}
#Override
public void setMinWidth(float minWidth) {
this.minWidth = minWidth;
}
#Override
public float getMinHeight() {
return minHeight;
}
#Override
public void setMinHeight(float minHeight) {
this.minHeight = minHeight;
}
void init(Drawable[] drawables, float[] vertices) {
initInfo(drawables, vertices);
initEdges();
initSize();
}
private void initInfo(Drawable[] drawables, float[] vertices) {
int i = 0;
for (Drawable drawable : drawables) {
infos.add(Info.builder()
.x(vertices[i])
.y(vertices[i + 1])
.width(drawable.getMinWidth())
.height(drawable.getMinHeight())
.drawable(drawable)
.build());
i += 2;
}
}
private void initSize() {
minHeight = topY - bottomY;
minWidth = rightX - leftX;
}
private void initEdges() {
topY = Float.MIN_VALUE;
rightX = Float.MIN_VALUE;
bottomY = Float.MAX_VALUE;
leftX = Float.MAX_VALUE;
int topI = 0;
int rightI = 0;
int bottomI = 0;
int leftI = 0;
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
if (info.y + info.height > topY) {
topY = info.y + info.height;
topI = i;
}
if (info.x + info.width > rightX) {
rightX = info.x + info.width;
rightI = i;
}
if (info.y < bottomY) {
bottomY = info.y;
bottomI = i;
}
if (info.x < leftX) {
leftX = info.x;
leftI = i;
}
}
Drawable top = infos.get(topI).drawable;
Drawable right = infos.get(rightI).drawable;
Drawable bottom = infos.get(bottomI).drawable;
Drawable left = infos.get(leftI).drawable;
leftWidth = left.getLeftWidth();
rightWidth = right.getRightWidth();
topHeight = top.getTopHeight();
bottomHeight = bottom.getBottomHeight();
}
static class Info {
float x, y, width, height;
Drawable drawable;
static InfoBuilder builder() {
return new InfoBuilder();
}
static class InfoBuilder {
float x, y, width, height;
Drawable drawable;
InfoBuilder x(float x) {
this.x = x;
return this;
}
InfoBuilder y(float y) {
this.y = y;
return this;
}
InfoBuilder width(float width) {
this.width = width;
return this;
}
InfoBuilder height(float height) {
this.height = height;
return this;
}
InfoBuilder drawable(Drawable drawable) {
this.drawable = drawable;
return this;
}
Info build() {
return new Info(x, y, width, height, drawable);
}
}
public Info(float x, float y, float width, float height, Drawable drawable) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.drawable = drawable;
}
}
}
And actually implementation BulkRegionDrawable:
public class BulkRegionDrawable extends BulkBaseDrawable {
public BulkRegionDrawable(Drawable[] drawables, float[] vertices) {
super(drawables, vertices);
}
#Override
public void draw(Batch batch,
float x,
float y,
float width,
float height) {
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
float yK = info.height / getMinHeight();
float xK = info.width / getMinWidth();
info.drawable.draw(
batch,
x + (info.x * width) / getMinWidth(),
y + (info.y * height) / getMinHeight(),
width * xK,
height * yK);
}
}
}
So I have two classes here:
PhotoComponent class:
(This class is to handle a specific image as a JComponent. When "flipped" I want to draw pen strokes instead of having an image. So I replace the image with a rectangle, attempting to draw pen strokes over it.)
public class PhotoComponent extends JComponent {
private Image pic;
private boolean flipped;
private int contentAreaWidth;
private int contentAreaHeight;
p
#Override
public void paintComponent(Graphics g) {
//Does all the drawing and contains whatever state information is associated with the photo
//create an action event to auto call repaint
//call repaint anytime flip was changed to true or false
System.out.println("Draw: " + draw + ", Pic: " + pic);
if (draw && pic != null) {
super.paintComponent(g);
System.out.println("width using this: " + this.getWidth() + ", actual width of JPanel: " + contentAreaWidth);
System.out.println("height using this: " + this.getHeight() + ", actual height of JPanel: " + contentAreaHeight);
g2 = (Graphics2D) g;
int x = (contentAreaWidth - pic.getWidth(null)) / 2;
int y = (contentAreaHeight - pic.getHeight(null)) / 2;
if (!flipped) {
g2.drawImage(pic, x, y, null);
} else if (flipped) {
g2.setColor(Color.WHITE);
g2.fillRect(x,y,pic.getWidth(null), pic.getHeight(null));
g2.drawRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (drawingMode) {
g2.setPaint(Color.RED);
if (drawOval) {
penStrokes.put(ovalX, ovalY);
if (penStrokes != null) {
for (Integer xCoor : penStrokes.keySet()) {
g2.setPaint(Color.RED);
int brushSize = 5;
g2.fillOval((xCoor - (brushSize / 2)), (penStrokes.get(xCoor) - (brushSize / 2)), brushSize, brushSize);
//System.out.println("SIZE OF HASHTABLE: " + penStrokes.size());
}
}
System.out.println("Filling an oval!" + ovalX + ", " + ovalY);
}
} else if (textMode) {
g2.setPaint(Color.YELLOW);
if (drawRect) {
rectDimensions.add(rectX);
rectDimensions.add(rectY);
rectDimensions.add(rectWidth);
rectDimensions.add(rectHeight);
for (int i = 0; i < rectDimensions.size(); i+=4) {
g2.fillRect(rectDimensions.get(i), rectDimensions.get(i+1), rectDimensions.get(i+2), rectDimensions.get(i+3));
g2.drawRect(rectDimensions.get(i), rectDimensions.get(i+1), rectDimensions.get(i+2), rectDimensions.get(i+3));
}
}
}
System.out.println("This is being called again!");
}
}
}
public void setRectangle(int x, int y, int width, int height) {
drawRect = true;
rectX = x;
rectY = y;
rectWidth = width;
rectHeight = height;
}
public void removeRectangle() {
drawRect = false;
}
public int[] setOval(int currentX, int currentY) {
drawOval = true;
int[] toReturn = {ovalX, ovalY};
ovalX =
NOTE THE DRAWLINE() METHOD ABOVE. I am drawing at the given points, repainting, and setting the old variables to be the current variables.
Main class:
private static PhotoComponent img;
private static JFrame frame;
private static JPanel contentArea;
//Mouse Coordinates for PenStrokes
private static int oldX, oldY;
//Mouse Coordinates for Sticky Notes
private static Point clickPoint;
public static void main (String[] args) {
frame = new JFrame("PhotoManip");
img = null;
contentArea = null;
oldX = 0;
oldY = 0;
setupMenubar(frame);
setupJFrame(frame);
}
private static void addPhotoComponent(File file) {
}
if (img.getTextMode()) {
img.removeRectangle();
clickPoint = null;
}
}
});
img.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (img.getDrawingMode()) {
if (withinRange(e.getX(), e.getY())) {
int[] toUpdate = img.setOval(e.getX(), e.getY());
oldX = toUpdate[0];
oldY = toUpdate[1];
img.repaint();
}
}
if (img.getTextMode()) {
if (withinRange(e.getX(), e.getY())) {
Point dragPoint = e.getPoint();
h, height);
img.repaint();
}
}
}
});
if (img!=null) {
contentArea.add(img);
}
}
private static boolean withinRange(int x, int y) {
if (x > img.getX() && x < img.getX() + img.getWidth()) {
if (y > img.getY() && y < img.getY() + img.getHeight()) {
return true;
}
}
return false;
}
private static void flipImage() {
if (!img.isFlipped()) {
img.setFlipped(true);
} else if (img.isFlipped()) {
img.setFlipped(false);
}
}
drawLine() is called above in this main class, when a mousedrag occurs. Problem is that the strokes don't appear to show.
I know that the program is calling g2.fillOval() because I am printing out a verification statement afterwards.
Additionally, I have created print statements for when the mouse is pressed and dragged and they are getting the correct coordinates?
Why don't red strokes appear? I'm confused. Is it the way my code is structured?
The crux of your problem is that you are trying to draw something outside the paintComponent method, which is never supported. Whatever you draw will get overwritten by the next call of paintComponent, which will happen almost instantly. We can solve this by storing the co-ordinates of the oval and drawing it within paintComponent instead of trying to draw on a graphics object outside of the paintComponent method. See code below:
First we are going to add the following variables to your PhotoComponent class:
private boolean drawOval = false;
private int ovalX = 0;
private int ovalY = 0;
Then we will add methods for controlling them:
public int[] setOval(int currentX, int currentY) {
drawOval = true;
int[] toReturn = {ovalX, ovalY};
ovalX = currentX;
ovalY = currentY;
return toReturn;
}
public void removeOval() {
drawOval = false;
}
After that we can change the paintComponent method to have it draw the oval based on those variables:
#Override
public void paintComponent(Graphics g) {
//Does all the drawing and contains whatever state information is associated with the photo
//create an action event to auto call repaint
//call repaint anytime flip was changed to true or false
super.paintComponent(g);
g2 = (Graphics2D) g;
int x = (contentAreaWidth - pic.getWidth(null)) / 2;
int y = (contentAreaHeight - pic.getHeight(null)) / 2;
if (!flipped) {
g2.drawImage(pic, x, y, null);
} else if (flipped) {
g2.setColor(Color.WHITE);
g2.fillRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.drawRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.RED);
}
//took the code you already used for drawing the oval and moved it here
if (drawOval) {
g2.setPaint(Color.RED);
int brushSize = 5;
g2.fillOval((ovalX - (brushSize / 2)), (ovalY - (brushSize / 2)), brushSize, brushSize);
}
}
Finally change the addPhotoComponent method to update those variables instead of trying to draw the oval directly:
private static void addPhotoComponent(File file) {
Image image = null;
try {
image = ImageIO.read(file);
} catch (IOException e2) {
System.out.println("ERROR: Couldn't get image.");
}
img = new PhotoComponent(image, contentArea);
img.revalidate();
img.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
// your code here
System.out.println("You flipped the photo!!!");
flipImage();
img.repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
img.setOval(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
img.removeOval();
}
});
img.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int[] toUpdate = img.setOval(e.getX(), e.getY());
oldX = toUpdate[0];
oldY = toUpdate[1];
}
});
if (img != null) {
contentArea.add(img);
}
}
I'm trying to make this game app.
I basically have this BitMap bMapEgg moving down every time UpdateCourt() gets called in a Surfaceview ChickenView. The problem I'm facing is that it looks really chunky. The movement of the bitmap doesn't look smooth.
ballPosition.y += 18; is the code that makes it move.
Any ideas how to make it look smooth?
public class MainActivity extends Activity implements View.OnTouchListener{
static Canvas canvas;
static ChickenView chickenView;
//Used for getting display details like the number of pixels
static Display display;
static Point size;
static int screenWidth;
static int screenHeight;
static Point ballPosition;
static int ballWidth;
static boolean ballIsMovingDown;
//stats
static long lastFrameTime;
static int fps;
static int score;
static int lives;
static float bitmapPositionX ;
static float bitmapPositionY ;
static float bitmapWidth ;
static float bitmapHeight;
static Bitmap bMapEgg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chickenView = (ChickenView) findViewById(R.id.chickenView);
//Get the screen size in pixels
display = getWindowManager().getDefaultDisplay();
size = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(size);
}
screenWidth = size.x;
screenHeight = size.y;
ballWidth = screenWidth / 35;
ballPosition = new Point();
ballPosition.x = screenWidth / 2;
ballPosition.y = 1 + ballWidth;
final ImageView imageEggs = (ImageView)findViewById(R.id.imageEggs);
final ImageView imageUpgrade = (ImageView)findViewById(R.id.imageUpgrade);
TextView test = (TextView)findViewById(R.id.textEggs);
imageUpgrade.setOnTouchListener(this);
chickenView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.imageUpgrade:
if (event.getAction() == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX();
final int y = (int) event.getY();
//now map the coords we got to the
//bitmap (because of scaling)
ImageView imageView = ((ImageView)v);
Bitmap bitmap =((BitmapDrawable)imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
//now check alpha for transparency
int alpha = Color.alpha(pixel);
if (alpha != 0) {
//do whatever you would have done for your click event here
Intent i;
i = new Intent(this, StructureActivity.class);
startActivity(i);
}
}
break;
case R.id.chickenView:
float x = event.getX();
float y = event.getY();
// Replace these with the correct values (bitmap x, y, width & height)
float x1 = bitmapPositionX;
float x2 = x1 + bitmapWidth;
float y1 = bitmapPositionY;
float y2 = y1 + bitmapHeight;
// Test to see if touch is inside the bitmap
if (x > x1 && x < x2 && y > y1 && y < y2) {
// Bitmap was touched
Log.v("test", "test");
} else {
Log.v("werkt ghil ni", "test");
}
break;
}
return true;
}
static class ChickenView extends SurfaceView implements Runnable {
Thread ourThread = null;
SurfaceHolder ourHolder;
volatile boolean playingSquash;
Paint paint;
public ChickenView(Context context) {
super(context);
init(context);
}
public ChickenView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ChickenView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
ourHolder = getHolder();
paint = new Paint();
ballIsMovingDown = true;
}
#Override
public void run() {
while (playingSquash) {
updateCourt();
drawCourt();
controlFPS();
}
}
public void updateCourt() {
//depending upon the two directions we should be
//moving in adjust our x any positions
if (ballIsMovingDown) {
ballPosition.y += 18;
}
//if hits bottom
if (ballPosition.y > screenHeight - 7*ballWidth) {
ballIsMovingDown = false;
}
}
public void drawCourt() {
if (ourHolder.getSurface().isValid()) {
canvas = ourHolder.lockCanvas();
//Paint paint = new Paint();
canvas.drawColor(Color.BLACK);//the background
paint.setColor(Color.argb(255, 255, 255, 255));
paint.setTextSize(45);
canvas.drawText("Score:" + score + " Lives:" + lives + " fps:" + fps, 20, 40, paint);
Bitmap bMapEgg = BitmapFactory.decodeResource(getResources(), R.drawable.egg);
bMapEgg = scaleDown(bMapEgg,180, true);
Bitmap bMapBackground = BitmapFactory.decodeResource(getResources(), R.drawable.backgrounddd);
canvas.drawBitmap(bMapBackground, 0, 0, paint);
canvas.drawBitmap(bMapEgg, ballPosition.x, ballPosition.y, paint);
bitmapPositionX = ballPosition.x;
bitmapPositionY = ballPosition.y;
bitmapWidth = bMapEgg.getWidth();
bitmapHeight = bMapEgg.getHeight();
ourHolder.unlockCanvasAndPost(canvas);
}
}
public void controlFPS() {
long timeThisFrame = (System.currentTimeMillis() - lastFrameTime);
long timeToSleep = 15 - timeThisFrame;
if (timeThisFrame > 0) {
fps = (int) (1000 / timeThisFrame);
}
if (timeToSleep > 0) {
try {
ourThread.sleep(timeToSleep);
} catch (InterruptedException e) {
}
}
lastFrameTime = System.currentTimeMillis();
}
public void pause() {
playingSquash = false;
try {
ourThread.join();
} catch (InterruptedException e) {
}
}
public void resume() {
playingSquash = true;
ourThread = new Thread(this);
ourThread.start();
}
}
#Override
protected void onStop() {
super.onStop();
while (true) {
chickenView.pause();
break;
}
finish();
}
#Override
protected void onResume() {
super.onResume();
chickenView.resume();
}
#Override
protected void onPause() {
super.onPause();
chickenView.pause();
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
chickenView.pause();
finish();
return true;
}
return false;
}
public static Bitmap scaleDown(Bitmap realImage, float maxImageSize,
boolean filter) {
float ratio = Math.min(
(float) maxImageSize / realImage.getWidth(),
(float) maxImageSize / realImage.getHeight());
int width = Math.round((float) ratio * realImage.getWidth());
int height = Math.round((float) ratio * realImage.getHeight());
Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width,
height, filter);
return newBitmap;
}
}
The problem is that in each frame you decode and scale all bitmaps all over again.
Move your bitmaps decoding and scaling out of the draw method, put it in an initialization method and store decoded and scaled bitmaps in member variables (maybe even static ones) so you can just reuse them for drawing in each frame.
I am trying to used OpenCV java wrapper to detect faces in an app.
1) The app is using front-facing camera in potrait mode.
2) The preview is displayed inside a SurfaceView.
3) I am using Android's onPreviewFrame()'s byte[] data and changing it into OpenCV format to detect the faces using OpenCV.
4) I send the coordinates detected by mJavaDetector to a View class to be drawn on a instance of the drawingView surface.
When I start the application, there are no errors but no rectangle is drawn. The
Log.v(TAG, "Length of facesArray" + facesArray.length);
inside SurfaceChanged is also not displayed. Is it because the onPreviewFrame() is not called or a problem with my OpenCV implementation or other problems?
I have attached my codes below.
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
/**if(previewing){
//mCamera.stopFaceDetection();
mCamera.stopPreview();
previewing = false;
}**/
if (mCamera != null){
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera mCamera) {
Log.d(TAG, "ON Preview frame");
int mAbsoluteFaceSize = 0;
int width = surfaceView.getWidth();
int height = surfaceView.getHeight();
Mat img = new Mat(height, width, CvType.CV_8UC1);
Mat gray = new Mat(height, width, CvType.CV_8UC1);
img.put(0, 0, data);
Imgproc.cvtColor(img, gray, Imgproc.COLOR_YUV420sp2GRAY);
MatOfRect faces = new MatOfRect();
if (mJavaDetector != null)
mJavaDetector.detectMultiScale(gray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
Rect[] facesArray = faces.toArray();
Log.v(TAG, "Length of facesArray" + facesArray.length);
if(facesArray != null){
drawingView.setHaveFace(true);
}
for (int i = 0; i < facesArray.length; i++){
double l = facesArray[i].tl().x;
double t = facesArray[i].tl().y;
double r = facesArray[i].br().x;
double b = facesArray[i].br().y;
drawingView.setCoordinates(l, t, r, b);
}
}
});
/**prompt.setText(String.valueOf(
"Max Face: " + mCamera.getParameters().getMaxNumDetectedFaces()));
mCamera.startFaceDetection();
previewing = true;**/
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Class DrawingView:
private class DrawingView extends View{
boolean haveFace;
Paint drawingPaint;
float left;
float top;
float right;
float bottom;
public DrawingView(Context context) {
super(context);
haveFace = false;
drawingPaint = new Paint();
drawingPaint.setColor(Color.GREEN);
drawingPaint.setStyle(Paint.Style.STROKE);
drawingPaint.setStrokeWidth(2);
}
public void setHaveFace(boolean h){
haveFace = h;
}
public void setCoordinates(double l,double t, double r, double b){
left = (float)l;
top = (float)t;
right = (float)r;
bottom = (float)b;
}
#Override
protected void onDraw(Canvas canvas) {
if(haveFace){
canvas.drawRect(
left, top, right, bottom,
drawingPaint);
}
else{
canvas.drawColor(Color.TRANSPARENT);
}
}
}
My drawingView declaration in onCreate():
drawingView = new DrawingView(this);
LayoutParams layoutParamsDrawing
= new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
this.addContentView(drawingView, layoutParamsDrawing);
I'm trying to create a custom extension of BasicSliderUI. I'm just trying to make the thumb a circle (note I'm in the Windows L&F). I've created a very simple implementation that just calls g.drawOval, but whenever I drag it, it leaves a "trail" behind. Any ideas why this is?
thanks,
Jeff
You need to call repaint on the whole thing, you cant just draw the oval on top of it. Swing will by default only repaint what needs to be repainted, which usually isn't the whole control. When are you drawing the circle?
If you want to get rid of "trail" when you drag you should write your custom TrackListener and control trumb position related to mouse move.
Look at my implementation:
public class LightSliderUI extends BasicSliderUI{
private final Color rangeColor = Color.BLUE;
private final BasicStroke stroke = new BasicStroke(2f);
private transient boolean upperDragging;
public LightSliderUI(JSlider b) {
super(b);
}
public static ComponentUI createUI(JComponent c) {
return new LightSliderUI((JSlider)c);
}
#Override
protected void calculateThumbSize() {
super.calculateThumbSize();
thumbRect.setSize(thumbRect.width, thumbRect.height);
}
/** Creates a listener to handle track events in the specified slider.*/
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new RangeTrackListener();
}
#Override
protected void calculateThumbLocation() {
// Call superclass method for lower thumb location.
super.calculateThumbLocation();
// Adjust upper value to snap to ticks if necessary.
if (slider.getSnapToTicks()) {
int upperValue = slider.getValue() + slider.getExtent();
int snappedValue = upperValue;
int majorTickSpacing = slider.getMajorTickSpacing();
int minorTickSpacing = slider.getMinorTickSpacing();
int tickSpacing = 0;
if (minorTickSpacing > 0) {
tickSpacing = minorTickSpacing;
} else if (majorTickSpacing > 0) {
tickSpacing = majorTickSpacing;
}
if (tickSpacing != 0) {
// If it's not on a tick, change the value
if ((upperValue - slider.getMinimum()) % tickSpacing != 0) {
float temp = (float)(upperValue - slider.getMinimum()) / (float)tickSpacing;
int whichTick = Math.round(temp);
snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
}
if (snappedValue != upperValue) {
slider.setExtent(snappedValue - slider.getValue());
}
}
}
// Calculate upper thumb location. The thumb is centered over its
// value on the track.
if (slider.getOrientation() == JSlider.HORIZONTAL) {
int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = upperPosition - (thumbRect.width / 2);
thumbRect.y = trackRect.y;
} else {
int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = trackRect.x;
thumbRect.y = upperPosition - (thumbRect.height / 2);
}
slider.repaint();
}
/** Returns the size of a thumb.
* Parent method not use size from LaF
* #return size of trumb */
#Override
protected Dimension getThumbSize() {
return Dimensions.getSliderThumbSize();
}
private Shape createThumbShape(int width, int height) {
Ellipse2D shape = new Ellipse2D.Double(0, 0, width, height);
return shape;
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Colors.TEXT_STEEL);
Color oldColor = Colors.TEXT_STEEL;
Rectangle trackBounds = trackRect;
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
int lowerX = thumbRect.width / 2;
int upperX = thumbRect.x + (thumbRect.width / 2);
int cy = (trackBounds.height / 2) - 2;
g2d.translate(trackBounds.x, trackBounds.y + cy);
g2d.setColor(rangeColor);
g2d.drawLine(lowerX - trackBounds.x, 2, upperX - trackBounds.x, 2);
g2d.translate(-trackBounds.x, -(trackBounds.y + cy));
g2d.setColor(oldColor);
}
g2d.setStroke(old);
}
/** Overrides superclass method to do nothing. Thumb painting is handled
* within the <code>paint()</code> method.*/
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = knobBounds.height;
Graphics2D g2d = (Graphics2D) g.create();
Shape thumbShape = createThumbShape(w - 1, h - 1);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(knobBounds.x, knobBounds.y);
g2d.setColor(Color.WHITE);
g2d.fill(thumbShape);
g2d.setColor(Colors.BIOLIN_BLUE_TINT);
g2d.draw(thumbShape);
g2d.dispose();
}
/** Listener to handle model change events. This calculates the thumb
* locations and repaints the slider if the value change is not caused by dragging a thumb.*/
public class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent arg0) {
calculateThumbLocation();
slider.repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JSlider slider = new JSlider(0, 100);
slider.setPaintTicks(true);
slider.setUI(new LightSliderUI(slider));
frame.add(slider);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
/** Listener to handle mouse movements in the slider track.*/
public class RangeTrackListener extends TrackListener {
#Override
public void mouseClicked(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX -= thumbRect.width / 2; // Because we want the mouse location correspond to middle of the "thumb", not left side of it.
moveUpperThumb();
}
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (slider.isRequestFocusEnabled()) {
slider.requestFocus();
}
boolean upperPressed = false;
if (slider.getMinimum() == slider.getValue()) {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
} else {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
}
if (upperPressed) {
switch (slider.getOrientation()) {
case JSlider.VERTICAL:
offset = currentMouseY - thumbRect.y;
break;
case JSlider.HORIZONTAL:
offset = currentMouseX - thumbRect.x;
break;
}
//upperThumbSelected = true;
upperDragging = true;
return;
}
upperDragging = false;
}
#Override
public void mouseReleased(MouseEvent e) {
upperDragging = false;
slider.setValueIsAdjusting(false);
super.mouseReleased(e);
}
#Override
public void mouseDragged(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (upperDragging) {
slider.setValueIsAdjusting(true);
moveUpperThumb();
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
/** Moves the location of the upper thumb, and sets its corresponding value in the slider.*/
public void moveUpperThumb() {
int thumbMiddle = 0;
switch (slider.getOrientation()) {
case JSlider.HORIZONTAL:
int halfThumbWidth = thumbRect.width / 2;
int thumbLeft = currentMouseX - offset;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int hMax = xPositionForValue(slider.getMaximum() -
slider.getExtent());
if (drawInverted()) {
trackLeft = hMax;
}
else {
trackRight = hMax;
}
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
setThumbLocation(thumbLeft, thumbRect.y);//setThumbLocation
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setValue(valueForXPosition(thumbMiddle));
break;
default:
return;
}
}
}
}