Evaluate bounds of a Path (created only with a String) - java

I would like to draw a String with Path and center it inside a Rectangle.
The problem is that I don't know how to evaluate the size/bounds of the path.
I have tried to use the corresponding size of the the same String drawn in a normal way (gc.drawString...) and after using gc.textExtent(String), but apparently the two size are different so the result is not ok....
Do you have any idea how to evaluate the size of the path in order to draw it centered in a rectangle?
The problem is that drawing a string with path is bigger that drawing a string in the normal way. You can verify it with this simple code.
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Path;
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 ShapeText
{
static Path path=null;
public static void main(String[] args)
{
final Display display = new Display();
Font font = new Font(display, "Times", 50, SWT.BOLD);
final Color blue = display.getSystemColor(SWT.COLOR_BLUE);
final Color red = display.getSystemColor(SWT.COLOR_RED);
try {
} catch (SWTException e) {
System.out.println(e.getMessage());
display.dispose();
return;
}
Shell shell = new Shell(display);
shell.addListener(SWT.Paint, new Listener()
{
public void handleEvent(Event e)
{
path = new Path(display);
e.gc.setFont(font);
path.addString("Path is different", 0, 0, font);
GC gc = e.gc;
gc.setAntialias(SWT.ON);
gc.setTextAntialias(SWT.ON);
gc.setForeground(blue);
gc.setBackground(blue);
//gc.fillPath(path);
gc.drawPath(path);
gc.setForeground(red);
gc.drawString("Path is different", 0, 0,true);
}
});
shell.setSize(530,120);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
path.dispose();
font.dispose();
display.dispose();
}
}
This is the result:
As you can see the String drawn with Path (in blue) is longer than the other (in red)...

Related

Putting an image in to a JFace table Cell is causing gap for image to appear in first column

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.

Problems in Using JLabel to Display a Chosen Image File

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.

Chroma key effect in Java

I also need to find a library which allows to implement the "chroma key" effect in Java. The video contains some part in green color, which is replaced which a picture during the rendering in order to create a new video.
I am linking my question with a similar question which was already answered but with uncomplete answer (Looking for Chromakey library in Java). Could you please specify how did you do to have something up and working so quickly? I have been unsuccessful for some months fighting against the same issue.
c00kiemon5ter pointed several resources:
JavaCV
JAI (Java Advanced Imaging API)
Java Image Processing Cookbook
Which one did work for you?
JavaCV contains lots of methods to process video streams.
This code should get you started: http://tech.groups.yahoo.com/group/OpenCV/message/59118 but it's probably too slow in Java. Try this approach:
Create a filter which turns all the green pixels into a mask (look for things that "select by color").
Use the mask to copy the background image into the video.
I would like to contribute with a piece of code which gave me quite good results. I wonder if I used the classes and methods that Aaron Digulla suggested.
Please note that in this case my video has black background, that is why I am replacing the black color with the background image. I expect to obtain better results when I can edit the video to have green background, because black color is more likely to be used within the video main characters and replacing wrong pixels causes a quite awful effect.
--
package transparentvideo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import java.io.File;
import javax.media.Manager;
import javax.media.Player;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TransparentVideo
{
Player mediaPlayer;
JFrame invisibleFrame;
JFrame visibleFrame;
JLabel videoScreen;
JPanel offScreenVideo;
String backgroundImageFile="nature.jpg";
String videoFile="girl.mov";
public TransparentVideo()
{
invisibleFrame = new JFrame();
invisibleFrame.setSize(400, 400);
Container container=invisibleFrame.getContentPane();
offScreenVideo = getvidComp();
offScreenVideo.setPreferredSize(container.getSize());
offScreenVideo.setVisible(true);
container.add(offScreenVideo);
invisibleFrame.setVisible(true);
visibleFrame=new JFrame();
visibleFrame.setSize(container.getSize());
visibleFrame.setLocationRelativeTo(null);
videoScreen = new JLabel();
visibleFrame.getContentPane().add(videoScreen);
visibleFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
visibleFrame.setVisible(true);
invisibleFrame.setVisible(false);
try
{
while(true)
{
if(mediaPlayer.getState()==Player.Started)
reDraw();
Thread.sleep(100);
}
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
public void reDraw()
{
BufferedImage bi=new BufferedImage(videoScreen.getWidth(), videoScreen.getHeight(),
BufferedImage.TYPE_INT_ARGB);
bi.getGraphics().drawImage(new ImageIcon(backgroundImageFile).getImage(), 0 , 0 ,
videoScreen.getWidth(), videoScreen.getHeight(), null);
BufferedImage screenShot = createImage((JComponent) offScreenVideo,
new Rectangle(invisibleFrame.getBounds()));
Image im = makeColorTransparent(new ImageIcon(screenShot).getImage(), Color.BLACK);
bi.getGraphics().drawImage(im, 0 ,0 , videoScreen.getWidth(), videoScreen.getHeight(), null);
videoScreen.setIcon(new ImageIcon(bi));
}
public static BufferedImage createImage(Component component, Rectangle region)
{
if (!component.isDisplayable()) {
Dimension d = component.getSize();
if (d.width == 0 || d.height == 0) {
d = component.getPreferredSize();
component.setSize(d);
}
layoutComponent(component);
}
BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
if (!component.isOpaque())
{
g2d.setColor(component.getBackground());
g2d.fillRect(region.x, region.y, region.width, region.height);
}
g2d.translate(-region.x, -region.y);
component.paint(g2d);
g2d.dispose();
return image;
}
public static void layoutComponent(Component component)
{
synchronized (component.getTreeLock())
{
component.doLayout();
if (component instanceof Container)
{
for (Component child : ((Container) component).getComponents())
{
layoutComponent(child);
}
}
}
}
public JPanel getvidComp()
{
Manager.setHint(Manager.LIGHTWEIGHT_RENDERER,true);
try
{
mediaPlayer = Manager.createRealizedPlayer(new File(videoFile).toURL());
mediaPlayer.realize();
mediaPlayer.prefetch();
JPanel video=new JPanel(new BorderLayout());
video.add(mediaPlayer.getVisualComponent()) ;
mediaPlayer.start();
return video;
}
catch( Exception d)
{
return null;
}
}
public static Image makeColorTransparent( Image im, final Color color)
{
ImageFilter filter = new RGBImageFilter()
{
public int markerRGB = color.getRGB() | 0xFF000000;
public final int filterRGB(int x, int y, int rgb)
{
Color c=new Color(rgb);
int red=c.getRed();
int green=c.getGreen();
int blue=c.getBlue();
//if(red<140 && green<140 && blue<140)
{
int alpha=Math.max(Math.max(red , green), Math.max(green, blue))*3;
c=new Color(red , green , blue , alpha>255 ?255 :alpha );
}
return c.getRGB();
}
};
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
public static void main(String[] args) {
new TransparentVideo();
}
}

delete drawings made with GC created on a SWT display

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...

Setting size of inner region of Java SWT shell window

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

Categories