In a Java SWT shell window, how do I set its inner size than its whole window frame size?
For instance, if I use shell.setSize(300, 250) this would make the whole window appearing as exactly 300x250. This 300x250 includes the size of the window frame.
How can I set the inner size, that is the content display region of the shell window to 300x250 instead? That's this 300x250 excludes the width of the window frame.
I tried to minus some offset values but the thing is different Operating Systems have different window frame sizes. So having a constant offset would not be accurate.
Thanks.
From your question what I understood is that you want to set the dimension of the Client Area. And in SWT lingo it is defined as a rectangle which describes the area of the receiver which is capable of displaying data (that is, not covered by the "trimmings").
You cannot directly set the dimension of Client Area because there is no API for it. Although you can achieve this by a little hack. In the below sample code I want my client area to be 300 by 250. To achieve this I have used the shell.addShellListener() event listener. When the shell is completely active (see the public void shellActivated(ShellEvent e)) then I calculate the different margins and again set the size of my shell. The calculation and resetting of the shell size gives me the desired shell size.
>>Code:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
public class MenuTest {
public static void main (String [] args)
{
Display display = new Display ();
final Shell shell = new Shell (display);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.numColumns = 1;
shell.setLayout(layout);
shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
final Menu bar = new Menu (shell, SWT.BAR);
shell.setMenuBar (bar);
shell.addShellListener(new ShellListener() {
public void shellIconified(ShellEvent e) {
}
public void shellDeiconified(ShellEvent e) {
}
public void shellDeactivated(ShellEvent e) {
}
public void shellClosed(ShellEvent e) {
System.out.println("Client Area: " + shell.getClientArea());
}
public void shellActivated(ShellEvent e) {
int frameX = shell.getSize().x - shell.getClientArea().width;
int frameY = shell.getSize().y - shell.getClientArea().height;
shell.setSize(300 + frameX, 250 + frameY);
}
});
shell.open ();
while (!shell.isDisposed()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
If I get you right you should set the size of the inner component to the needed size and use the method pack() (of the frame).
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class SWTClientAreaTest
{
Display display;
Shell shell;
final int DESIRED_CLIENT_AREA_WIDTH = 300;
final int DESIRED_CLIENT_AREA_HEIGHT = 200;
void render()
{
display = Display.getDefault();
shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);
Point shell_size = shell.getSize();
Rectangle client_area = shell.getClientArea();
shell.setSize
(
DESIRED_CLIENT_AREA_WIDTH + shell_size.x - client_area.width,
DESIRED_CLIENT_AREA_HEIGHT + shell_size.y - client_area.height
);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
public static void main(String[] args)
{
SWTClientAreaTest appl = new SWTClientAreaTest();
appl.render();
}
}
Use computeTrim to calculate the bounds that are necessary to display a given client area. The method returns a rectangle that describes the bounds that are needed to provide room for the client area specified in the arguments.
In this example the size of the shell is set so that it is capable to display a client area of 100 x 200 (width x height):
Rectangle bounds = shell.computeTrim(0, 0, 100, 200);
shell.setSize(bounds.width, bounds.height);
This article describes the terms used by SWT for widget dimensions:
https://www.eclipse.org/articles/Article-Understanding-Layouts/Understanding-Layouts.htm
Related
So I have a problem, when I add an image to any column of a JFace table the first column also behaves like it has an image in and the text is indented by the size of that image.
Here's a screenshot illustrating my point with the code needed to produce it. Is there anyway to stop this from happening because it's really getting on my wick?
Regards,
Glen x
package widgets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ComponentTest {
private static Image image;
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, true));
TableViewer viewer1 = getViewer(shell, true);
TableViewer viewer2 = getViewer(shell, false);
List<String> rows = new ArrayList<String>();
rows.add("Row 1");
rows.add("Row 2");
viewer1.setInput(rows);
viewer2.setInput(rows);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static TableViewer getViewer(final Shell shell, boolean addImage) {
TableViewer viewer = new TableViewer(shell, SWT.FULL_SELECTION
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.NONE);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.getTable().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Text Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setText((String) cell.getElement());
}
});
col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Second Text Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setText((String) cell.getElement());
}
});
if (addImage) {
col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Image Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setImage(getImage(shell.getDisplay()));
}
});
}
viewer.getTable().setHeaderVisible(true);
return viewer;
}
// make a little green square
private static Image getImage(Display display) {
if (image == null) {
PaletteData palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
ImageData imageData = new ImageData(16, 16, 24, palette);
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
imageData.setPixel(x, y, 0xFF00);
}
}
;
image = new Image(display, imageData);
}
return image;
}
}
That is a quite annoying bug when using Windows. You can use a dirty fix by skipping the first column (not using it) and setting its width to zero.
As far as I remember correctly, this will introduce some minor glitches when using MacOS.
I had the same problem and worked around it by using a StyledCellLabelProvider with owner draw and overriding the paint method to paint the image. The point is that you should not set the image of the viewer cell because this will give the bug. I posted example code to the Eclipse bug report.
TableItem line:301: I see a problem with SWT code here.
if (code == 0) return new RECT ();
if (!getImage) {
RECT iconRect = new RECT ();
iconRect.left = OS.LVIR_ICON;
parent.ignoreCustomDraw = true;
code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, iconRect);
parent.ignoreCustomDraw = false;
if (code != 0) rect.left = iconRect.right;
//****problem
code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, iconRect);
for the first table viewer with image, here code is 1 that why drawing text started iconRect right coordinate.
for the second table viwer with no image, code is zero. so it always starts from the actual bounds.
If you are really keen on fix it at CellStyleStyledCellLabelProvider i would suggest you to override paint method there.
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 am developing an app for which I need the screen DPI.. I checked a few forums and got a code snippet which goes as follows:
Dimension screen = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
System.out.println("screen width: "+screen.getWidth());
System.out.println("screen height: "+screen.getHeight());
int pixelPerInch=java.awt.Toolkit.getDefaultToolkit().getScreenResolution();
System.out.println("pixelPerInch: "+pixelPerInch);
double height=screen.getHeight()/pixelPerInch;
double width=screen.getWidth()/pixelPerInch;
double x=Math.pow(height,2);
double y=Math.pow(width,2);
But whatever be the value of my screen resolution, the pixelPerInch value remains the same at 96. What is the problem with the code??
I got another swt code for the same thing which goes as follows:
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class MainClass {
public void run() {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Display Device");
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private void createContents(Shell shell) {
Device device = shell.getDisplay();
System.out.println("getBounds(): "+ device.getBounds());
System.out.println("getClientArea(): "+device.getClientArea());
System.out.println("getDepth(): "+device.getDepth());
System.out.println("getDPI(): "+device.getDPI());
device.setWarnings(true);
System.out.println("Warnings supported: "+device.getWarnings());
}
public static void main(String[] args) {
new MainClass().run();
}
But again here also whatever be my screen resolution, the getDPI() returns the same value of 96.. What is going wrong?? Is my code wrong or am I interpreting it in a wrong way??
The problem is no one, not even the OS, knows the exact physical dimensions of the screen. You'd need to know that in order to calculate the PPI.
There's a display setting in the control panel where the user can manually specify the PPI and by default it's set to 96.
this code works for me on win10
import javafx.stage.Screen
double getScaleFactor() {
double trueHorizontalLines = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
double scaledHorizontalLines = Screen.getPrimary().getBounds().getHeight();
double dpiScaleFactor = trueHorizontalLines / scaledHorizontalLines;
return dpiScaleFactor;
}
it uses some awt apis though
I need to implement a class, using Swing, which can obtain the mouse coordinates when the user clicks anywhere on the screen. if I wanted to obtain the mouse coordinates inside my own window, I'd use a MouseListener, but I want it to work even when the user clicks outside my program.
I want my class to behave just like KColorChooser: the user clicks on the drop button and he can click anywhere on the screen to obtain the color of that spot. but I don't know if that's possible using pure Java.
It is possible though limited:
Add an AWTEventListener for focus events. As long as your app has focus before the button is clicked you'll receive a focus lost event. Then query for the pointer position.
The limitation is that, of course, your app loses focus. So depending on what you are ultimately trying to achieve this might not be useful.
If you don't want to lose focus then you will have to temporarily take a screenshot of the whole screen and display that in a screen filling window which listens for a mouse click as usual.
Proof of first method:
import java.awt.AWTEvent;
import java.awt.MouseInfo;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.JFrame;
public class Application1 {
public static void main(String[] args) {
Toolkit.getDefaultToolkit().addAWTEventListener(
new Listener(), AWTEvent.MOUSE_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static class Listener implements AWTEventListener {
public void eventDispatched(AWTEvent event) {
System.out.print(MouseInfo.getPointerInfo().getLocation() + " | ");
System.out.println(event);
}
}
}
Clicking outside of the app produced:
java.awt.Point[x=198,y=59] | java.awt.event.MouseEvent[MOUSE_EXITED, ...
java.awt.Point[x=976,y=503] | java.awt.FocusEvent[FOCUS_LOST, ...
The second point is outside of the app.
Forget about GlassPane, there's another 100% native Java way to do it that works both on OS X and on Windows.
Java has always supported translucency for its windows on OS X and Java now supports translucency for its windows on Windows too (since Java 1.6.0_10 or so, needs to be checked).
So the trick is: upon clicking on the "pick a color" tool, you create a nearly transparent borderless Java window covering the entire screen. You set its alpha to 10 (alpha goes from 0 to 255). That alpha is so low the user won't notice that there's a very thin "nearly transparent but only very very very translucent" borderless window covering the entire screen.
Now when the user clicks on your "alpha set to 10 translucent borderless window" covering the entire screen, you get your (x,y).
Discard the borderless Java window.
Use Robot's getRgb(x,y) and you're done.
Why set the alpha to 10 and not 0? Because otherwise clicks aren't intercepted by Java but go directly to the OS (at least that's how it works for a fact on OS X). There's a treshold and I know it's not set at '1', nor '2', it's around 10 or so.
EDIT I just realized you know need to pick several colors, this is trickier but can still be done using 100% Java. Either you can live with "slightly off" colors (affected by the "nearly transparent" 'invisible' layer) or upon getting a click you must remove the layer, get the correct pixel color, and put again a "nearly transparent" layer. Now of course that is one heck of a hack but it can be done in 100% Java.
Use
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
PointerInfo inf = MouseInfo.getPointerInfo();
Point p = inf.getLocation();
p.x and p.y will give you co-ordinates outside your window.
I don't know if that's possible using
pure Java.
Its not possible using pure Java, since Java is only aware of MouseEvents on Windows belonging to Java.
These events are directed to the window which has the focus, from all events on the desktop you can only get the mouse position.
As already shown by Keilly it's only possible to get the mouse postion.
You need to include a native lib
I haven't tried this myself, but maybe you could create a full-screen, transparent panel/frame/etc, and add a MouseListener to that.
It is possible with a little trick. Should be 100% cross-platform (tested on Linux & Windows). Basically, you create a small JWindow, make it "alwaysOnTop" and move it around with the mouse using a timer.
For details, see my answer here.
The location (x,y) and the time interval
(d) between each click is supplied thru command line arguments. Here is the
program
import java.awt.* ;
import java.util.* ;
public final class ClickMouse extends TimerTask {
public static int x, y, d ;
public static void main(String[] args) {
TimerTask clikMouse = new ClickMouse();
Timer t = new Timer();
/*
x = Integer.parseInt(args[0]) ;
y = Integer.parseInt(args[1]) ;
d = Integer.parseInt(ares[2]) ;
*/
x = 500;
y = 200;
d = 5;
t.schedule(clikMouse,1000,d*1000);
}
public void run() {
try
{
Robot bot = new Robot();
bot.mouseMove(x,y);
bot.mousePress(java.awt.event.InputEvent.BUTTON1_MASK );
bot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK);
}
catch (Exception e)
{
System.out.println("Exception occured :" + e.getMessage());
}
}
}
https://github.com/kwhat/jnativehook JNativeHook: Global keyboard and mouse listeners for Java.
I don't have enough rep yet to leave comments, but here are my comments on the other techniques:
Use a native lib: will work, but has obvious distribution limitations
Use GlassPane to fill entire screen: GlassPanes must be contained within a Window.
Create a Window containing a picture of the desktop and fill the entire screen: Will work, but it will suddenly make the desktop static. The cursor will no longer change, any animations or video in other windows or desktop will become eerily static.
Alternative solution:
A refinement of the screen filling window, if you are using Java 6u10 or later is to make the window completely transparent. Put this window in front of all others and listen for mouse clicks. It still has shortcomings, such as no cursor changes, but it depends on what you want to do.
Based on SyntaxT3rr0r's answer I created a sample color picker in groovy which shows how it can work.
import java.awt.*
import java.awt.datatransfer.*
//import com.sun.awt.AWTUtilities;
import javax.swing.WindowConstants as WC;
import javax.swing.SwingConstants as SWC
import groovy.swing.SwingBuilder
class ColorPicker {
SwingBuilder swb = new SwingBuilder()
def window;
def overlayWindow
def mainPanel;
def mainLabel;
def menu;
def transparent = new Color(0, 0, 0, 0);
def nearlyTransparent = new Color(0, 0, 0, 26);
Color color = new Color(150, 150, 255);
def colorHex = { col ->
col = col?: color;
"#"+Integer.toHexString(col.getRGB())[2..-1]
}
def getTextColor = { baseColor ->
baseColor = baseColor?: color;
(baseColor.red*1.5 + baseColor.green*1.5 + baseColor.blue > 400) ? Color.BLACK : Color.WHITE;
}
def setDisplayColor = {newColor ->
mainPanel.background = newColor
mainLabel.foreground = getTextColor(newColor)
mainLabel.text = colorHex(newColor)
}
def show(){
menu = swb.popupMenu { // invoker: mainPanel
menuItem(text: "Pick Color", actionPerformed: capturePixelColor)
menuItem(text: "Copy to Clipboard", actionPerformed: {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(colorHex()), null);
})
separator()
menuItem(text: "Close", actionPerformed: {dispose()})
}
window = swb.frame(
title: "Color Picker",
location:[50,50],
size:[60, 60],
resizable: false,
undecorated: true,
alwaysOnTop: true,
defaultCloseOperation:WC.EXIT_ON_CLOSE
){
def textColor = getTextColor()
mainPanel = panel( constraints: BorderLayout.CENTER,
border: lineBorder(color: Color.BLACK),
componentPopupMenu: menu){
borderLayout()
mainLabel = label(text: "--",
constraints: BorderLayout.CENTER,
horizontalAlignment: SWC.CENTER)
}
}
setDisplayColor(color);
window.show();
}
def capturePixelColor = {
def screenSize = Toolkit.getDefaultToolkit().screenSize
overlayWindow = swb.frame(
location:[0,0],
size: screenSize,
resizable: false,
undecorated: true,
alwaysOnTop: true,
defaultCloseOperation:WC.DISPOSE_ON_CLOSE,
show: true,
background: nearlyTransparent, // AWTUtilities.setWindowOpacity(overlayWindow, 0.1f);
cursor: Cursor.CROSSHAIR_CURSOR,
mouseClicked: {event ->
int x = event.getXOnScreen() // or maybe getX() is enough
int y = event.getYOnScreen()
overlayWindow.dispose()
overlayWindow = null
color = new Robot().getPixelColor(x, y)
setDisplayColor(color)
}
)
}
public static void main(String...args){
println "Welcome to ColorPicker"
def picker = new ColorPicker()
picker.show()
}
}
Look, I understand I am 7 years late...
This is a re-make of Keilly's answer, which allows to get when the mouse button is clicked, anywhere. The main problem is that fullscreen games are always unfocused, and it becomes annoying to handle.
Here is the code:
import java.awt.AWTEvent;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.JFrame;
public class Main {
public static JFrame frame = new JFrame();
public static void main(String[] args) {
Toolkit.getDefaultToolkit().addAWTEventListener(
new Listener(), AWTEvent.MOUSE_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setLocation(1, 1);
}
private static class Listener implements AWTEventListener {
public void eventDispatched(AWTEvent event) {
// We do not want the event to show twice,
// as it shows for focusing and unfocusing
if(event.getID() == 1004) {
Point p = MouseInfo.getPointerInfo().getLocation();
System.out.println("Mouse Clicked at " + p.x + ", " + p.y);
}
// The frame was just unfocused! To make
// sure we get the next mouse click, we
// need to focus it again!
frame.setVisible(true);
}
}
}
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();
}