I'm creating simple app i have Tree object where i store filenames when user choose one SWTImageCanvas.loadImage(path) is being called. Every image has some points defined so points are displayed as gc.fillOval. When user move mouse over oval it name is being displayed i achive this by setting some additional variable and using SWTImageCanvas.redraw() method. Such redrawing cause blinking of canvas so i thought about double buffering i have read some tutorials about it but when i'm trying to run it my image is hovered by white layer with ovalls on it here is my drawing function
private void drawStations(Event e) {
Rectangle clientRect = mainSWTImageCanvas.getClientArea();
if(mainSWTImageCanvas.getSourceImage()!=null)
{
if(mainSWTImageCanvas.getScreenImage()!=null)
mainSWTImageCanvas.getScreenImage().dispose();
Image screenImage = new Image(mainSWTImageCanvas.getDisplay(),clientRect.width,clientRect.height);
this.gc = new GC(screenImage);
//drawing ovals on gc
.
.
.
this.gc.drawImage(screenImage, 0, 0);
this.gc.dispose();
e.gc.drawImage(screenImage, 0, 0);
}
It turns out that double buffering in swt display can by done by passing SWT.DOUBLE_BUFFERED in constructor.
Related
I want to take the screenshot of a java native application ( any framework AWT, Swing, JavaFx ) without bringing it to the foreground. Are there any framework-specific methods available for this?
I have tried using Robot class to get the screenshot
private static void capture(int x, int y , int width , int height, String setName) {
Robot robot = new Robot();
Rectangle area = new Rectangle(x, y, width, height);
BufferedImage image = robot.createScreenCapture(area);
ImageIO.write(image, "png", new File(System.getProperty("user.dir") + "\\images\\" + setName +".png"));
}
Now robot class with just take the area coordinates and capture the image, whether the target application is on the top or not, to get the application on the top I am using JNA to bring it to focus
private static void bringToFocus() {
for (DesktopWindow desktopWindow : WindowUtils.getAllWindows(true)) {
if (desktopWindow.getTitle().contains("notepad")) {
HWND hwnd = User32.INSTANCE.FindWindow(null, desktopWindow.getTitle());
User32.INSTANCE.SetForegroundWindow(hwnd);
break;
}
}
}
But this is an example where we need to capture only one application, if we need to capture 10 applications screenshots we need to one by one bring them to the front and capture and bring next.
Is there any framework specific method availabe which can take the application screenshot without bringing it to the front.
If your screen shot only needs to be of the Java GUI, you can paint to a BufferedImage
public static Image screenShot(Component c) {
BufferedImage im = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = im.getGraphics();
c.paint(g); // Paint is the proper entry point to painting a (J)Component, rather than paintComponent
g.dispose(); // You should dispose of your graphics object after you've finished
return im;
}
If your requirement is to paint the Java GUI component along with the rest of the screen, but like your java (J)Frame is in front, you can do that by painting the screen using the robot first, then doing what I've posted above, but with the BufferedImage (which has already been drawn on) being passed in as a parameter rather than being created in the method.
Disclaimer: I am using Java and Javafx 11. Just putting it out there :)
I am in the process of trying to create an Interpreter for Logo, but have run into a roadblock. You see, I defaulted to using a canvas to display all the things I needed as that is fitting for what I am doing. However, I did not account for the fact that my Turtle needed to move.
private void drawTurtle()
{
vertices[0] = new Vector2(position.x, position.y + 15); // The three points that make the triangle that is the turtle
vertices[1] = new Vector2(position.x - 15, position.y);
vertices[2] = new Vector2(position.x + 15, position.y);
vertices[1] = Renderer.rotatePoint(vertices[1], position, rotation); // applying rotation to vertices
vertices[2] = Renderer.rotatePoint(vertices[2], position, rotation);
vertices[0] = Renderer.rotatePoint(vertices[0], position, rotation);
Renderer.drawLine(vertices[2], vertices[1], currentPen); // drawing the vertices
Renderer.drawLine(vertices[2], vertices[0], currentPen);
Renderer.drawLine(vertices[1], vertices[0], currentPen);
}
Trails left due to rotating the turtle in realtime.
In order to achieve this without leaving "trails", I tried to erase the existing turtle by drawing with a white pen over it. That gave me... weird results.
This is after rotating the turtle 360 degrees.
Then I came across a post here on SO talking about how I should use a Line object on a Pane if I wanted to move stuff. And well, I tried combining it with a canvas to make a CanvasPane:
public class CanvasPane extends Pane
{
public final Canvas canvas;
public CanvasPane(double width, double height)
{
setWidth(width);
setHeight(height);
canvas = new Canvas(width, height);
getChildren().add(canvas);
canvas.widthProperty().bind(this.widthProperty()); // Change this so this canvas does not scale with the pane, and its size is constant.
canvas.heightProperty().bind(this.heightProperty());
}
}
And added line objects to this so I can then edit their start and end values to make the turtle move, but I got nothing out of it, no line to show, and I am quite confused and don't know what to do. Nothing on the great internet helped my either, so I am now asking this question to see if anyone has ideas on how I can move my turtle flawlessly. And no, I can't use clearRect()
TLDR: My turtle leaves trails when moving on a canvas, and using Line and Pane doesn't work, and I can't use clearRect() on my canvas. Help!
Use one Pane to hold both the Canvas Node and your "turtle" Node.
Canvas canvas = new Canvas(640, 480);
Shape turtle = new Polygon(); // fill in the points
Pane p = new Pane(canvas, turtle);
Now you can control the position of the turtle node by either setting the layout coordinates or applying a translation. As it was added last, it will be drawn over the Canvas. (You could also use a StackPane to make that layering more explicit.)
I just can't figure this, and I am pulling my hair out right now!!
I have a Stage with a Label added to it, I set everything up and the first time I call Stage.draw() everything works fine. However, as soon as I set the text of the Label nothing gets drawn. Funny thing is, when I don't change the text it draws perfectly as expected, but when I call label.setText("THE TEXT") it just doesn't draw.
I have stepped through my code and I have noted down the height, width, x and y values before and after setting text of the Label, and they are all the same (before and after).
Also, when I draw the Stage it's drawn above a Sprite, and positioning the Sprite is based on the Label's position.
The Sprite draws fine before I set text on the Label and after.
PS: I have also made sure that the Sprite is not drawn "over" the Label.
This is my setup:
I have a MainGame class that renders a Player class, when ever the back button is pressed the Sprite with the Stage gets drawn, or should get drawn.
spriteBatch.begin();
player.update(spriteBatch, delta);
spriteBatch.end();
// the pause menu is drawn with a separate sprite batch as it needs to be in middle relative to the screen and above everything else
if (player.isPaused()){
messageSpriteBatch.begin();
messageSprite.draw(messageSpriteBatch);
messageSpriteBatch.end();
messageStage.draw(); // the stage doesn't seem to be getting drawn
}
Player class - update method
if (!paused){
// removed for clarity
}else{
// on MainGame class we render a small box with one of the following messages
// READY
// PAUSE
// QUIT?
// GAME OVER
if (Gdx.input.justTouched()){
paused = false;
}
spriteBatch.setProjectionMatrix(camera.combined);
camera.update();
}
messageSpriteBatch = new SpriteBatch();
messageStage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
messageFont = new BitmapFont(Gdx.files.internal("fonts/fontfile.fnt"));
messageStyle = new LabelStyle();
messageStyle.font = messageFont;
messageLabel = new Label("READY", messageStyle);
This is how I initialise my Label, Sprite and Stage:
float fontScaleX = Gdx.graphics.getWidth()/SCALE_X_DIVIDER;
float fontScaleY = Gdx.graphics.getHeight()/SCALE_Y_DIVIDER;
messageLabel.setFontScale(fontScaleX*1.4f, fontScaleY*4.2f);
messageLabel.setPosition((messageStage.getWidth()/2)-((messageLabel.getWidth()/2)*messageLabel.getFontScaleX()), (messageStage.getHeight()/2)-((messageLabel.getHeight()/2)*messageLabel.getFontScaleY())+(player.getScoreboard().getSize().y/2));
messageStage.addActor(messageLabel);
messageStage.act();
messageTexture = new Texture(Gdx.files.internal("images/message_background.png"));
messageSprite = new Sprite(messageTexture);
messageSprite.setSize((messageLabel.getWidth()*messageLabel.getFontScaleX())*1.5f, (messageLabel.getHeight()*messageLabel.getFontScaleY())*3);
messageSprite.setPosition(messageLabel.getX()-(messageSprite.getWidth()/6), messageLabel.getY()-messageSprite.getHeight()/2);
Please help me, before I get bald xD
Well the width and height of the label is usually set once when creating the Label, matching the width and height of the initial text passed to the Constructor. You of course can make it bigger by setting the width and height later on. Then you could also use alignments by the way...
Are you using any special characters when changing the text, so the font has a problem with that?
Maybe posting some code could give more insights...
Haha, well, I found out what was up, it was my font file, you see when I was editing it, I used the text READY, so when I saved it, I didn't know that the text written is what is saved, so when I looked at the font.png file, I found that it only contained the letters ADERY.
Thanks for the help anyway =]
I have a canvas and a simple bitmap for background image, fills the whole screen. I created a rect painted black and set it's alpha to 250 in order to make a "dark" effect on the background image. My aim to make a simple circle object that reveals the place it's hovering above. I tried thinking in many ways how to excecute it and failed.
I think the best way is to create a simple circle that manages to decrease the darkness alpha on the position it hovers above, but I have no idea how to do it.
The relevant part of my code:
private ColorFilter filter = new LightingColorFilter(Color.BLACK, 1);
private Paint darkPaint = new Paint(Color.BLACK), paint = new Paint(), paint2 = new Paint();//The style of the text and dark.
public DarkRoomView(Context context) {
super(context);
myChild = this;
darkPaint.setColorFilter(filter);
darkPaint.setAlpha(250);
paint2.setAlpha(10);
paint.setAlpha(50);
}
private void loadGFX() {//Loads all of this view GFX file.
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.darkroomscreen);
lightImage = BitmapFactory.decodeResource(getResources(), R.drawable.light);
}
private void drawGFX(Canvas canvas) {
canvas.drawBitmap(backgroundImage, 0, 0, paint2);//The backgeound image.
canvas.drawRect(0, 0, WIDTH, HEIGHT, darkPaint);//The darkness.
canvas.drawBitmap(lightImage, 50, 50, paint);//A spotlight.
}
Any ideas how I should get it done?
Thanks!
For the spotlight, you could draw a circle of the original image over the darkness. You'd simply need to find the correct rectangle of the original image (based on where your finger is), and then draw a circle of that particular rectangle over the darkness. Trying to look "through" the darkness won't really get you anywhere; you need to place something over it.
By the time you draw the "spotlight", you've already darkened the image with the rectangle. It would be difficult to recover information lost during that draw.
A more flexible approach would be to draw a dark rectangle with a spotlight in a separate image (that is, compose the "darkness" and spotlight alpha and color mask image first), and then draw that mask image on top of the background as a separate step. This would also let you easily do things like e.g. give the spotlight fuzzy borders.
is there a way to arrange drawable drawen on canvas, before redrawing it? I mean setting which drawable will be drawn in the front, and which drawable will be drawn in the back.
They're drawn in the order you draw them. Just try drawing the one which sits in the back first, the front one last.
A way to do it is to have everything you draw define a z-index variable and collect everything you draw at a single point and put them in a list that you then order by the z-index before drawing it.
ex:
Interface IDrawable{
int getZ();
void draw();
}
class drawMe implements IDrawable{
#overrider
draw(){
/// do my drawing
}
#override
int getZ() {return z; }
}
in your drawing or main class
List<IDrawable> myList= new ArrayList();
myList.Add(new DrawMe());
and in your draw method
for(IDrawable draw : myList.OrderBy(z){
draw.draw();
}
thats the concept anyway
You can draw to a temporary canvas for drawing to the main canvas later.
Picture iconFrame = new Picture();
Canvas tempCanvas = iconFrame.beginRecording(width, height);
// width and height refer to the intended destination canvas size
...
// Any configuration before performing the draw should be done here
tempCanvas.drawPath(...);
tempCanvas.drawBitmap(...);
// Any required draw commands for this image should be done to tempCanvas
iconFrame.endRecording();
...
// Any other configuration or draw commands can be done here
iconFrame.draw(canvas);
// Assigns the content of tempCanvas to the top of the main Canvas
In my case, the PorterDuff manipulation of my image within a custom path only worked if it was done first because later draws corrupted it.