I'm trying to support multiple screen sizes in my app... I added this to my Manifest.xml:
`<supports-screens
android:normalScreens="true"
android:smallScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"/>`
I also added different layout sizes and densities:
layout-small
layout-large
layout-normal
layout-xlarge
drawable-ldpi
drawable-hdpi
drawable-mdpi
drawable-xhpi
My layout-normal is currently set on Nexus 4: Image here
Now it's set on Nexus One: Image here
How can I set the elements to scale automatically?
Is there any other way to scale the elements automatically without setting their height and width to wrap_content or match_parent?
of course you can do it programmatically
example:
I defined Simple Object ImageSize like this:
public class ImageSize {
private float width;
private float height;
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}
then I created a layout which contains Image(another layout) in it
final LinearLayout sellCarImage = (LinearLayout) findViewById(R.id.sellCarImage);
final RelativeLayout sellCarLayout = (RelativeLayout) findViewById(R.id.sellCarLayout);
then I've calculated width and height to scale view sizes based on image real size:
ImageSize img = new ImageSize();
img = getImageSize(R.drawable.indeximage5, MainActivity.this);
int sellCarWidth = sellCarLayout.getWidth();
int sellCarHeight = (int) ((sellCarWidth * img.getHeight()) / img.getWidth());
and programmatically set width and height:
RelativeLayout.LayoutParams sellCarImageIconParams = new RelativeLayout.LayoutParams(sellCarWidth, sellCarHeight);
//sellCarImageIconParams.setMargins(marg, 0, marg, 0);
sellCarImage.setLayoutParams(sellCarImageIconParams);
sellCarImage.setBackgroundResource(R.drawable.indeximage5);
here is getImageSize
public ImageSize getImageSize(int resource, Context ctx) {
ImageSize imageSize = new ImageSize();
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(ctx.getResources(), resource, dimensions);
imageSize.setHeight(dimensions.outHeight);
imageSize.setWidth(dimensions.outWidth);
return imageSize;
}
it's better to put them in:
sellCarLayout.post(new Runnable() {
#Override
public void run() {
//here
});
}
I hope it helps
Related
I have a multiple screen video player, and I just want to keep 16:9 ratio. There is a qgroupbox as a container of a qwidget which plays video in it. I also use qgroupbox to show selected frame by painting border to green. I can't do this on qwidget because rendered video overlaps that. When I have done with resize, I emit a signal with mouseup event to be able to informed about the resize operation completed. Then I calculate new bounds for qwidget to keep 16:9 ratio and apply this values for qwidget. Here is the image to show you how my app looks like:
And here is the code that I use to resize qwidgets:
void playBack::OnWindowResized()
{
float ratio = 16.0f / 9.0f;
float w = playBackplayer_contList.at(0)->size().width(); //qgroupbox's width
float h = playBackplayer_contList.at(0)->size().height();//qgroupbox's height
float currentRatio = w / h;
float newW = 0;
float newH = 0;
if (currentRatio > ratio)
{
newH = h;
newW = h*ratio;
}
else if (currentRatio < ratio)
{
newW = w;
newH = w / ratio;
}
qDebug() << "NEW WIDGET SIZE: " << (int)newW << " x " << (int)newH;
for (int i = 0; i < playBackplayer_widgtList.count(); i++)
{
playBackplayer_widgtList.at(i)->setMinimumSize(newW, newH);
//playBackplayer_widgtList.at(i)->resize(newW, newH);
}
}
This code works perfectly when I enlarge form, but When I want to shrink, It doesn't allow me to do that. Because I set a minimum value for qwidgets. If I don't use setMinimumSize, use resize(w,h) instead, than orientation problems occur. And here is a example for this issue:
This code below shows ctor and this is where I set the layout:
playBack::playBack()
{
playback_player_1_widget = new QWidget;
playback_player_2_widget = new QWidget;
playback_player_3_widget = new QWidget;
playback_player_4_widget = new QWidget;
playback_player_1_widget_cont = new QGroupBox;
playback_player_2_widget_cont = new QGroupBox;
playback_player_3_widget_cont = new QGroupBox;
playback_player_4_widget_cont = new QGroupBox;
playBackplayer_widgtList.append(playback_player_1_widget);
playBackplayer_widgtList.append(playback_player_2_widget);
playBackplayer_widgtList.append(playback_player_3_widget);
playBackplayer_widgtList.append(playback_player_4_widget);
playBackplayer_contList.append(playback_player_1_widget_cont);
playBackplayer_contList.append(playback_player_2_widget_cont);
playBackplayer_contList.append(playback_player_3_widget_cont);
playBackplayer_contList.append(playback_player_4_widget_cont);
int rowcnt = 0;
int colcnt = 0;
for (int i = 0; i < 4; i++)
{
playBackplayer_contList.at(i)->setStyleSheet(QString("border:1px solid #000;background-color:#000;"));
playBackplayer_widgtList.at(i)->setStyleSheet(QString("background-color:#f00;"));
QGridLayout* layout = new QGridLayout;
layout->setRowStretch(0, 1);
layout->setColumnStretch(0, 1);
layout->setRowStretch(2, 1);
layout->setColumnStretch(2, 1);
playBackplayer_widgtList.at(i)->setMinimumWidth(100);
playBackplayer_widgtList.at(i)->setMinimumHeight(100);
playBackplayer_widgtList.at(i)->setMaximumWidth(10000);
playBackplayer_widgtList.at(i)->setMaximumHeight(10000);
layout->addWidget(playBackplayer_widgtList.at(i),1,1);
layout->setMargin(0);
layout->setSpacing(0);
playBackplayer_contList.at(i)->setLayout(layout);
mainLayout->addWidget(playBackplayer_contList.at(i), colcnt, rowcnt);
rowcnt++;
if (rowcnt % 2 == 0)
{
rowcnt = 0;
colcnt++;
}
playBackplayer_widgtList.at(i)->setAcceptDrops(true);
}
}
I have tried various things, I have tried to set size 0 for qwidget before resize, (in mousedownevent) that didn't work, I have tried deleting layout for qgroupbox, after resize happens, create new layout and set it for groupbox, that didn't work, I have tried layout()->adjustSize(), update(), repaint(), all that stuff didn't work. What am I missing? I need helps from you. Any help would be appreciated. Thank you in advance.
Do away with the grid layout inside the container group boxes. Instead, align and resize the video widget with setGeometry
Here is a simple subclass of QGroupBox I made that keeps your desired ratio and always stays in the center:
class RatioGroupBox : public QGroupBox{
Q_OBJECT
public:
RatioGroupBox(QWidget *parent = nullptr) : QGroupBox (parent){
setFlat(true);
setStyleSheet("border:1px solid #000;background-color:#000;");
setMinimumSize(100, 100);
setMaximumSize(10000, 10000);
ratio = 16.0f/9.0f;
ratioWidget = new QWidget(this);
ratioWidget->setStyleSheet("background: #f00;");
ratioWidget->setAcceptDrops(true);
}
protected:
void resizeEvent(QResizeEvent *){//or you can use your own resize slot
float w = width();
float h = height();
float currentRatio = w/h;
float newW(0);
float newH(0);
if (currentRatio > ratio){
newH = h;
newW = h*ratio;
}
else if (currentRatio < ratio){
newW = w;
newH = w / ratio;
}
ratioWidget->setGeometry((w-newW)/2, (h-newH)/2, newW, newH);
}
private:
QWidget *ratioWidget;
float ratio;
};
Your entire ctor will become something like:
playBack::playBack()
{
for(int r=0; r<2; r++){
for(int c=0; c<2; c++){
RatioGroupBox* playback_player_cont = new RatioGroupBox;
mainLayout->addWidget(playback_player_cont, c, r);
playBackplayer_contList.append(playback_player_cont);
}
}
}
You can of course access your video widgets by exposing ratioWidget any way you like. Either by making it public or creating a getter function.
I have customized the column width CMFCPropertyListCtrl by overriding the same class.
Code:
class CMyPropertyGridCtrl : public CMFCPropertyGridCtrl
{
public:
void SetFirstColumnWidth(int width)
{
m_nLeftColumnWidth = width;
AdjustLayout();
}
};
And in OnSize() method of the class where pChannelListCtrl is declare as data member, I have called this method.
I want to fixed second column with size 50.
Code:
int iWidth = pChannelListCtrl.GetLeftColumnWidth();
pChannelListCtrl.SetFirstColumnWidth(iWidth + (iWidth - 50));
Here, its display as expected.(Second column with size 50).
Problem:
I want to keep the second column size fixed. But, here its resizable.
Can you please guide me, how to restrict the column resize.
Thanks,
Abdula
Override CMFCPropertyGridCtrl::SetLeftColumnWidth.
The header control for the grid is accessed with CMFCPropertyGridCtrl::GetHeaderCtrl()
Optionally, you can disable the header control to prevent resizing GetHeaderCtrl().EnableWindow(FALSE);
class CMyPropertyGridCtrl : public CMFCPropertyGridCtrl
{
public:
CMyPropertyGridCtrl()
{
m_nLeftColumnWidth = 50;
}
void make_fixed_header()
{
HDITEM hdItem = { 0 };
hdItem.mask = HDI_FORMAT;
GetHeaderCtrl().GetItem(0, &hdItem);
hdItem.fmt |= HDF_FIXEDWIDTH;
GetHeaderCtrl().SetItem(0, &hdItem);
}
void SetLeftColumnWidth(int cx)
{
m_nLeftColumnWidth = cx;
AdjustLayout();
}
void OnSize(UINT f, int cx, int cy)
{
EndEditItem();
if (cx > 50)
m_nLeftColumnWidth = cx - 50; //<- 2nd column will be 50 pixels
AdjustLayout();
}
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyPropertyGridCtrl, CMFCPropertyGridCtrl)
ON_WM_SIZE()
END_MESSAGE_MAP()
Use HDF_FIXEDWIDTH to fix the column for header control. From parent window call these functions after the control is created:
grid.SetLeftColumnWidth(50);
grid.make_fixed_header();
CMyPropertyGridCtrl::SetLeftColumnWidth will not detect when column is resized by the user. Override CMyPropertyGridCtrl::OnHeaderItemChanged in order to detect changes requested by user.
now i`m trying to make camera app which can recognize text. For this I use the information from guides by google. This site describes how to make a full-screen reader. But i need to set Mobile Vision text scanner active in small rectangle(like in picture).Screenshot of barcode reader app(i need the same solution for text). Please help me).
required result
I have implemented this feature by integrating "filter" in front of the detector which crops the image (in my case a line of text from the center of image). Look at the code below:
public class LineDetector extends Detector {
Detector mDelegate;
public LineDetector(Detector delegate) {
mDelegate = delegate;
}
#Override
public SparseArray detect(Frame frame) {
int width = frame.getMetadata().getWidth();
int height = frame.getMetadata().getHeight();
int mBoxHeight = height;
int mBoxWidth = Math.toIntExact(Math.round(mBoxHeight * ConstantsPool.CROP_BOX_ASPECT_RATIO));
int right = (width / 2) + (mBoxWidth / 2);
int left = (width / 2) - (mBoxWidth / 2);
int bottom = height;
int top = 0;
YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, width, height, null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(left, top, right, bottom), 100, byteArrayOutputStream);
byte[] jpegArray = byteArrayOutputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
Frame croppedFrame = new Frame.Builder()
.setBitmap(bitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
return mDelegate.detect(croppedFrame);
}
#Override
public boolean isOperational() {
return mDelegate.isOperational();
}
#Override
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
And then you can use it in a following way:
TextRecognizer textRecognizer = new TextRecognizer.Builder(this).build();
LineDetector lineDetector = new LineDetector(textRecognizer);
lineDetector.setProcessor(...);
...
Camera2Source camera2Source = new Camera2Source.Builder(getContext(), lineDetector).build();
If you have any questions, just ask
Tom
I have a game that involves lots of collisions and explosions.
Basically, enemy-projectiles are launched from the bottom-right corner of the screen towards the left side. The player can intercept them using his weapon.
I want whenever a "bullet" and a projectile collide, the code will draw pre-made particles at the impact position.
My problem is that in real-time, in collision, the particles are drawn nicely but they never stop. The particles continue to be drawn even after the collision.
Now, I use callback mechanism to inform the renderer a collision took place somewhere, and I pass him the coordinates of the collision(x,y)
Here is my renderer code. I cut some parts from the code, leaving only the relevant ones:
package com.david.gameworld;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.utils.Array;
import com.david.helpers.AssetsLoader;
import com.david.helpers.CollisionAndTouchCallbacks;
public class GameRenderer implements CollisionAndTouchCallbacks.DrawThings{
/* The GameRenderer class. Responsible for all the rendering work and graphics */
public static final float FLOOR_HEIGHT = 100.0f; // Public variable - The floor height
private static final float Pixels_To_Meters = 32.0f; // PTM Ration
public static float screenWidth; // Screen width
public static float screenHeight; // Screen height
public OrthographicCamera camera; // The orthographic camera
private GameWorld world; // The game world object, for rendering
private boolean drawTrajectory;
private boolean drawParticle;
private boolean isDrawnParticle;
private Box2DDebugRenderer debugRenderer; // Debug renderer, to see the positions and sizes of the bodies/fixtures
private SpriteBatch batch; // A sprite batch
private Array<Body> tempBodies; // An array that contains all the bodies of Box2D
private Array<Vector2> collisionPositions;
private float delta;
public GameRenderer(float screenWidth, float screenHeight, GameWorld world) {
this.world = world;
GameRenderer.screenHeight = screenHeight;
GameRenderer.screenWidth = screenWidth;
debugRenderer = new Box2DDebugRenderer();
batch = new SpriteBatch();
camera = new OrthographicCamera();
tempBodies = new Array<Body>();
collisionPositions = new Array<Vector2>();
drawTrajectory = false;
drawParticle = false;
isDrawnParticle = false;
}
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.delta = delta;
// Update the world
world.updateWorld();
batch.setProjectionMatrix(camera.combined);
// Get box2d World bodies
world.getBox2DWorld().getBodies(tempBodies);
// Draw the entire scene
batch.begin();
drawBodiesBox2D();
if(drawTrajectory)
drawTrajectory();
if(drawParticle) {
if(!isDrawnParticle) {
drawParticle();
isDrawnParticle = true;
} else {
if(AssetsLoader.explosion.isComplete()) {
drawParticle = false;
isDrawnParticle = false;
}
}
}
batch.end();
// Debug Renderer for box2d world
}
// If user is aiming, draw the trajectory of the acorn
public void drawTrajectory() {
Gdx.app.log("System Out Println!!!!!!!!!", "Draw projectile");
float t = 0.1f, x = world.getArrayAcorns().peek().getX(), y = world
.getArrayAcorns().peek().getY();
float width = AssetsLoader.orbit.getWidth() / 8 / Pixels_To_Meters;
float height = AssetsLoader.orbit.getHeight() / 8 / Pixels_To_Meters;
float timeSeparation = 0.08f;
for (int i = 0; i < 40; i++) {
x = world.getAcornEquation().getX(t);
y = world.getAcornEquation().getY(t);
batch.draw(AssetsLoader.orbit, x, y, width, height);
t += timeSeparation;
}
}
private void drawBodiesBox2D() {
for (Body body : tempBodies) {
if (body.getUserData() != null
&& body.getUserData() instanceof Sprite) {
Sprite sprite = (Sprite) body.getUserData();
if (!sprite.getTexture().equals(AssetsLoader.ground)) {
sprite.setPosition(body.getPosition().x - sprite.getWidth()
/ 2, body.getPosition().y - sprite.getHeight() / 2);
} else {
sprite.setSize(screenWidth, FLOOR_HEIGHT / Pixels_To_Meters);
}
sprite.setRotation((float) Math.toDegrees(body.getAngle()));
batch.draw(AssetsLoader.catapult_base1, 450 / Pixels_To_Meters,
(FLOOR_HEIGHT - 10) / Pixels_To_Meters,
AssetsLoader.catapult_base1.getWidth()
/ Pixels_To_Meters,
AssetsLoader.catapult_base1.getHeight()
/ Pixels_To_Meters);
sprite.draw(batch);
}
}
}
public void dispose() {
AssetsLoader.dispose();
batch.dispose();
world.dispose();
debugRenderer.dispose();
}
// Update method for the orthographic camera
public void updateCamera(int width, int height) {
camera.setToOrtho(false, width, height);
screenWidth = (float) width;
screenHeight = (float) height;
camera.update();
// Already Meters
}
public OrthographicCamera getCamera() {
return this.camera;
}
private void drawParticle() {
// TODO Auto-generated method stub
AssetsLoader.explosion.setPosition(collisionPositions.first().x,collisionPositions.first().y);
AssetsLoader.explosion.start();
AssetsLoader.explosion.draw(batch,delta);
AssetsLoader.explosion.allowCompletion();
}
#Override
public void signalToTrajectory(boolean flag) {
// TODO Auto-generated method stub
drawTrajectory = flag;
}
#Override
public void signalToParticle(boolean flag, Array<Vector2> positions) {
// TODO Auto-generated method stub
if(flag)
collisionPositions = positions;
drawParticle = flag;
}
}
How can I draw the particle effect once and that's it?
You can use/optimise my particle class, look my post here
To draw the particle effect once and that's it : ( it's in myparticle free method ) :
ParticleEffect effect = new ParticleEffect();
Emitter emitter = effect.getControllers().first().emitter;
if (emitter instanceof RegularEmitter){
RegularEmitter reg = (RegularEmitter) emitter;
reg.setEmissionMode(RegularEmitter.EmissionMode.EnabledUntilCycleEnd);
//reg.durationValue.setLow(10f);
reg.dispose();
}
emitter.dispose();
I'm attempting to create a software renderer for my tile based game and got stuck in the most important step : which is copying pixel chunks
to frame buffer.
First off , here's my class :
struct pixel_buffer
{
int width,height,bytesPerPixel;
unsigned char* pixels;
pixel_buffer()
{
pixels = NULL;
}
pixel_buffer(const char* imageName)
{
Image i = LoadImage(imageName);
width = i.width();
height = i.height();
bpp = i.bpp();
pixels = i.duplicate();
i.destroy();
}
pixel_buffer(int w,int h,int bpp)
{
width = w;
height = h;
bytesPerPixel = bpp;
pixels = new unsigned char[w*h*bpp];
}
~pixel_buffer()
{
delete pixels;
}
void attach(int x,int y,const pixel_buffer& other)
{
//How to copy the contents of "other" at x,y offset of pixel buffer ?
}
};
//This is the screen buffer and the contents get uploaded with glDrawArrays
pixel_buffer screen(640,480,4);
//This is a simple tile
pixel_buffer tile("files\\tiles\\brick.bmp");
//Attach tile to screen at offset 50,10
screen.attach(50,10,tile);
And this is the part that confuses me:
void attach(int x,int y,const pixel_buffer& other)
{
//How to copy the contents of "other" at x,y offset of pixel buffer ?
}
Im not sure how i am supposed to attach("copy") the pixel buffer of the tile to the screen buffer.
I tried this but didn't worked :
void attach(int x,int y,const pixel_buffer& other)
{
memcpy(&pixels[x + y * (this->width * this->bpp),other.pixels,other.width * other.height * other.bpp);
}
So i would like to ask for some help :-D