BlackBerry - ButtonField with centered Bitmap - user-interface

I have a class that extends from ButtonField :
class BitmapButtonField extends ButtonField
{
private Bitmap _bitmap;
private int _buttonWidth;
private int _buttonHeight;
BitmapButtonField(Bitmap bitmap, int buttonWidth, int buttonHeight, long style)
{
super(style);
_buttonWidth = buttonWidth;
_buttonHeight = buttonHeight;
_bitmap = bitmap;
}
public int getPreferredHeight()
{
return _buttonHeight;
}
public int getPreferredWidth()
{
return _buttonWidth;
}
protected void layout(int width, int height)
{
setExtent(Math.min( width, getPreferredWidth()), Math.min( height, getPreferredHeight()));
}
protected void paint(Graphics graphics)
{
// THIS IS NOT CENTERED
int x = (getPreferredWidth() - _bitmap.getWidth()) >> 1;
graphics.drawBitmap(x, 0, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0);
// THIS IS NOT LEFTMOST, TOPMOST
graphics.drawBitmap(0, 0, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0);
}
}
If you could see from my comments on the paint method, clearly the ButtonField 0,0 position is not exactly in leftmost and topmost corner of the button, somehow it is padded with unknown offset, so this makes centering the image is difficult.
But if I extend from a Field class, the problem goes away, but I need to keep extending from ButtonField since I need the ButtonField border and focus style (blue-white rounded rectangle), I just need to display centered image on a ButtonField, and still retaining all of the standard ButtonField attributes.
Is there a way to eliminate the padded offset in paint method on a ButtonField? I've tried setPadding and setMargin but no such luck. Thanks a lot!

In paint() to define x offset for image there is a code:
int x = (getPreferredWidth() - _bitmap.getWidth()) >> 1;
It is ok, still button can have other size, because of:
protected void layout(int width, int height)
{
setExtent(Math.min( width, getPreferredWidth()),
Math.min( height, getPreferredHeight()));
}
Try to use
protected void layout(int width, int height)
{
setExtent(getPreferredWidth(), getPreferredHeight());
}

Related

Centering an Actor horizontally and vertically causes the bounds to be wrong

I have a button in the center of my stage and want to scale it from the center as soon as the user starts to tap on it and then reset the scale as soon as he releases his finger.
This is the code I use:
private int size;
private Texture texture;
private Action scaleAction, scaleDownAction;
public PlayButtonActor(int x, int y, int size) {
this.size = size;
setBounds(x, y, size, size);
this.texture = new Texture("data/play_button.png");
this.setTouchable(Touchable.enabled);
setOrigin(size / 2, size / 2);
final float finalSize = size;
addListener(new InputListener() {
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
event.handle();
removeAction(scaleAction);
scaleDownAction = Actions.parallel(
Actions.scaleTo(1f, 1f, 0.1f)
);
addAction(scaleDownAction);
}
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
removeAction(scaleDownAction);
scaleAction = Actions.parallel(
Actions.scaleTo(1.4f, 1.4f, 0.2f)
);
addAction(scaleAction);
return true;
}
});
}
#Override
public void draw(Batch batch, float parentAlpha) {
final float realSize = this.getScaleX() * size;
batch.draw(this.texture, this.getX() - realSize / 2, this.getY() - realSize / 2, realSize, realSize);
}
This works as it successfully scales the button, however only the top right quadrant of the button is clickable.
How can I make it so that the button scales from / to the center while the bounds of it are still correct all the time?
Thanks in advance!
Don't set the texture, but add the texture as an Image:
add(new Image(texture));
then scale the image. The clickable Area will always be the full Button size, independant from the image scaling.

get() throws ArrayIndexOutOfBoundsException

I need to create an overlay image with variable-defined size. However, if I use surface.setSize() when I then try to store the resulting image with get() the sketch crashes with ArrayIndexOutOfBoundsException. Why? Does size() initialize the canvas differently?
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
surface.setSize(w, h); // remove it, and you're ok
background(0); // draw something
overlay = get(); // exception
}
I'm guessing that you're using surface.setSize() instead of size() because you got an error when you tried to pass variables into the size() function?
The solution to that problem is not to call the surface.setSize() function. Instead, you should define a settings() function that then calls the size() function with variables as parameters. The rest of your code would remain in the setup() function.
final int w = 320;
final int h = 240;
PImage overlay;
void settings() {
size(w, h);
}
void setup() {
background(0);
overlay = get();
}
More info can be found in the reference.
Another approach would be to get rid of the w and h variables entirely, and just pass in numbers to the size() function. Then you could just use the width and height variables wherever you were previously using the w and h variables.
Have a look at this issue, I can't comment much on the "why" of things here but as far as I can understand, setSize() runs after setup is finished because it can't run while things(in this case, the background) are being drawn. Moving that line to the end of setup doesn't produce the out of bounds exception:
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
background(0,200,150);
overlay = get();
surface.setSize(w, h);
}
void draw() {
tint(0,200,0);
image(overlay,50,0);
}
Edit: It seems like the get() in this case is grabbing only the default window size of pixels
There is a workaround for that- you can start by declaring size with some reasonable or basically any dimensions bigger than w and h, then use the get() method with 4 parameters to grab the image according to the w and h dimensions:
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
size(1000, 1000); //can be any numbers greater than w and h
background(0, 200, 150);
surface.setSize(w, h);
overlay = get(0, 0, w, h);
}
void draw() {
tint(0, 200, 0);
image(overlay, 50, 0);
}

How to remove previous shape after draw() in Processing

I cant figure this out. I have a sketch with little rotating rectangles on it. They rotate on every draw(). However the previous rectangle remains visible. I tried moving background() around but it either gets rid of all the rectangles apart from one or it doesn't clear the screen. I would like to be able to clear all the rectangles after each draw.
Here is the code:
//Create array of objects
ArrayList<Circle> circles = new ArrayList<Circle>();
ArrayList<Connector> centrePoint = new ArrayList<Connector>();
void setup(){
size(800, 800);
frameRate(1);
rectMode(CENTER);
background(204);
for(int i = 1; i < 50; i++){
float r = random(100,height-100);
float s = random(100,width-100);
float t = 20;
float u = 20;
println("Print ellipse r and s " + r,s);
circles.add(new Circle(r,s,t,u,color(14,255,255),random(360),random(5),random(10)));
}
//Draw out all the circles from the array
for(Circle circle : circles){
circle.draw();
float connectStartX = circle.x1;
float connectStartY = circle.y1;
println("PrintconnectStartX and Y " + connectStartX,connectStartY);
for(Circle circleEnd : circles){
float connectEndX = (circleEnd.x1);
float connectEndY = (circleEnd.y1);
centrePoint.add(new Connector(connectStartX,connectStartY,connectEndX,connectEndY));
}
}
//For each ellipse, add the centre point of the ellipse to array
for(Connector connectUp : centrePoint){
println(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
stroke(100, 0, 0);
if (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75){
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
//For the line weight it should equal the fat of the node it has come from ie
//for each circle, for each connectUp if the x==connectStartX and y==connectStartY then make the line strokeWeight==fat
for(Circle circle : circles){
for(Connector connectUp : centrePoint){
if (connectUp.connectStartX == circle.x1 & connectUp.connectStartY == circle.y1 & (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75)){
print(" true "+ circle.fat);
float authority = circle.fat;
strokeWeight(authority*1.5);
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
}
}
void update(){
}
void draw() {
for(Circle circle : circles){
circle.rot =+0.02;
circle.draw();
circle.rot = random(-6,6);
}
}
//Need to connect each ellipse to all the other ellipses
class Connector {
public float connectStartX;
public float connectStartY;
public float connectEndX;
public float connectEndY;
public color cB;
public float thickness;
public Connector(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
this.connectStartX = connectStartX;
this.connectStartY = connectStartY;
this.connectEndX = connectEndX;
this.connectEndY = connectEndY;
//this.cB = tempcB;
//this.thickness = thickness;
}
void draw(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
line(connectStartX, connectStartY, connectEndX, connectEndY);
// float fat = random(255);
//fill(fat);
stroke(100, 0, 0);
}
}
class Circle{
public float x1;
public float y1;
public float x2;
public float y2;
public color cB;
public float rot;
public float fat = random(5);
public float fert = 0.1;
public Circle(float x1, float y1, float x2, float y2, color tempcB, float rot, float fat, float fert){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.cB = tempcB;
//Tilt - I think this is done in radians
this.rot = rot;
//Authority -this is the fill
this.fat = fat;
//Fertility- this is a multiplier for the tilt
this.fert = fert;
}
void draw(){
pushMatrix();
translate(x1, y1);
fert = random(0.5);
rot = random(-6,6);
rotate(rot*fert);
translate(-x1, -y1);
//float fat = random(255);
fill(fat);
rect(x1, y1, 24, 36);
popMatrix();
}
}
You've got a few things going on in your code that I've seen in your previous posts. The way you're doing your drawing doesn't make a ton of sense, and I'll explain why.
Here's what most Processing sketches do:
Use the setup() function to setup any data structures you'll use in your program. Don't do any drawing from the setup() function.
Call background() every frame to clear out old frames.
Draw everything you want to be drawn in the frame in the draw() function.
Modify the data structures to change what you're drawing on the screen.
Your code is a bit too long for an MCVE, so here's a little example that handles the drawing in a more standard way:
ArrayList<PVector> circles = new ArrayList<PVector>();
void setup() {
size(500, 500);
ellipseMode(RADIUS);
//setup your data structures here
circles.add(new PVector(250, 250));
//don't do any drawing yet
}
void mousePressed() {
//modify the data structure whenever you want to change what's on the screen
circles.add(new PVector(mouseX, mouseY));
}
void keyPressed() {
//modify the data structure whenever you want to change what's on the screen
if (!circles.isEmpty()) {
circles.remove(0);
}
}
void draw() {
//call background every frame to clear out old frames
background(0);
//draw everything
for (PVector p : circles) {
ellipse(p.x, p.y, 20, 20);
}
}
Notice how this is different from what you're doing. Here's what you do:
You use the setup() function to setup your data structures, but then you draw the background and some of the objects to the screen.
You then don't call background() from draw(), so you're always stuck with whatever has already been drawn.
You then only draw a subset of what you want on the screen, so you can't redraw your whole scene.
You have to modify your code to no longer draw anything from setup(), to call the background() function every frame, and to draw everything you want on the screen every frame.
What you are doing is printing every single circle or line...ect. You need to have a timer that removes them every so often. If you do it too fast you get a strobe like look. So have a timer that removes the first rect from the array list every so often.

How to create Rounded Rectangle Buttons in MFC

I need to create Rounded Rectangle Buttons in MFC. I tried several resources but did not found the correct way of explanation. Even in **Code Project ** I founded circular or elliptical buttons.
Please suggest how we can create Rounded Rectangle Buttons or any other article
My answers are...
1. Use Skin Library.
I usually use Codejock SkinFramework.
That's ver easy. Include XTSkinFrameworkPro.h in your stdafx.h then load skin file before your dialog is invoked.
XTPSkinManager()->LoadSkin(_T("..."));
2-1. Draw by yourself.
Most simple one is here. Read it first.
https://vcpptips.wordpress.com/tag/owner-draw-button-control/
Then use this code for making round button. It would be nicer if you slide the label text 1px to right-bottom when they hit the button.
http://www.codeproject.com/Articles/11683/CRoundButton-A-fancy-graphical-button
2-2. Draw by yourself. (Use bitmap)
The other one is using bitmap button. Make a bitmap image of rounded button then set it to your button.
how to add bitmap image to buttons in MFC?
Exsample:
Save below as a SimpleBitmapButton.h and include it in your project.
#pragma once
#include <afxwin.h>
class CSimpleBitmapButton : public CButton
{
DECLARE_DYNAMIC(CSimpleBitmapButton)
protected:
enum EButtonState
{
NORMAL = 0,
PUSHED = 1
};
public:
CSimpleBitmapButton();
BOOL Open( int resource_id );
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
protected:
int Width, Height;
BOOL Pushed;
CBitmap Bitmap;
};
Save below as a SimpleBitmapButton.cpp and include it in your project.
#include "stdafx.h"
#include "SimpleBitmapButton.h"
const int BUTTON_IMAGE_NUM = 2;
IMPLEMENT_DYNAMIC(CSimpleBitmapButton, CButton)
BEGIN_MESSAGE_MAP(CSimpleBitmapButton, CButton)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_CREATE()
END_MESSAGE_MAP()
CSimpleBitmapButton :: CSimpleBitmapButton()
{
Pushed = FALSE;
Width = 0;
Height = 0;
}
void CSimpleBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct )
{
CDC memDC;
memDC.CreateCompatibleDC( NULL );
CBitmap *oldBitmap = memDC.SelectObject( &Bitmap );
if( Pushed == FALSE )
BitBlt( lpDrawItemStruct->hDC, 0, 0, Width, Height, memDC, 0, 0, SRCCOPY );
else
BitBlt( lpDrawItemStruct->hDC, 0, 0, Width, Height, memDC, Width , 0, SRCCOPY );
memDC.SelectObject( oldBitmap );
}
BOOL CSimpleBitmapButton :: Open( int resource_id )
{
Pushed = FALSE;
Bitmap.LoadBitmap( resource_id );
//adjust the button size
BITMAP bm;
Bitmap.GetObject(sizeof(BITMAP),&bm);
Width = bm.bmWidth / BUTTON_IMAGE_NUM;
Height = bm.bmHeight;
RECT rect;
GetWindowRect( &rect );
GetParent()->ScreenToClient( &rect );
rect.right = rect.left + Width;
rect.bottom = rect.top + Height;
MoveWindow( &rect );
return TRUE;
}
void CSimpleBitmapButton::OnLButtonDown(UINT nFlags, CPoint point)
{
Pushed = TRUE;
Invalidate( FALSE );
CButton::OnLButtonDown(nFlags, point);
}
void CSimpleBitmapButton::OnLButtonUp(UINT nFlags, CPoint point)
{
Pushed = FALSE;
Invalidate( FALSE );
CButton::OnLButtonUp(nFlags, point);
}
Import this bitmap to resource.
Then set IDB_ROUND_BUTTON for resource ID.
Add button on your dialog and set the "Owner Darw" proerty to True. Important!
Add member variables of the button as m_PlayButton.
At the dialog header, include SimpleBitmapButton.h and change the class of m_PlayButton from CButton to CSimpleBitmapButton.
CSimpleBitmapButton m_Button; // it was CButton m_Button;
At the last, set the bitmap on OnInitDialog()
m_PlayButton.Open( IDB_ROUND_BUTTON );

Processing rect statement leaving trail of other black rectangles

When trying to make a rectangle come back and forth from the Frame, it leaves behind a black rectangle covering the background.
Here is my code:
float x = 0;
float y = 0;
float speed = 1;
void setup() {
size(500,500);
background(255);
}
void draw() {
move();
display();
}
void move() {
x = x + speed;
if (x > width) {
x = 0;
}
}
void display() {
rect(x,y,30,10);
}
Now I hate that since it is almost the same exact code that is in the examples.
Edit: I don't want the black color that it leaves behind. Now do some research..
To avoid a trailing of your triangle, you need to redraw your background before redrawing your triangle, otherwise it just draws another triangle over the top.
You should add;
background(255);
to your draw() method before move() and display().
Hope this helps.
In Processing void setup() is only Called once when the sketch is started. This is why you define the size of the canvas in it. ( as the canvas side does not change)
On the other hand void draw() is constantly running. So any active content that changes when the program is running needs to be in it.
float x = 0;
float y = 0;
float speed = 1;
void setup() {
size(500,500);
}
void draw() {
background(255);
move();
display();
}
void move() {
x = x + speed;
if (x > width) {
x = 0;
}
}
void display() {
rect(x,y,30,10);
}

Resources