i am showing simple code sample. I showed an gif image in a Jlabel. When run the programme, TASK manager shows that memory is increasing continuously. Why it happens?
Edited:
try this code please... on show glass button, glass panel is shown with gif image and a hide glass button in it and with that memory will be started increasing. On clicking hide glass button, glass panel will be hidden and memory increasing will b stopped.
#mKorbel : I had debugged it, the constructor will be called once, so no re-initializing of JFrame and also included : setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
public class circle extends JFrame {
public ImageIcon pic;
final JPanel glass;
public JButton glass_show;
public JButton hide_glass;
public circle() {
super("Hi shamansdsdsd");
setSize(500, 300);
// Image icon initialize once :
pic = new ImageIcon("images/loadinag.gif");
glass_show = new JButton("Show Glass panel");
this.add(glass_show);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
glass = (JPanel) this.getGlassPane();
hide_glass = new JButton("Hide Glass panel");
glass.add(hide_glass);
glass.add(new JLabel(pic));
glass.setOpaque(false);
}
public void initialize_listeners(){
glass_show.addActionListener(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent A) {
glass.setVisible(true);
}
});
hide_glass.addActionListener(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent A) {
glass.setVisible(false);
}
});
}
public static void main(String[] args) {
circle mFrame = new circle();
mFrame.initialize_listeners();
mFrame.setVisible(true);
}
}
There is a bug in Java with animated GIF images. There is no memory increase with other images.
Edit;
Below example runs without memory leak; but you need Eclipse SWT library from Eclipse's site
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
public class GIFExample {
static Display display;
static Shell shell;
static GC shellGC;
static Color shellBackground;
static ImageLoader loader;
static ImageData[] imageDataArray;
static Thread animateThread;
static Image image;
static final boolean useGIFBackground = false;
public static void main(String[] args) {
display = new Display();
shell = new Shell(display);
shell.setSize(300, 300);
shell.open();
shellGC = new GC(shell);
shellBackground = shell.getBackground();
FileDialog dialog = new FileDialog(shell);
dialog.setFilterExtensions(new String[] {"*.gif"});
String fileName = dialog.open();
if (fileName != null) {
loader = new ImageLoader();
try {
imageDataArray = loader.load(fileName);
if (imageDataArray.length > 1) {
animateThread = new Thread("Animation") {
#Override
public void run() {
/* Create an off-screen image to draw on, and fill it with the shell background. */
Image offScreenImage = new Image(display, loader.logicalScreenWidth, loader.logicalScreenHeight);
GC offScreenImageGC = new GC(offScreenImage);
offScreenImageGC.setBackground(shellBackground);
offScreenImageGC.fillRectangle(0, 0, loader.logicalScreenWidth, loader.logicalScreenHeight);
try {
/* Create the first image and draw it on the off-screen image. */
int imageDataIndex = 0;
ImageData imageData = imageDataArray[imageDataIndex];
if (image != null && !image.isDisposed()) image.dispose();
image = new Image(display, imageData);
offScreenImageGC.drawImage(
image,
0,
0,
imageData.width,
imageData.height,
imageData.x,
imageData.y,
imageData.width,
imageData.height);
/* Now loop through the images, creating and drawing each one
* on the off-screen image before drawing it on the shell. */
int repeatCount = loader.repeatCount;
while (loader.repeatCount == 0 || repeatCount > 0) {
switch (imageData.disposalMethod) {
case SWT.DM_FILL_BACKGROUND:
/* Fill with the background color before drawing. */
Color bgColor = null;
if (useGIFBackground && loader.backgroundPixel != -1) {
bgColor = new Color(display, imageData.palette.getRGB(loader.backgroundPixel));
}
offScreenImageGC.setBackground(bgColor != null ? bgColor : shellBackground);
offScreenImageGC.fillRectangle(imageData.x, imageData.y, imageData.width, imageData.height);
if (bgColor != null) bgColor.dispose();
break;
case SWT.DM_FILL_PREVIOUS:
/* Restore the previous image before drawing. */
offScreenImageGC.drawImage(
image,
0,
0,
imageData.width,
imageData.height,
imageData.x,
imageData.y,
imageData.width,
imageData.height);
break;
}
imageDataIndex = (imageDataIndex + 1) % imageDataArray.length;
imageData = imageDataArray[imageDataIndex];
image.dispose();
image = new Image(display, imageData);
offScreenImageGC.drawImage(
image,
0,
0,
imageData.width,
imageData.height,
imageData.x,
imageData.y,
imageData.width,
imageData.height);
/* Draw the off-screen image to the shell. */
shellGC.drawImage(offScreenImage, 0, 0);
/* Sleep for the specified delay time (adding commonly-used slow-down fudge factors). */
try {
int ms = imageData.delayTime * 10;
if (ms < 20) ms += 30;
if (ms < 30) ms += 10;
Thread.sleep(ms);
} catch (InterruptedException e) {
}
/* If we have just drawn the last image, decrement the repeat count and start again. */
if (imageDataIndex == imageDataArray.length - 1) repeatCount--;
}
} catch (SWTException ex) {
System.out.println("There was an error animating the GIF");
} finally {
if (offScreenImage != null && !offScreenImage.isDisposed()) offScreenImage.dispose();
if (offScreenImageGC != null && !offScreenImageGC.isDisposed()) offScreenImageGC.dispose();
if (image != null && !image.isDisposed()) image.dispose();
}
}
};
animateThread.setDaemon(true);
animateThread.start();
}
} catch (SWTException ex) {
System.out.println("There was an error loading the GIF");
}
}
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}
Code Source
there are two areas
1) you forgot to declare setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); then current JVM instance is still in (the Native OS) RAM, until PC restart or power-off
2) maybe you are create a new JFrame for every Images on the fly
Related
I am a bit confused about the use of JavaCV FFmpegFrameRecorder. I have several byte[] or short[] arrays (depending if my images are 8 or 16 bit) were I have the data related for several images. Now, my idea is to use JavaCPP to send each image to ffmpeg so it creates me a mute video from this collection at the framerate I wish. Up to now I have:
package ffmpeg;
import java.awt.EventQueue;
import java.io.File;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import javax.swing.JFrame;
public class rwa {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
rwa window = new rwa();
window.frame.setVisible(true);
Frame myframe = new Frame();
myframe .imageHeight = 100;
myframe .imageWidth = 200;
myframe .imageChannels = 1;
myframe .imageDepth = 8;
byte[] myimage = new byte[20000];
//all black
for (int j = 0; j<myimage.length; j++){
myimage[j]=-128;
}
File dest = new File("C:\\out.mp4");
FFmpegFrameRecorder record = new FFmpegFrameRecorder(dest, 0);
//FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(dest);
record.setFrameRate(0.04);
record.setVideoCodec(13);
record.setFormat("mp4");
record.setPixelFormat(0);
record.setImageHeight(100);
record.setImageWidth(200);
record.setVideoBitrate(1000000);
record.start();
for (int i=0; i<100; i++){
if (myimage.length*(1+i)<20000) {
//this is just for debugging it. I'm creating a different image each frame to see if it works. In practice, I will read in each step the propper image
for (int j = myimage.length*i; j<myimage.length*(i+1); j++){
myimage[j]=127;
}
}
Buffer[] buf = {ByteBuffer.wrap(myimage)};
myframe.image = buf;
record.recordImage(200, 100, 8, 1, 0, 0, ByteBuffer.wrap(myimage));
//record.record(myframe);
}
record.stop();
record.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public rwa() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
But I am getting errors like
A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000007fefe4511d3, pid=6432, tid=0x000000000000027c
what is wrong there? And how should I select the bitrate? My images, at maximum, will be 16bit 1 channel 2048*2048 pixels.
Thanks!
You should use Parallel.run() method in JavaCV, when you are using an event/thread.
I am trying to make a simple game with Java swing/awt.
I am have issue with lagging while printing and moving images on the screen.
Here is my code below:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
public class StarDef extends JFrame implements Runnable, KeyListener{
private BufferedImage back;
private boolean start = false, end = false;
public int w = 1500, h = 800, commandx = 200, commandy = 100, ground = 500, mineral = 100;
private int mineralx = 0, mineraly = commandy + 104;
private int dronecnt = 0;
private ArrayList<Drone> DrList = null;
private ArrayList<Enemy> EnList = null;
private ArrayList<Building> BuildList = null;
private ArrayList<Allies> AlyList= null;
public Image imagearr[] = new Image[10];
private boolean makedrone = false, NeedMinerals = false;
public int picnum = 1;
private int OrderBuild = 0;
public static void main(String[] args){
Thread t = new Thread(new StarDef());
t.start();
}
public StarDef(){
back = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
DrList = new ArrayList<>();
BuildList = new ArrayList<>();
EnList = new ArrayList<>();
AlyList = new ArrayList<>();
this.addKeyListener(this);
this.setSize(w,h);
this.setTitle("Starcraft");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
try {
imagearr[0] = ImageIO.read(new File("Char/Command.png"));
imagearr[1] = ImageIO.read(new File("Char/droneleft.png"));
imagearr[2] = ImageIO.read(new File("Char/droneright.png"));
imagearr[3] = ImageIO.read(new File("Char/Mineral.png"));
imagearr[4] = ImageIO.read(new File("Char/barracks.png"));
} catch (Exception e){
e.printStackTrace();
}
}
public void initGame(){
DrList.clear();
mineral = 100;
}
public void draw(){
Graphics gs = back.getGraphics();
gs.setColor(Color.white);
gs.fillRect(0,0,w,h);
gs.setColor(Color.DARK_GRAY);
gs.fillRect(0,ground,w,200);
if (!end) {
gs.drawImage(imagearr[0], commandx, commandy, null); // First Image-Command Center
gs.drawImage(imagearr[3], mineralx,mineraly,null); // Second Image-Mineral
for (int i = 0; i < DrList.size(); i++) { //Printing Drones
Drone m = DrList.get(i);
gs.drawImage(imagearr[m.state], m.x, m.y, null); //Drawing Drones
m.moveDr(); // Moving the Drone
}
for (int i = 0; i < BuildList.size(); i++){ //Printing Building
Building bd = BuildList.get(i);
if(bd.buildingtype == 'R'){
gs.drawImage(imagearr[4], bd.x, bd.y, null); // Drawing Building-Problem starts..?
}
}
gs.drawImage(imagearr[0], commandx, commandy, null);
}
gs.setColor(Color.black);
gs.drawString("mineral : " + mineral, 10,50);
gs.drawString("Drones : " + DrList.size(), 10, 70);
Graphics ge = this.getGraphics();
ge.drawImage(back, 0,0,w,h,this);
}
public void run(){
try{
int timer = 10;
while (true){
Thread.sleep(timer);
if(start){
if (makedrone) {
makedrone();
}
if (OrderBuild>0){
makeBuilding(OrderBuild);
}
}
draw();
}
} catch (Exception e){
e.printStackTrace();
}
}
public void makeBuilding(int buildingnumber){
int bdx, bdy;
char BuildingType;
if(buildingnumber == 1){
bdx = 500;
bdy = 100;
BuildingType = 'R';
Building barracks = new Building(this, bdx, bdy, BuildingType);
BuildList.add(barracks);
}
}
public void makedrone() {
if (mineral >= 50) {
int dronex = commandx;
int droney = commandy+129;
Drone dr = new Drone(this ,dronex, droney);
DrList.add(dr);
dronecnt++;
mineral -= 50;
makedrone = false;
} else if (mineral < 50) {
NeedMinerals = true;
makedrone = false;
}
}
public void keyPressed(KeyEvent ke){
switch (ke.getKeyCode()){
case KeyEvent.VK_ENTER:
start = true;
end = false;
break;
case KeyEvent.VK_D:
makedrone = true;
break;
case KeyEvent.VK_R:
OrderBuild = 1;
break;
}
}
public void keyReleased(KeyEvent ke){
switch ((ke.getKeyCode())){
}
}
public void keyTyped(KeyEvent ke) {
}
}
When you compile the code, the first few stationary images appear fine.
After moving images(Drones) appear nicely, but when you summon the next stationary image(Building), heavy lag starts to appear and the speed of the moving drones decrease visibly.
The building is about 300*150 pixels and the drones are 40*30 pixels.
What is the cause of this problem? Is this because of the code(the way of summoning the image), or the picture's size, or the computer(I am using a notebook(LG Gram 14in)).?
Start by not using Graphics ge = this.getGraphics();.
Because you're also using your own Thread, you're running the risk of thread race conditions which could result in dirty reads/ paints.
Start by understanding how Swing painting actually works and work within the API functionality.
Start by having a look at Performing Custom Painting, Painting in AWT and Swing and Concurrency in Swing
KeyListener is also a poor choice for monitor key input and you should be using the Key Bindings API - see How to use key bindings for more details.
Adding content to the ArrayList can cause the ArrayList to go through a growth cycle, which can consume time and force a longer GC cycle. Consider seeding the ArrayList with initial capacity, it will help reduce the interval between growth cycles.
Focus on separating the "update" logic from the "paint" logic, it can help you find performance issues
You could also have a look at
java what is heavier: Canvas or paintComponent()?
Swing animation running extremely slow
Rotating multiple images causing flickering. Java Graphics2D
Which demonstrate a verity of techniques for improving performance of rendering in Swing.
If these still are't getting your to the level you want, then you will want to explore using a BufferStrategy
Better draw in JPanel and use repaint() method to update your JPanel
I encountered a problem while I am trying to display an image after I clicked a button and chose image file within the "Choose File Dialog".
Initially, I was managed to display the chosen image in JLabel, but later I created a separate ActionListener, I think it started to go wrong since then. Whatever image I choose, the JLabel won't display it.
I debugged it, and sure that the file chooser does pass the image to ImageIcon, JLabel does get the value from ImageIcon, but it doesn't display the image even after revalidate() and repaint().
Here I attached my code for your kind reference!
(I trimmed the code for a clean look, so there might be some brackets left not useful)
package com.xxx.LoyalCardManager;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
public class LoyalCardManagerMain implements ActionListener{
private JFrame frame;
private DatabaseHandler db = new DatabaseHandler();
private JLabel labelPic;
private JButton buttonPic;
private File picFile = new File("");
private BufferedImage image;
/**
* Launch the application.
* #throws SQLException
* #throws ClassNotFoundException
*/
public static void main(String[] args) throws SQLException, ClassNotFoundException {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
LoyalCardManagerMain window = new LoyalCardManagerMain();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
/**
* Create the application.
*/
public LoyalCardManagerMain() {
// Database initialisation
initDatabase();
// Draw GUI
frame = new JFrame();
frame.setBounds(100, 100, 619, 487);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
buttonPic = new JButton("Click to Choose Pic");
buttonPic.setBounds(415, 252, 166, 29);
frame.getContentPane().add(buttonPic);
buttonPic.setEnabled(false);
buttonPic.setActionCommand("ChoosePic");
buttonPic.addActionListener(this);
labelPic = new JLabel();
labelPic.setBounds(415, 30, 167, 210);
frame.getContentPane().add(labelPic);
}
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("ChoosePic")) {
//TODO Label now cannot display images.
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(new FileFilter() {
public boolean accept (File f) {
String extension = Utils.getExtension(f);
if(extension != null) {
if (extension.equals(Utils.gif) ||
extension.equals(Utils.jpeg) ||
extension.equals(Utils.jpg) ||
extension.equals(Utils.png) ||
extension.equals(Utils.tif) ||
extension.equals(Utils.tiff)) {
return true;
}else{
return false;
}
}
return false;
}
public String getDescription() {
return "Image File (*.gif, *.jpeg, *.jpg, *.png, *.tif, *.tiff)";
}
});
int retVal = chooser.showOpenDialog(frame);
if (retVal == JFileChooser.APPROVE_OPTION) {
picFile = chooser.getSelectedFile();
try {
image = ImageIO.read(picFile);
} catch (IOException e) {
e.printStackTrace();
}
// Calculate the pic's ratio and do re-scale
double ratio = (double) labelPic.getWidth() / (double) labelPic.getHeight();
// Do image scale, scaledW is the new Width, and LabelPic.getHeight is the new Height.
int scaledW = (int) (image.getHeight() * ratio);
image = new BufferedImage(scaledW, labelPic.getHeight(), BufferedImage.SCALE_FAST);
ImageIcon icon = new ImageIcon(image);
labelPic.setVisible(true);
labelPic.setIcon(icon);
labelPic.revalidate();
labelPic.repaint();
}
}
}
}
I also referenced other similar questions:
image loading using a JFileChooser into a JFrame
Image won't display in JLabel
Updating an image contained in a JLabel - problems
External Site: JFIleChooser opening image to JLabel
As well as Java Tutorial Docs
How to Use Buttons, Check Boxes, and Radio Buttons
But I still can't figure it out why the JLabel not display the chosen image.
Thanks for your kind help mates!
Ok, I finally figured out what's wrong with the code:
If I intend to use BufferedImage to resize (sorry, in my question I mis-understanding the method scale with resize), I need to use drawImage method to "redraw" the image. Otherwise the image will not be shown.
I made modification here:
double ratio = (double) labelPic.getWidth() / (double) labelPic.getHeight();
// Do image scale, scaledW is the new Width, and LabelPic.getHeight is the new Height.
int scaledW = (int) (image.getHeight() * ratio);
image = new BufferedImage(scaledW, labelPic.getHeight(), BufferedImage.SCALE_FAST);// Edit here
ImageIcon icon = new ImageIcon(image);
labelPic.setVisible(true);
labelPic.setIcon(icon);
labelPic.revalidate();
labelPic.repaint();
From the "Edit Here" mark, I use the following code:
BufferedImage imageTemp = new BufferedImage(resizedW, resizedH, BufferedImage.TYPE_INT_RGB);
imageTemp.getGraphics().drawImage(image,0,0, scaledW, scaledH, null);
image = imageTemp;
And there's difference between first pass the value to imageTemp then pass to image and directly pass the value to image. If I pass the new BufferedImage directly to image, it will display a pure black colour instead of the image you choose.
Try using this to display the image:
JfileChooser getImage = new JFileChooser();
..........
ImageIcon imagePath= new ImageIcon(getImage.getPath());
JLabel imageLabel= new JLabel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(imagePath.getImage(), 0, 0, width, height, null);
}
};
imageLabel.setLocation(10, 40);
imageLabel.setBorder(viewAnimalPanelBorder);
imageLabel.setSize(200, newHeight);
panel.add(imageLabel);
Let me know if you require more assistance.
Also, try displaying the picture without using the JFileChooser, maybe hard code the path for a test.
I create a GC on the display, and then I do some drawing. My question is how do I un-draw?
The code looks like this:
final GC gc = new GC(display);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setLineWidth(5);
gc.drawRectangle(rectangle);
gc.dispose();
Context:
I need to let users select a window from other applications. The behavior I expect can be seen here: http://tools.tortoisesvn.net/SendMessage.html Instead, All my screen is filled with red rectangles.
It is OK for me even if it is a Windows-only solution.
EDIT: sorry, red garbage remains even after I close my application.
EDIT2: The working example:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.addListener(SWT.MouseMove, new Listener() {
#Override
public void handleEvent(Event event) {
final Point displayPoint = display.map(shell, null, event.x, event.y);
final POINT point = new POINT();
point.x = displayPoint.x;
point.y = displayPoint.y;
final int windowHandle = OS.WindowFromPoint(point);
if (windowHandle != 0 && windowHandle != shell.handle) {
RECT rect = new RECT();
if (OS.GetWindowRect(windowHandle, rect)) {
Rectangle rectangle = new Rectangle(rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top);
final GC gc = new GC(display);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setLineWidth(5);
gc.drawRectangle(rectangle);
gc.dispose();
}
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
To use it, start a mouse drag from the shell (not the title bar) and hover it over an application that uses real windows controls (not swing, QT, XUL). A good example of target application is Total Commander. You will see that the screen becomes full of red rectangles. Ideally I would like to have only one red rectangle visible.
I know I could make a new shell with regions that will simulate the red rectangle, but if the mouse jumps over that, I'm stuck.
I make some code. It's not perfect solution, cause after many tries I'm not able to make transparency everything except the "window" border, so I'm just making the whole shell (which covers the "window" area) partially transparent (and it makes nice effect though).
Here's the code
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.win32.OS;
import org.eclipse.swt.internal.win32.POINT;
import org.eclipse.swt.internal.win32.RECT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
public class ShellBorder {
private Display display = new Display();
private Shell shell = new Shell(display);
private RECT currRect = null;
private Shell paintShell = null;
public ShellBorder() {
shell.addListener(SWT.MouseUp, new Listener() {
#Override
public void handleEvent(Event event) {
paintShell.dispose();
// do whatever you need
// ...
currRect = null;
}
});
shell.addListener(SWT.MouseMove, new Listener() {
#Override
public void handleEvent(Event event) {
final Point displayPoint = display.map(shell, null, event.x, event.y);
final POINT point = new POINT();
point.x = displayPoint.x;
point.y = displayPoint.y;
if(currRect == null) {
getWindowAndDrawBorder(point);
} else {
// cursor is outside the current rectangle
if (point.x < currRect.left || point.x > currRect.right || point.y < currRect.top || point.y > currRect.bottom) {
currRect = null;
paintShell.dispose();
getWindowAndDrawBorder(point);
}
}
}
private void getWindowAndDrawBorder(POINT point) {
long windowHandle = OS.WindowFromPoint(point);
if (windowHandle != 0 && windowHandle != shell.handle) {
RECT rect = new RECT();
if (OS.GetWindowRect(windowHandle, rect)) {
currRect = rect;
paintShell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP);
paintShell.setLocation(currRect.left, currRect.top);
paintShell.setSize(currRect.right - currRect.left, currRect.bottom - currRect.top);
paintShell.setLayout(new FillLayout());
paintShell.setAlpha(50);
Canvas canvas = new Canvas(paintShell, SWT.NO_BACKGROUND);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
GC gc = e.gc;
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setLineWidth(5);
gc.drawRectangle(new Rectangle(0, 0, paintShell.getSize().x, paintShell.getSize().y));
}
});
paintShell.open();
}
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static void main(String[] args) {
new ShellBorder();
}
}
To do this, you must draw on a Shell that covers the complete display. When the Shell is disposed, the drawn rectangles are removed.
I don't know how to find the window under the cursor though...
In my first answer I assumed that you wanted to test for a window of other applications on the Desktop. As that is not the case, you should have a look at my answer to How to draw over child elements of a Composite in SWT? which automatically handles redraw of the relevant parts when a rectangle should be removed again...
I'm trying to update just a portion of a canvas in SWT, but I don't understand how to do it.
I read tht I have to use the setClipping, the documentation indeed says:
"Sets the area of the receiver which can be changed by drawing operations to the rectangular area specified by the argument. Specifying null for the rectangle reverts the receiver's clipping area to its original value."
So I have just tried but with no luck, here a simple example:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class SimpleCanvas {
boolean manualDraw=false;
public void run() {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Canvas Example");
createContents(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
/**
* Creates the main window's contents
*
* #param shell the main window
*/
private void createContents(Shell shell) {
shell.setLayout(new FillLayout());
// Create a canvas
Canvas canvas = new Canvas(shell, SWT.NONE);
// Create a button on the canvas
Button button = new Button(shell, SWT.PUSH);
button.setBounds(10, 10, 300, 40);
button.setText("TEST");
button.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
switch (e.type) {
case SWT.Selection:
manualDraw=true;
canvas.redraw();
break;
}
}
});
// Create a paint handler for the canvas
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
if (manualDraw){
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_GREEN));
e.gc.setClipping(90,90,60,60);
e.gc.drawRectangle(90,90,30,30);
return ;
}
Rectangle rect = ((Canvas) e.widget).getBounds();
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_RED));
e.gc.drawText("DRAW TEXT", 0, 0);
e.gc.dispose();
}
});
}
/**
* The application entry point
*
* #param args the command line arguments
*/
public static void main(String[] args) {
new SimpleCanvas().run();
}
}
Can you please help me to understand what I'm doing wrong?
Thank you in advance.
I found the problem. In order to update only a portion of the canvas I don't have to call :
canvas.redraw();
and drawing there a portion of the canvas, but instead get the GC from canvas and use the setClipping there, so invoke something like that:
public void redrawCanvas (Canvas canvas) {
GC gc = new GC(canvas);
gc.setClipping(90,90,60,60);
gc.drawRectangle(90,90,30,30);
gc.dispose();
}