On SWT spinner (or maybe some other similar SWT widget), how can I force the user to use the UI buttons instead of edit the text from the keyboard. thanks.
SWT.READ_ONLY will prevent the user from entering values. To disable arrow keys as well, you can do something like this:
public static void main(String args[])
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
Spinner spinner = new Spinner(shell, SWT.READ_ONLY);
spinner.addListener(SWT.Verify, new Listener()
{
#Override
public void handleEvent(Event e)
{
if(e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN)
{
e.doit = false;
}
}
});
shell.pack();
shell.setSize(100, shell.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
shell.open();
while (!shell.isDisposed())
{
if (!shell.getDisplay().readAndDispatch())
shell.getDisplay().sleep();
}
}
This will make sure that the only way to change the Spinner value is using the buttons.
Related
I want to add a KeyListener to my existing window. I want to catch 3 KeyDown's. On the first KeyDown I want to put something in a Combo. On the second KeyDown I want to put something in another Combo. If both textbox are filled, I want the next KeyDown to simulate the OK Button.
But I have a problem with the error widget disposed. Because I dont know when to remove the filter correct. This only happend if I open the window again!
My Code:
_disp.addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(Event e) {
if(!_disp.isDisposed()){
_disp.removeFilter(SWT.KeyDown, this);
}
if (e.keyCode == SWT.CR) {
if (_cmbCCID.getText().isEmpty()) {
_cmbCCID.setText(_lastFiveCCID[0]);
} else if (_cmbDescription.getText().isEmpty()) {
_cmbDescription.setText(_lastFiveComment[0]);
} else if (!_cmbCCID.getText().isEmpty() && !_cmbDescription.getText().isEmpty()) {
_btnOk.notifyListeners(SWT.Selection, new Event());
}
}
}
});
You're removing the filter after the first key press. Try something like this:
public static void main(String[] args)
{
final Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
new Text(shell, SWT.NONE);
display.addFilter(SWT.KeyDown, new Listener()
{
int i = 0;
#Override
public void handleEvent(Event arg0)
{
if (i < 2)
System.out.println("Press " + i);
else
{
System.out.println("Press " + i);
System.out.println("Remove");
if (!display.isDisposed())
display.removeFilter(SWT.KeyDown, this);
}
i++;
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
while (!display.readAndDispatch())
{
display.sleep();
}
}
}
It will remove the filter after the third key press event.
i have another question. I use a ModifyListener for one textfield to activate and deactivate the OK-Button in a swt dialog. It works great.
Now I want to add a ModifyListener for another textfield. I want that the OK-Button only is activated if in both text fields is min one char.
This is the code of the two fields:
descriptionText.addModifyListener(new ModifyListener(){
public void modifyText(ModifyEvent e) {
Text text = (Text) e.widget;
if (text.getText().length() == 0) {
getButton(IDialogConstants.OK_ID).setEnabled(false);
}
if (text.getText().length() >= 1) {
getButton(IDialogConstants.OK_ID).setEnabled(true);
}
}
});
}
the second field:
ccidText.addModifyListener(new ModifyListener(){
public void modifyText(ModifyEvent e) {
Text text = (Text) e.widget;
if (text.getText().length() == 0) {
getButton(IDialogConstants.OK_ID).setEnabled(false);
}
if (text.getText().length() >= 1){
getButton(IDialogConstants.OK_ID).setEnabled(true);
}
}
});
}
I know that it doesn´t work because there are no dependencies between the two buttons.
How can i combine it?
I want to set the ok-button false while both modifylistener detect a char.
If i delete all chars in one testfield the button must be deactivated again.
Thank u.
You can use the same Listener for both Text fields and add it for SWT.KeyUp:
public static void main(String[] args)
{
final Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout(SWT.VERTICAL));
final Text first = new Text(shell, SWT.BORDER);
final Text second = new Text(shell, SWT.BORDER);
final Button button = new Button(shell, SWT.PUSH);
button.setText("disabled");
button.setEnabled(false);
Listener listener = new Listener()
{
#Override
public void handleEvent(Event e)
{
String firstString = first.getText();
String secondString = second.getText();
button.setEnabled(!isEmpty(firstString) && !isEmpty(secondString));
button.setText(button.isEnabled() ? "enabled" : "disabled");
}
};
first.addListener(SWT.KeyUp, listener);
second.addListener(SWT.KeyUp, listener);
shell.pack();
shell.setSize(300, shell.getSize().y);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static boolean isEmpty(String input)
{
if(input == null)
return true;
else
return input.trim().isEmpty();
}
Looks like this:
The code will basically (on each key stroke) check if both Texts are empty. If so, disable the Button, else enable it.
When I press a button, I want to change the foreground color of the selected item in a List.
So far, I tried this:
list.setForeground(display.getSystemColor(SWT.COLOR_RED));
but it changes the foreground color of all the items, not just the selected one.
Any ideas how to solve this?
Doing this with a List would require custom drawing. You are better off using a Table instead (or even a TableViewer depending on your requirements). Here is an example of a table that does what you want:
public static void main(String[] args)
{
final Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
shell.setText("StackOverflow");
final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
for (int i = 0; i < 10; i++)
{
TableItem item = new TableItem(table, SWT.NONE);
item.setText("item " + i);
}
Button button = new Button(shell, SWT.PUSH);
button.setText("Color selected");
button.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
List<TableItem> allItems = new ArrayList<>(Arrays.asList(table.getItems()));
TableItem[] selItems = table.getSelection();
for (TableItem item : selItems)
{
item.setForeground(display.getSystemColor(SWT.COLOR_RED));
allItems.remove(item);
}
for (TableItem item : allItems)
{
item.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Before button press:
After button press:
Just a note: This is not the most efficient way to do it, but should give you the basic idea.
List does not supports what you want.
Use Table and Table items instead.
Each table item represent a row, and it has setForeground(Color) method.
Is there a standard SWT control that resembles a button which displays an arrow and opens a dropdown menu when pressed and is not a toolbar-only control?
It would be something like this:
It is similar to a combo box control, except that the "button" area would act more similarly to an actual button - its text would not change based on your selection, it would appear depressed when clicked, and the items would be used for actions or navigational purposes instead of for selection. It's also similar to a control available for toolbars, but I need to use it on a regular composite instead.
This is nearly doable simply by using regular button and popup-menu controls - however, I do not believe I can display the arrow next to the text on the button this way. Anyway, since this kind of control seems fairly common, I assumed there would be a standard way to use these two things as one.
I think, this is what you should do get Drop down menu behavior
Create Menu with style SWT.DROP_DOWN
Create MenuItems on Menu
if you want a button
Create a Button with style SWT.ARROW | SWT.DOWN
add SelectionListener
In SelectionListener, Create a Menu with style SWT.POP_UP and position the menu at the button location.
//code
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(300, 200);
shell.setText("Button Example");
shell.setLayout(new RowLayout());
/**
*
* Approach1
*
*/
final Composite btnCntrl = new Composite(shell, SWT.BORDER);
btnCntrl.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
btnCntrl.setBackgroundMode(SWT.INHERIT_FORCE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).spacing(0, 1).applyTo(btnCntrl);
CLabel lbl = new CLabel(btnCntrl, SWT.NONE);
lbl.setText("Animals");
Button btn = new Button(btnCntrl, SWT.FLAT|SWT.ARROW|SWT.DOWN);
btn.setLayoutData(new GridData(GridData.FILL_VERTICAL));
btn.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
Menu menu = new Menu(shell, SWT.POP_UP);
MenuItem item1 = new MenuItem(menu, SWT.PUSH);
item1.setText("Hare");
MenuItem item2 = new MenuItem(menu, SWT.PUSH);
item2.setText("Fox");
MenuItem item3 = new MenuItem(menu, SWT.PUSH);
item3.setText("Pony");
Point loc = btnCntrl.getLocation();
Rectangle rect = btnCntrl.getBounds();
Point mLoc = new Point(loc.x-1, loc.y+rect.height);
menu.setLocation(shell.getDisplay().map(btnCntrl.getParent(), null, mLoc));
menu.setVisible(true);
}
});
/***
*
*
* Approach 2
*
*/
final Composite btnCntrl2 = new Composite(shell, SWT.BORDER);
btnCntrl2.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
btnCntrl2.setBackgroundMode(SWT.INHERIT_FORCE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).spacing(0, 1).applyTo(btnCntrl2);
CLabel lbl2 = new CLabel(btnCntrl2, SWT.NONE);
lbl2.setText("Animals");
Button btn2 = new Button(btnCntrl2, SWT.FLAT|SWT.ARROW|SWT.DOWN);
btn2.setLayoutData(new GridData(GridData.FILL_VERTICAL));
btn2.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
Shell menu = (Shell) btnCntrl2.getData("subshell");
if(menu != null && !menu.isDisposed()){
menu.dispose();
}
menu = new Shell(shell, SWT.NONE);
menu.setLayout(new FillLayout());
Table table = new Table(menu, SWT.FULL_SELECTION);
table.addListener(SWT.MeasureItem, new Listener() {
#Override
public void handleEvent(Event event) {
event.height = 20; //TODO: determine later
}
});
table.addListener(SWT.PaintItem, new Listener() {
#Override
public void handleEvent(Event event) {
Rectangle bounds = event.getBounds();
event.gc.setBackground(event.display.getSystemColor(SWT.COLOR_BLUE));
event.gc.drawLine(bounds.x, bounds.y+bounds.height-1, bounds.x+bounds.width, bounds.y+bounds.height-1);
}
});
TableItem tableItem= new TableItem(table, SWT.NONE);
tableItem.setText(0, "Hare");
TableItem tableItem2= new TableItem(table, SWT.NONE);
tableItem2.setText(0, "Pony" );
TableItem tableItem3= new TableItem(table, SWT.NONE);
tableItem3.setText(0, "Dog");
Point loc = btnCntrl2.getLocation();
Rectangle rect = btnCntrl2.getBounds();
Point mLoc = new Point(loc.x, loc.y+rect.height);
menu.setLocation(shell.getDisplay().map(btnCntrl2.getParent(), null, mLoc));
menu.pack();
menu.setVisible(true);
btnCntrl2.setData("subshell", menu);
}
});
display.addFilter(SWT.MouseDown, new Listener() {
#Override
public void handleEvent(Event event) {
Shell shell = (Shell) btnCntrl2.getData("subshell");
if(shell != null && !shell.getBounds().contains(event.display.map((Control)event.widget, null, new Point(event.x, event.y)))){
shell.dispose();
btnCntrl2.setData("subshell", null);
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
This snippet shows how to use the described widget in a SWT toolbar. You can set the button text by using the item.setText() method.
This question is almost 10 years old, but just in case someone is still looking for a solution (like I just did ;) ):
I achieved a pretty close behaviour of your description using only a Button and a Menu using this approach: http://eclipseo.blogspot.com/2012/07/show-context-menu-programmatically.html
Button button = new Button(parent, SWT.PUSH);
button.setText("Animals");
Menu menu = new Menu(button);
MenuItem item = new MenuItem(menu, SWT.PUSH);
item.setText("hare");
menu.addListener(SWT.Show, new Listener() {
#Override
public void handleEvent(Event event) {
menu.setVisible(true);
}
});
button.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
menu.notifyListeners(SWT.Show, null);
}
});
The result is that the menu is shown when you (left) click on the button.
Bonus: to achieve the expand icon at the end, you can add a unicode character for a down triangle in the button text like so:
button.setText("Animals \u2BC6");
HTH,
Ben
Consider the following Java (SWT) code:
private static ComboViewer createViewer(final Shell shell) {
final ComboViewer v = new ComboViewer(shell, SWT.DROP_DOWN);
v.setLabelProvider(new LabelProvider());
v.setContentProvider(new ArrayContentProvider());
v.setInput(new String[]{"value 1", "value 2"});
return v;
}
public static void main(final String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(200, 60);
shell.setLayout(new GridLayout());
final ComboViewer v = createViewer(shell);
// This wires up the userSelectedSomething method correctly
v.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(final SelectionChangedEvent event) {
userSelectedSomething();
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static void userSelectedSomething() {
// This should be called *only if* the user selected from the drop-down
}
public static void userTypedSomething() {
// This should be called *only if* the user typed in the combo
}
I want to call the userTypedSomething method only if the user typed into the combo (and not when they selected from the drop-down). What listener should I add to achieve this? Adding a modify listener to the combo viewer with v.getCombo().addModifyListener(...) is no good as this is triggered for both typing and selection from the combo.
private static ComboViewer createViewer(final Shell shell) {
final ComboViewer v = new ComboViewer(shell, SWT.DROP_DOWN);
v.setLabelProvider(new LabelProvider());
v.setContentProvider(new ArrayContentProvider());
v.setInput(new String[]{"value 1", "value 2"});
return v;
}
private static boolean userTyped;
private static int index = -1;
public static void main(final String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(200, 60);
shell.setLayout(new GridLayout());
final ComboViewer v = createViewer(shell);
/*
* invoked multiple times when combo selection happens
* invoked once when user types
*/
v.getCombo().addVerifyListener(new VerifyListener() {
#Override
public void verifyText(VerifyEvent e) {
userTyped = (e.keyCode != 0);
}
});
v.getCombo().addModifyListener(new ModifyListener() {
#Override
public void modifyText(ModifyEvent e) {
Combo c = (Combo)e.widget;
if(userTyped || index == c.getSelectionIndex() || c.getSelectionIndex() == -1)
{
userTypedOrEditedSomething();
}
index = c.getSelectionIndex();
}
});
// This wires up the userSelectedSomething method correctly
v.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(final SelectionChangedEvent event) {
userSelectedSomething();
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static void userSelectedSomething() {
// This should be called *only if* the user selected from the drop-down
System.out.println("User selected");
}
public static void userTypedOrEditedSomething() {
// This should be called *only if* the user typed in the combo
System.out.println("User typed or edited");
}
I would suggest you to use Verify event instead Key UP as you might endup handling lot of things (arrow keys, magic keys...etc). Verify is also Key Event but it filter out ALT,CNTRL,SHIFT combination. When user types just check for keycode!=0.
As you pointed out, when you use CNTRL+V ,Right click Menu paste....combo doesn't consider it as key event but it fires verify event to make sure the clipboard text is valid for combo or not. I think this is how it should work as Menu item selection and Key event on combo are different things.
you can always monitor all key events for special actions like copy/paste/delete.
the above sample code should be able to perform what you are looking for.
Since you want to listen to keyboard input, I would suggest listening to SWT.KeyUp.
This should be a good starting point:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final Combo combo = new Combo(shell, SWT.NONE);
combo.add("First");
combo.add("Second");
combo.addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event arg0) {
System.out.println("Selected: " + combo.getItem(combo.getSelectionIndex()));
}
});
combo.addListener(SWT.KeyUp, new Listener() {
#Override
public void handleEvent(Event arg0) {
System.out.println("Typed");
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}