I use a SWT Text field and I want to prevent it from being de-focused while it has no Text entered or just white spaces. Also I want to inform the User if thatĀ“s the case.
My current solution is that I check it inside a FocusListenerĀ“s focusLostMethod.
But the focusLost Event is sended twice so the User will get informed twice and thats not what I want. So my Questions are:
Is it normal that the focusLostEvent ist sended multiple times? Or is there something wrong in my application?
If it is normal: Is there a possibility to ensure the User gets informed just once?
This code here works just fine. SWT.FocusOut is only fired one:
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final Text text = new Text(shell, SWT.BORDER);
text.addListener(SWT.FocusOut, new Listener()
{
#Override
public void handleEvent(Event event)
{
if (text.getText().trim().length() < 1)
{
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
System.out.println("Please enter something!");
if (text != null && !text.isDisposed())
{
text.setFocus();
text.forceFocus();
}
}
});
}
else
{
System.out.println("Nothing to see here, move along.");
}
}
});
new Text(shell, SWT.BORDER);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
Related
I need to know if there is any way to open a shell and not make it active, even if i click a control in it. The best way to explain what i need is to show you this little example. I need to keep the first shell active, even if i click the second one, or any widget that it contains.
public class TestMeOut
{
public static void main(final String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
final Shell shell2 = new Shell(shell);
shell2.setLayout(new GridLayout());
final Button btn = new Button(shell, SWT.PUSH);
final Button btn2 = new Button(shell2, SWT.PUSH);
btn.setText("Test me");
btn2.setText("I steal focus");
btn.addSelectionListener(new SelectionAdapter()
{
#Override
public void widgetSelected(final SelectionEvent e)
{
shell2.setVisible(true);
}
});
btn2.addSelectionListener(new SelectionAdapter()
{
#Override
public void widgetSelected(final SelectionEvent e)
{
shell2.setVisible(false);
}
});
shell.pack();
shell.open();
shell.addShellListener(new ShellListener()
{
public void shellIconified(final ShellEvent e)
{
}
public void shellDeiconified(final ShellEvent e)
{
}
public void shellDeactivated(final ShellEvent e)
{
System.out.println("Deactivated! This isn't supposed to happen.");
}
public void shellClosed(final ShellEvent e)
{
}
public void shellActivated(final ShellEvent e)
{
System.out.println("Activated!");
}
});
shell2.pack();
shell2.open();
shell2.setVisible(false);
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Thank you in advance!
You can change the style of your second Shell and use SWT.APPLICATION_MODAL which will make sure that you cannot interact with the parent shell unless you close the child shell:
final Shell shell2 = new Shell(shell, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
The modality of an instance may be specified using style bits. The modality style bits are used to determine whether input is blocked for other shells on the display. The PRIMARY_MODAL style allows an instance to block input to its parent. The APPLICATION_MODAL style allows an instance to block input to every other shell in the display. The SYSTEM_MODAL style allows an instance to block input to all shells, including shells belonging to different applications.
Even SWT.PRIMARY_MODAL would suffice in this case.
UPDATE
If on the other hand you don't want the parent to loose focus when the child is clicked, just disable the child:
shell2.setEnabled(false);
I want to capture Shift+Left Mouse Up event in SWT. I just want to print some sample message only while holding shift key down and releasing the left mouse button.
Listen for SWT.MouseUp and compare the Event.stateMask to SWT.SHIFT, then compare Event.button to 1.
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout());
Text text = new Text(shell, SWT.BORDER);
text.addListener(SWT.MouseUp, new Listener()
{
#Override
public void handleEvent(Event e)
{
if ((e.stateMask & SWT.SHIFT) != 0 && e.button == 1)
{
System.out.println("shift pressed and left mouse clicked");
}
}
});
shell.pack();
shell.open();
shell.layout(true, true);
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
I wish to use org.eclipse.swt.widgets.List just to present some data. User should not be allowed to select any item.
I could just:
List list = new List(this, SWT.V_SCROLL);
list.setEnabled(false);
But then I will loose scrolling feature. How can I just make list items unselectable?
Another alternative is to use a Table instead of List and disable selection painting like this:
table.addListener(SWT.EraseItem, new Listener() {
#Override
public void handleEvent(Event event) {
event.detail &= ~SWT.SELECTED;
event.detail &= ~SWT.HOT;
}
});
You could try to clear selection each time user selects an item. The selection will be visible for a short time interval, though.
list.addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event event) {
list.setSelection(new String[0]);
}
});
If you don't like my other answer with clearing selection, you could try to keep the list disabled, but inside a ScrolledComposite. It will look disabled, but scrolling will work. Here is a snippet:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
scrolledComposite.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
final List list = new List(scrolledComposite, SWT.NONE);
list.setEnabled(false);
scrolledComposite.setContent(list);
scrolledComposite.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(Event event) {
final Point size = list.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
scrolledComposite.setMinSize(size);
}
});
for (int i = 0; i < 1000; i++) {
list.add(Integer.toString(i));
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
Arrow keys and page up/down down do not work, so you will have to register key listeners and implement scrolling with keyboard.
So I've stolen this cool PopupComposite, and I am really satisfied with it.
There's just one issue. If it put a org.eclipse.swt.widgets.Text in it, I open the popup, focus the Text, and press ESC, then both the Text and the PopupComposite dispose themselves.
I really can't figure out where the dispose call is coming from. Is it a Shell issue? What Shell should I use with the popup?
SSCCE:
/**
*
* #author ggrec
*
*/
public class PopupCompositeTester
{
public static void main(final String[] args)
{
new PopupCompositeTester();
}
private PopupCompositeTester()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if ( !display.readAndDispatch() )
display.sleep();
}
display.dispose();
}
private static void createContents(final Composite parent)
{
final Button button = new Button(parent, SWT.PUSH);
button.setText("Poke Me");
final PopupComposite popup = new PopupComposite(parent.getShell());
new Text(popup, SWT.NONE);
popup.pack();
button.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
popup.show( Display.getDefault().map(parent, null, button.getLocation()) );
}
});
}
}
The reason for this is because when you focus the text field and press Escape, the field sends a SWT.TRAVERSE_ESCAPE event to its parent shell. The shell (in your case not being a top-level shell) responds by calling Shell.close(). You can work around that by adding a traverse listener to your text field, which would cancel the event (code below).
new Text(popup, SWT.NONE).addTraverseListener(new TraverseListener() {
#Override
public void keyTraversed(TraverseEvent e) {
if(e.detail == SWT.TRAVERSE_ESCAPE) {
e.doit = false;
}
}
});
Keep in mind, this is a rather crude solution to your specific issue. I would not recommend using this for anything other than testing purposes. You can read more about this here -> http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fevents%2FTraverseEvent.html
And here: http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fwidgets%2FShell.html
Because my "bug" is actually a normal behaviour of the SWT platform, I've used the following workaround:
/**
* Lazy initialization of the popup composite
*/
private void createPopup()
{
// popupContainer is now a field
if (popupContainer != null && !popupContainer.isDisposed())
return;
// ... create popup AND its contents ...
}
and in the button listener:
createPopup();
popup.show( Display.getDefault().map(parent, null, button.getLocation()) );
Thank you #blgt
Group group = new Group(parent, SWT.NONE);
StyledText comment = new StyledText(group, SWT.BORDER_DASH);
This creates a group with a text area inside.
How can I later delete the text (remove it from the screen so that I can replace it with something else)?
Use Widget.dispose.
public class DisposeDemo {
private static void addControls(final Shell shell) {
shell.setLayout(new GridLayout());
Button button = new Button(shell, SWT.PUSH);
button.setText("Click to remove all controls from shell");
button.addSelectionListener(new SelectionListener() {
#Override public void widgetDefaultSelected(SelectionEvent event) {}
#Override public void widgetSelected(SelectionEvent event) {
for (Control kid : shell.getChildren()) {
kid.dispose();
}
}
});
for (int i = 0; i < 5; i++) {
Label label = new Label(shell, SWT.NONE);
label.setText("Hello, World!");
}
shell.pack();
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
addControls(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Another option is to use a StackLayout to switch between underlying controls. This prevents you from running into a "widget is disposed" error.
You have to either call comment.changeParent(newParent) or comment.setVisible(false) to remove/hide it from the Group. I am unsure if comment.changeParent(null) would work but I would give that a try.
We do it this way because SWT uses the Composite Pattern.
group.getChildren()[0].dispose() will remove the first child. You need to find a way to identify the precise child you want to delete. It could be comparing the id. You can do that by using the setData / getData on that control:
For example:
StyledText comment = new StyledText(group, SWT.BORDER_DASH);
comment.setData("ID","commentEditBox");
and then:
for (Control ctrl : group.getChildren()) {
if (control.getData("ID").equals("commentEditBox")) {
ctrl.dispose();
break;
}
}