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);
Related
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();
}
Today I wanted to create a simple Java SWT GUI Application using Eclipse, but for better clarity I wanted to have every sub-window in a different class. Since I am very new to Java Programming, is there a way to make a different class do its thing just by calling a method? I looked everywhere on the internet, but couldn't find what I was looking for...
Here's what I have so far
Button foo = new Button(shell, SWT.PUSH);
foo.setText("Edit");
foo.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
switch (e.type) {
case SWT.Selection:
// Call the other Class file here
break;
}
}
});
Yes. It is possible. I wouldn't call it "calling a class" though, rather "opening another window" in SWT terms.
You simply wrap a Shell in your other class, then call the open() API from "outside".
If you want to edit something, you could even create wizards.
There are many ways to do what you want to do, I simply chose one of the simple versions. But this is not the only way to do it. Wait for Baz to answer, he'll come along with another cool example. ;)
I would recommend you read the Shell's javadoc, too.
Example:
ShellTest.class (run this as Java Application)
/**
*
* #author ggrec
*
*/
public class ShellTest
{
// ==================== 2. Instance Fields ============================
private AnotherShell anotherShell;
// ==================== 3. Static Methods =============================
public static void main(final String[] args)
{
new ShellTest();
}
// ==================== 4. Constructors ===============================
private ShellTest()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
anotherShell = new AnotherShell();
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if ( !display.readAndDispatch() )
display.sleep();
}
display.dispose();
}
// ==================== 5. Creators ===================================
private void createContents(final Composite parent)
{
final Button buttonOpen = new Button(parent, SWT.PUSH);
buttonOpen.setText("Open");
buttonOpen.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
anotherShell.open();
}
});
final Button buttonClose = new Button(parent, SWT.PUSH);
buttonClose.setText("Close");
buttonClose.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
anotherShell.close();
}
});
}
}
AnotherShell.class (this would be your "other class")
/**
*
* #author ggrec
*
*/
public class AnotherShell
{
// ==================== 2. Instance Fields ============================
private Shell shell;
// ==================== 4. Constructors ===============================
public AnotherShell()
{
shell = new Shell(Display.getCurrent());
}
// ==================== 6. Action Methods =============================
public void open()
{
shell.open();
}
public void close()
{
// Don't call shell.close(), because then
// you'll have to re-create it
shell.setVisible(false);
}
}
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
When I have a operation running in the back ground, I am setting my cursor to busy until the process completes. Is there a way to also grey out and disable the current Display/Dialog/Shell until the process completes. I want to visually let the user know that something is working and they have to wait.
EDIT
plotButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event arg0) {
getShell().setEnabled(!getShell().getEnabled());
getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
recursiveSetEnabled(getShell(), getShell().getEnabled());
startPrinterListOperation(); <== This is method that runs operation
}
});
Method that runs a printer operation.
private void startPrinterListOperation() {
listOp = new AplotPrinterListOperation(appReg.getString("aplot.message.GETPRINTERLIST"), session);
listOp.addOperationListener(new MyOperationListener(this) {
public void endOperationImpl() {
try {
printers.clear();
printers.addAll((ArrayList<PrinterProfile>) listOp.getPrinters());
Display.getDefault().asyncExec(new Runnable() {
public void run() {
showAplotPlotterDialog(); <== When operation returns - opens selection dialog
}
});
}
finally {
listOp.removeOperationListener(this);
listOp = null;
}
}
});
session.queueOperation(listOp);
} // end startPrinterListOperation()
showAplotPlotterDialog() (Seperate Class) opens a dialog with network printers, then with a button push sends a job to the selected printer. When that operation finishes the Plotter Dialog closes - This is the end of that method - baseDialog is the MAIN GUI
finally {
plotOp.removeOperationListener(this);
plotOp = null;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
baseDialog.removeAllTableRows();
baseDialog.plotRequestCompleted = true;
baseDialog.setResultsButtonVisibility();
getShell().close();
}
});
}
The following should do what you want. It will recursively disable and grey out all the Controls in your Shell. The Shell itself does not have a setGrayed method, but this will work:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Button button = new Button(shell, SWT.PUSH);
button.setText("Button");
button.addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event arg0) {
shell.setEnabled(!shell.getEnabled());
shell.setCursor(new Cursor(display, SWT.CURSOR_WAIT));
recursiveSetEnabled(shell, shell.getEnabled());
}
});
new Text(shell, SWT.NONE).setText("TEXT");
shell.setSize(400, 400);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void recursiveSetEnabled(Control control, boolean enabled) {
if (control instanceof Composite)
{
Composite comp = (Composite) control;
for (Control c : comp.getChildren())
recursiveSetEnabled(c, enabled);
}
else
{
control.setEnabled(enabled);
}
}
Use
BusyIndicator.showWhile(Display.getDefault(), new Runnable()
{
public void run()
{
//operation
}
});
It sets the busy cursor on all Shells (Window, Dialog, ...) for the current Display until the Runnable.run() is executed.
Baz's answer was a great start for me, but doesn't act on Combo since it extends Composite. By making the call to setEnabled unconditional, every Control (including Combo) are enabled/disabled correctly.
private static void recursiveSetEnabled(Control control, boolean enabled) {
if (control instanceof Composite)
{
Composite comp = (Composite) control;
for (Control c : comp.getChildren())
recursiveSetEnabled(c, enabled);
}
control.setEnabled(enabled);
}
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;
}
}