Get Cursor Control for Disabled Control - java

I want to get the control the mouse hovers over which normally is done by Display#getCursorControl. However when one control in the hierarchy is disabled, this method doesn't work any longer:
Example:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(400, 300);
shell.setLayout(new GridLayout(2, false));
final Label mouseControl = new Label(shell, SWT.BORDER);
mouseControl.setLayoutData(GridDataFactory.fillDefaults().span(2, 1).grab(true, true).create());
display.addFilter(SWT.MouseMove,
e -> mouseControl.setText("" + e.display.getCursorControl()));
final Group enabledGroup = new Group(shell, SWT.NONE);
enabledGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
enabledGroup.setText("Enabled Group");
createControls(enabledGroup);
final Group disabledGroup = new Group(shell, SWT.NONE);
disabledGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
disabledGroup.setText("Disabled Group");
disabledGroup.setEnabled(false);
createControls(disabledGroup);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void createControls(Composite parent) {
parent.setLayout(new GridLayout());
final Label label = new Label(parent, SWT.NONE);
label.setText("Label");
final Text text = new Text(parent, SWT.BORDER);
text.setText("Text");
}
Hold the mouse over the left label and then over the right one. The control is only displayed for an enabled parent, else the shell is displayed.
How do I get the control below the mouse pointer? Do I have to implement this functionality myself? Are there any methods that can help me or do I have to calculate the bounds of each control inside the tree and check if it is on the mouse position?

I can't see anything in Display that would help.
The following will search the children of a Shell for a control containing the cursor and works with disabled controls:
static Control findCursorinShellChildren(final Shell shell)
{
return findLocationInCompositeChildren(shell, shell.getDisplay().getCursorLocation());
}
static Control findLocationInCompositeChildren(final Composite composite, final Point displayLoc)
{
final var compositeRelativeLoc = composite.toControl(displayLoc);
for (final var child : composite.getChildren())
{
if (child.getBounds().contains(compositeRelativeLoc))
{
if (child instanceof Composite)
{
final var containedControl = findLocationInCompositeChildren((Composite)child, displayLoc);
return containedControl != null ? containedControl : child;
}
return child;
}
}
return null;
}
I imagine this is going to be significantly slower than Display.getCursorControl

Related

How to create a SWT text field with inactive text as a suffix?

I am using Java's SWT toolkit to create a GUI with text field inputs. These input fields require numerical input and have units assigned to them. I'm trying to create a fancy way to integrate units within the field as a fixed suffix to the text, such that the user can only edit the numerical part. I'd also like for the suffix to be greyed out so the user knows it is disabled - something like the following:
While searching, I saw some solutions with a mask formatter from Swing that might do the trick, but I'm sort of hoping there might be something default with SWT. Any suggestions on how to make this work?
The field is part of a a matrix, so I can't simply add the units to a header label. I suppose I could create another column after the text field that could provide units as a label, but I'm going for something more intuitive and aesthetic.
Any suggestions?
One option would be to group Text and Label widgets in the same composite, and set the text on the Label to the desired suffix:
The area to the left of the suffix is the single-line text field, which can be edited, and the suffix is a disabled Label.
public class TextWithSuffixExample {
public class TextWithSuffix {
public TextWithSuffix(final Composite parent) {
// The border gives the appearance of a single component
final Composite baseComposite = new Composite(parent, SWT.BORDER);
baseComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
final GridLayout baseCompositeGridLayout = new GridLayout(2, false);
baseCompositeGridLayout.marginHeight = 0;
baseCompositeGridLayout.marginWidth = 0;
baseComposite.setLayout(baseCompositeGridLayout);
// You can set the background color and force it on
// the children (the Text and Label objects) to add
// to the illusion of a single component
baseComposite.setBackground(new Color(parent.getDisplay(), new RGB(255, 255, 255)));
baseComposite.setBackgroundMode(SWT.INHERIT_FORCE);
final Text text = new Text(baseComposite, SWT.SINGLE | SWT.RIGHT);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Label label = new Label(baseComposite, SWT.NONE);
label.setEnabled(false);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true));
label.setText("kg/m^3");
}
}
final Display display;
final Shell shell;
public TextWithSuffixExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
new TextWithSuffix(shell);
}
public void run() {
shell.setSize(200, 100);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static void main(final String[] args) {
new TextWithSuffixExample().run();
}
}

Wrap the text inside a Button

I am having an issue trying to do what seemed to be an easy task.
Coding an UI in java/swt, I'm trying to get the text of a button display on two lines (wrap the string passed to the button), but I can't manage to do so with the carriage return in the string, nor with the SWT.WRAP style of the button.
Here is a sample of my code :
Button myButton = new Button(compoCentre, SWT.WRAP);
myButton.setBounds(40, 200, 240, 40);
myButton.setText("A long text, but not so long, just enough);
However, this results in the text displaying on one single line, hiding the part not fitting the size of the button.
Any ideas / workaround ?
Thank you for your time.
Check out below code :
public class Sample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
Composite comp = new Composite(shell, SWT.NONE);
comp.setLayout(new GridLayout(1, false));
comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Button testButton = new Button(comp, SWT.PUSH | SWT.WRAP);
testButton.setText("A long text, but not so long, just enough");
final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
layoutData.widthHint = 100;
testButton.setLayoutData(layoutData);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Output on Windows 10:

SWT CTabFolder: Add watermark (in case of no tabs)

I am looking for a method to add a kind of watermark to a SWT CTabFolder.
My goal is that the tab folder does not look as "boring" if there are no tabs present.
I am aware of the setBackgroundImage method of CTabFolder. Unfortunately, this seems to be non adjustable and can only display an image in "tiled" format.
Do you know of any way to add a centered image to an empty tab folder?
You'll have to add your own Listeners for SWT.Paint, and SWT.Resize. Then draw your Image on the GC. Here is an example:
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final Image image = new Image(null, "info.png");
final CTabFolder folder = new CTabFolder(shell, SWT.TOP);
folder.addListener(SWT.Paint, new Listener()
{
#Override
public void handleEvent(Event event)
{
if (image.isDisposed())
return;
Rectangle parentSize = folder.getBounds();
int tabHeight = folder.getTabHeight();
Rectangle imageSize = image.getBounds();
event.gc.drawImage(image, (parentSize.width - imageSize.width) / 2, (parentSize.height - imageSize.height + tabHeight) / 2);
}
});
folder.addListener(SWT.Resize, new Listener()
{
#Override
public void handleEvent(Event event)
{
folder.redraw();
}
});
CTabItem item = new CTabItem(folder, SWT.CLOSE);
item.setText("TEST");
Composite content = new Composite(folder, SWT.NONE);
content.setLayout(new FillLayout());
new Label(content, SWT.NONE).setText("bla");
item.setControl(content);
shell.pack();
shell.setSize(400, 200);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
image.dispose();
}
Looks like this when you have a CTabItem:
And like this when you close the item:

print swt component even if hidden by scrollbar

I try to print a swt TreeViewer to png file. With:
Tree tree = treeViewer.getTree();
Image image = new Image(display, tree.getSize().x, tree.getParent().getSize().y);
GC gc = new GC(image);
System.out.println(new File(pathToSave).getAbsolutePath());
tree.print(gc);
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image.getImageData() };
loader.save(pathToSave, SWT.IMAGE_PNG);
gc.dispose();
image.dispose();
the png contains only the visible part of the tree. The tree has a scrollbar because it contains more elements than fit on the form.
I would like to print the tree with all elements visible and without scrollbar. Any ideas?
On swing components i could use .paintall().. swt components don't seem to know that.
First, the size of the image should have the size the tree would have without scrolls, and not the current size. For that you should use computeSize(SWT.DEFAULT, SWT.DEFAULT, true). Then you should resize the tree that size, print, and then resize it back. Since you don't want users to notice that, during this operation you should disabled draws with setRedraw(false).
Here is a full snippet that does all this:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new FillLayout());
final Tree tree = new Tree(composite, SWT.NONE);
for (int i = 0; i < 100; i++) {
final TreeItem treeItem = new TreeItem(tree, SWT.NONE);
treeItem.setText(String.format("item %d long name", i));
}
tree.addListener(SWT.DefaultSelection, new Listener() {
#Override
public void handleEvent(Event event) {
tree.getParent().setRedraw(false);
final Point originalSize = tree.getSize();
final Point size = tree.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
final Image image = new Image(display, size.x, size.y);
final GC gc = new GC(image);
tree.setSize(size);
tree.print(gc);
tree.setSize(originalSize);
final ImageLoader loader = new ImageLoader();
loader.data = new ImageData[]{image.getImageData()};
final String pathToSave = "out.png";
System.out.println(new File(pathToSave).getAbsolutePath());
loader.save(pathToSave, SWT.IMAGE_PNG);
gc.dispose();
image.dispose();
tree.getParent().setRedraw(true);
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
Press enter to save the file.

Enabling focus listeners on the composite container

I have four composites aligned in order.
Each composite has a check box, Label, and 2 Buttons. Now these composites are aligned one after another.
I want to enable focus on these items, i.e. when I use tab to go from one composite to other, the current composite should look highlighted. Ideally I want it to behave like a list, when you choose an item then that gets highlighted. Is this possible?
I understand that composite acts as a container for others widgets, control. My requirement is that I have a list of 5 entries, and that each item in the list has a check box, label, and two Buttons. I would also want it to be focused on when they are selected.
Also please let me know alternative solutions for the same UI that I have described above.
To make tab go from composite to composite, set the tab list for each composite to be one control that you want to have focus after a tab. For example, the check box:
composite.setTabList(new Control[]{checkButton});
To make the highlight, your imagination is the limit. You can change background, add some border, you name it. You just have to update it whenever one of the controls from the composite get focus.
Here is a full example:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout(SWT.VERTICAL));
createElement(shell);
createElement(shell);
createElement(shell);
createElement(shell);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void createElement(final Composite parent) {
final Composite composite = new Composite(parent, SWT.BORDER);
composite.setLayout(new GridLayout(4, false));
final Button checkButton = new Button(composite, SWT.CHECK);
new Label(composite, SWT.NONE);
final Button button1 = new Button(composite, SWT.PUSH);
final Button button2 = new Button(composite, SWT.PUSH);
Listener listener = new Listener() {
#Override
public void handleEvent(Event event) {
for (Control control : parent.getChildren()) {
control.setBackground(null);
}
composite.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_RED));
if (event.widget == button1 || event.widget == button2) {
checkButton.setFocus();
}
}
};
checkButton.addListener(SWT.FocusIn, listener);
button1.addListener(SWT.FocusIn, listener);
button2.addListener(SWT.FocusIn, listener);
composite.setTabList(new Control[]{checkButton});
}

Categories