I want to use an AccessibilityService to remove automatically all shortcuts on the home screen by holding them and draging them up to the remove area.
For now I can remove one shortcut, but I fail to find a way to chain this drag and drop process multiple time.
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
sendToTrashbin(110, 600); //pass the shortcut's coordinate
sendToTrashbin(265, 600); //nothing happens when adding this line
}}, 2000);
}
private void sendToTrashbin(int x, int y){
dragAndDrop(x, y, 380, 70); //380 and 70 are the trashbin's coordinates
}
private void dragAndDrop(int x1, int y1, int x2, int y2){
Path path = new Path();
path.moveTo(x1, y1);
GestureDescription.StrokeDescription sd = new GestureDescription.StrokeDescription(path, 0, 1, true); //Press and hold the shortcut
Path path2 = new Path();
path2.moveTo(x1, y1);
path2.lineTo(x2, y2);
GestureDescription.StrokeDescription sd2 = sd.continueStroke(path2, 500, 100, false); //Drag and drop the shortcut in the remove area
dispatchGesture(new GestureDescription.Builder().addStroke(sd).build(), new AccessibilityService.GestureResultCallback() {
#Override
public void onCompleted(GestureDescription gestureDescription) {
super.onCompleted(gestureDescription);
dispatchGesture(new GestureDescription.Builder().addStroke(sd2).build(), null, null);
}}, null);
}
When only adding sendToTrashbin(110, 600); the program removes the first shortcut icon successfully, but when I add sendToTrashbin(265, 600); nothing happens then.
I thought about adding mutiple continuing strokes as a callback at the end of dragAndDrop() but as I have to do it 10 times, this is going to result in a lot of nested callbacks.
How could I wait for the first gesture from the sendToTrashbin() call to end before starting the next one?
Related
I'm trying to draw a stage and a string with a specific font, but when I draw the stage, the string disappears, but the images do not. I suppose it's a simple thing, but I have no idea. I've already tried to change the order to render, but that doesn't seem to be the problem. Any help would be aprecciated.
#Override
public void create() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
batch = new SpriteBatch();
textatlas = new TextureAtlas("Agorafunfa.txt");
TextureAtlas.AtlasRegion a = textatlas.findRegion("spider");
spider = new Sprite(a);
img = new Texture("Captura.PNG");
yesa = new BitmapFont(Gdx.files.internal("yesa.fnt"));
font = "Escape Planet";
img3 = new Texture("saturno.png");
funciona = new BitmapFont(Gdx.files.internal("yesa.fnt"));
starte = "Começar";
opcoes = "Opções";
Skin skin = new Skin();
skin.addRegions(ta);
final TextButton.TextButtonStyle tbs = new TextButton.TextButtonStyle();
tbs.font = yesa;
tbs.checked = skin.getDrawable("comecaversao2");
tbs.up = skin.getDrawable("comeca");
b = new TextButton("Começar",tbs);
b.setHeight(250);
b.setWidth(300);
b.setPosition(-10, 50);
b.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
stage.addActor(b);
Gdx.input.setInputProcessor(stage);
}
public void render() {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img,0,0);
batch.draw(img3, 200,170, 250, 170);
yesa.setColor(Color.WHITE);
yesa.draw(batch,font,430,300);
stage.draw();//if I comment this line, the string appears
batch.end();
}
You're on right track, stage.draw() is causing the problem. You're calling it without closing the spritebatch before. If you look into stage's source code you'll see it has its own spritebatch. Call batch.end() before drawing the stage.
Rendering a batch inside another opened batch will result in all kind of weird behaviour that makes you think the fault lies in everything but the batch.
As these type of problems pop up frequently nowadays I checked out the stage docs, there is clear information that it uses its own batch, you can even set your own with the constructor stage(Viewport viewport, Batch batch). If you use that constructor you don't need to use the solution above. However the docs doesn't mention batches needs to be closed, not even in the batch docs. This is something that probably should be added so we can avoid the same issues popping up.
Possible duplicate of this and this.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I need to set up a standard smiley face GUI where you can wink, blink, smile, and frown with JButtons. I need to do this with three separate classes: a class that draws the smiley face, a class with all my buttons and actionListeners that control the smiley face, and a class with the applet.
I keep getting NPE's on my buttons in the button class. I can't figure out why. Please go easy on me, I'm new to Java.
Here's my controls class:
public class SmileyControls extends JPanel implements ActionListener {
Smiley smiley;
JPanel controlPanel, eyePanel;
JButton open, wink, shut; // make these an animation???? see loop chapter in text
public SmileyControls(Smiley smileControl) {
smiley = smileControl;
controlLayout();
}
public void controlLayout() {
eyePanel = new JPanel(new FlowLayout());
open = new JButton("Open");
wink = new JButton("Wink");
shut = new JButton("Shut");
open.addActionListener(this);
wink.addActionListener(this);
shut.addActionListener(this);
eyePanel.add(open);
eyePanel.add(wink);
eyePanel.add(shut);
add(eyePanel);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==open){
smiley.setEyeCondition(0); // this calls the method setEyeCondition() from the smiley class that I created. I'm getting my NPE's here
}
if(e.getSource()==wink){
smiley.setEyeCondition(1); // and here
}
if(e.getSource()==shut){
smiley.setEyeCondition(2); // and here
}
}
}
Here's my smiley class:
public class Smiley extends JPanel {
int locX, locY, height, width;
Color moleColor;
int eyeCondition;
Graphics2D g2d;
public Smiley(int x, int y, int w, int h) {
locX = x;
locY = y + 100; // needed to add 100 pixels to make room for hair
height = h;
width = w;
moleColor = new Color(84,60,37);
eyeCondition = 0;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d= (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
setHair();
setFace();
setEyes(); // these methods paint the face
setMole();
setMouth();
}
// CONTROL METHODS
public void setEyeCondition(int eye) {
// the int values here are taken from the smileyControls class
// I think they'd repaint my applet if it weren't for the NPE's
if(eye == 0) {
// draw eyes open
g2d.fillOval(locX+width/5, locY+height/5,width/5, height/5); // left eye
g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye
repaint();
} else if(eye == 1) {
// draw wink
g2d.fillRect(locX+width/5, locY+height/5,width/2, height/20); // left eye winking
g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye open
repaint();
} else if(eye == 2) {
// draw blink
g2d.fillRect(locX+width/5, locY+height/5,width/2, height/20); // left eye blinking
g2d.fillRect(locX+3*width/5, locY+height/5,width/2, height/20); // right eye blinking
repaint();
}
}
public void setEyes() { // this method paints the original eyes
g2d.setColor(Color.black);
g2d.fillOval(locX+width/5, locY+height/5,width/5, height/5); // left eye
g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye
}
}
And here's my applet:
public class SmileyApplet extends JApplet {
Smiley smiley1;
SmileyControls control1;
JPanel container, smileyAndControls1, smileyAndControls2, smileyAndControls3;
BorderLayout border;
public void init() {
border = new BorderLayout();
setLayout(border);
setUpContainer();
}
public void setUpContainer() {
container = new JPanel(new FlowLayout());
smileyAndControls1 = new JPanel(new FlowLayout());
setUpControl();
setUpSmiley();
smiley1.setPreferredSize(new Dimension(450, 600));
smileyAndControls1.add(control1);
smileyAndControls1.add(smiley1);
container.add(smileyAndControls1); // add more controls to master container here
add(container, BorderLayout.CENTER);
}
public void setUpSmiley() {
smiley1 = new Smiley(0, 0, 400, 400);
add(smiley1);
}
public void setUpControl() {
control1 = new SmileyControls(smiley1);
}
}
At first you call setUpControl(), in there you create your SmileyControls and pass smiley1 to it (which is null at that time).
After that you call setUpSmiley() which creates the instance of Smiley.
So you probably only have to call setUpSmiley() before you call setUpControl() and your problem should be solved.
Try changing the order of these lines, as you use your smiley1 variable before it gets its value:
setUpControl(); // This uses smiley1
setUpSmiley(); // This instantiates smiley1
EDIT
You should move the drawing to the paint*() methods, or methods called directly from them.
That is, your setEyeCondition() method should set a property on the smiley, and the drawing should go into your setEyes()method.
I am trying to take input from webcam and draw it in the canvas.
For this I wrote following block of code:
void addImageToCanvas(Image img){
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
}
If I pass only one Image in that function by hand, it works.
If I pass two Images then it only draws the last one.
But I am implementing thread and calling it continuously from the thread. The function is then comes to stand still on the line:
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
The part of code from where the method is invoked:
public void run() {
try {
FrameGrabber grabber = new VideoInputFrameGrabber(cameraId);
CvMemStorage storage = CvMemStorage.create();
grabber.start();
IplImage grabbedImage;
BufferedImage bufImg;
int counter = 0;
while (primaryCameraChosen != null) {
grabbedImage = grabber.grab();
bufImg = grabbedImage.getBufferedImage();
addImageToCanvas(SwingFXUtils.toFXImage(bufImg, null));
try{
Thread.sleep(10000);
} catch(InterruptedException e){}
}
grabber.stop();
grabber.release();
} catch (Exception ex) {
}
}
Could you please tell me what I am doing wrong here? What is the solution? Thanks.
So you have actually two problems
1) If I pass two Images then it only draws the last one.
You are drawing images to the same X, Y coordinates, with the same height and width. The result is (like in real life if your paint something on an existing painting) that only the last drawing is visible as it hides the first one. This is the expected working.
Update after comment from OP:
The problem with this line: gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight()); is, that at the first Image it tries to draw the Image using the actual height and width of the Canvas, but most probably at this moment the Canvas itself was not drawn, so the actual height and width are both zero, therefore the picture gets drawn with zero width and height.
Two possible solutions are:
1) Only start the Thread when the Stage that contains the Canvas is actually showing. This will ensure that the Canvas has the correct height and width even at the first picture.
2) Listen to the width and height change of the canvas and redraw the Image if needed. This will ensure, that whenever the canvas is resized, the Image is redrawn (it has the advantage that the picture fits to the screen all the time so this one is the suggested way)
The example contains both approaches.
2) But I am implementing thread and calling it continuously from the
thread. The function is then comes to stand still on the line
We shall see the full code what can be wrong, but until you update the post to include every part that is needed to detect the problem, here is an example which updates a canvas with an Image from a background thread every 3 seconds:
public class Main extends Application {
Canvas canvas;
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
canvas = new Canvas();
Pane pane = new Pane();
pane.getChildren().add(canvas);
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
root.setCenter(pane);
Thread thread = new Thread(new Runnable() {
private ObjectProperty<Image> imageToBeDrawn = new SimpleObjectProperty<Image>(new Image(getClass().getResource("a.jpg").toExternalForm()));
#Override
public void run() {
// Option 2: Listen to the width and height property change of the canvas and redraw the image
canvas.widthProperty().addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
canvas.heightProperty().addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
imageToBeDrawn.addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
while(true){
Random rand = new Random();
if(rand.nextBoolean())
imageToBeDrawn.set(new Image(getClass().getResource("a.jpg").toExternalForm()));
else
imageToBeDrawn.set(new Image(getClass().getResource("b.jpg").toExternalForm()));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.setDaemon(true);
thread.start();
primaryStage.setScene(scene);
// Option 2: start the Thread only when the stage is showing
// primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {
//
// #Override
// public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
// if(newValue)
// thread.start();
//
// }
// });
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
void addImageToCanvas(Image img){
Platform.runLater(new Runnable(){
#Override
public void run() {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
}});
}
public static void main(String[] args) {
launch(args);
}
}
I am trying to write a simple app that create a transparent overlay over the full screen and draw a line at my current mouse position. This line should then follow my mouse movements until mouse press when the app is to exit.
I currently have an issue with redraw in the app that will not work and I guess that I have missplaced and/or missunderstood how the redraw should be used.
How to redraw an application like this correctly and resource efficient?
Sample code:
public class TAGuideLine {
static Display display = new Display();
static Shell shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP);
public static void main(String[] args) {
shell.setBackground(display.getSystemColor(SWT.COLOR_RED));
shell.setMaximized(true);
shell.setFullScreen(true);
shell.setLayoutData(0);
shell.layout(true, true);
shell.setAlpha(50);
shell.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
System.exit(0);
}
});
shell.addListener(SWT.MouseMove, new Listener() {
public void handleEvent(Event e) {
drawMyLine(MouseInfo.getPointerInfo().getLocation().x,
MouseInfo.getPointerInfo().getLocation().y);
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
shell.redraw();
shell.layout();
display.dispose();
}
public static void drawMyLine(int x, int y) {
final GC gc = new GC(shell);
gc.setForeground(display.getSystemColor(SWT.COLOR_GREEN));
gc.setLineWidth(8);
gc.drawLine(x - 250, y - 250, x + 250, y + 250);
gc.dispose();
shell.open();
}
}
To draw on a Shell you usually add a paint listener that does the actual drawing. The mouse event listener would just store the coordinates to draw and then trigger a redraw on the shell.
Below is a sketch of what the code could look like:
List<Point> points = new ArrayList<>();
shell.addListener( SWT.Paint, new Listener() {
public void handleEvent( Event event ) {
event.gc.setForeground( display.getSystemColor( SWT.COLOR_GREEN ) );
event.gc.setLineWidth( 8 );
for( Point point : points ) {
event.gc.drawLine( point.x - 250, point.y - 250, point.x + 250, point.y + 250 );
}
} );
shell.addListener( SWT.MouseMove, new Listener() {
public void handleEvent( Event event ) {
points.add( MouseInfo.getPointerInfo().getLocation() );
shell.redraw();
}
} );
Class GC also has a drawPolyLine() method that might be more suitable for this use case.
Unrelated to your question but still: a more graceful way to exit the application is to dispose of the Shell with shell.dispose()instead of calling System.exit().
I use libgdx's scene2d built-in UI library to make an UI in my game. I'm interesting how can I draw 2 images(or actors) in a table one on another? I'm looking to the similar like LayerDrawable in Android. Is there any exists stuff to make it?
There is a Stack widget in libGDX UI library for these purposes.
UPDATE: if you want to place one widget on top of another widget and these widgets have different size then you should wrap the smaller widget. Something like:
//First add actual content
stack.add(content);
//Second add wrapped overlay object
Table overlay = new Table();
overlay.add(overlayWidget).expand().fillX().bottom().left();
stack.add(overlay);
stack variable is a Stack instance
It's an actual excerpt from my project. You should tune it for your case.
You can use somethings like this :
//create stage
stage = new Stage(new StretchViewport(game.width, game.height));
//create table
Table table = new Table();
table.setSize(game.width,game.height); //fullscreen
//add Image 1
table.add(new Image(game.skin.getDrawable("image1")));
//add Image 2 (create new col)
table.add(new Image(game.skin.getDrawable("image2"))).width(xx).height(xx);
//add new row
table.row();
//add Image 3 - padding to draw over image1/2 && colspan
table.add(new Image(game.skin.getDrawable("image3"))).width(xx).height(xx).padTop(-50f).colspan(2);
//add table to stage
stage.addActor(table);
/*
* Add action
*
*/
#Override
public void render(float delta) {
...
//don't forget to draw ur stage
stage.act(delta); // or stage.act(Gdx.graphics.getDeltaTime())
stage.draw();
}
Also you can add action to stage/table or image etc ... :
stage.addAction(Actions.sequence(
Actions.fadeOut(0.0001f),
Actions.fadeIn(0.5f),
Actions.delay(0.1f),
Actions.run(new Runnable() {
#Override
public void run() {
//mmmm new screen
dispose();
game.setScreen(new BoobsScreen(game));
}
})));
Of course you can draw more than image : button, textbutton, label etc or add scrollPane for Table but before take a look at Skin on libgdx
For exemple a programmatically ninepatch textbutton :
private NinePatch processNinePatchFile(String fname) {
final Texture t = new Texture(Gdx.files.internal(fname));
final int width = t.getWidth() - 2;
final int height = t.getHeight() - 2;
return new NinePatch(new TextureRegion(t, 1, 1, width, height), 3, 3, 3, 3);
}
//create skin
skin = new Skin();
...
//create font
...
//create ninepatch button from android/assets/style/button
NinePatch ninepatch = processNinePatchFile("style/button.9.png");
skin.add("button.9", ninepatch);
//create textbuttonstyle
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.font = skin.getFont("font_black_38");
textButtonStyle.fontColor = Color.DARK_GRAY;
textButtonStyle.up = skin.getDrawable("button.9");
skin.add("buttonTextStyle", textButtonStyle);
//now you can create textbutton
TextButton btn = new TextButton("Hello", game.skin.get("buttonTextStyle", TextButton.TextButtonStyle.class));
//add a clicklistener
btn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
//mmmmmm add action for exemple
stage.addAction(Actions.sequence(Actions.fadeOut(0.5f), Actions.run(new Runnable() {
#Override
public void run() {
//dispose and load screen
dispose();
game.setScreen(new MoreBoobsScreen(game));
}
})));
}
});
table.add(btn);
To create bitmapfont take a look at Gdx freetype, it's really easy to use.