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.
Related
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.
How to do a discrete (row-by-row) scrolling in SWT Table (JFace TableViewer)?
I need a Table to be scrolled "one unbroken row at a time", putting a full cell on top.
I use JFace TableViewer, but I didn't find a way to add a mouse-listener to it, so I made something like this:
TableViewer table = new TableViewer(shell, SWT.BORDER_DASH |SWT.FULL_SELECTION);
//some visual settings ommited here
table.getControl().addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseScrolled(MouseEvent e) {
Table sourceControl = (Table)e.getSource();
System.out.println(e.count);
if(e.count >=0)
sourceControl.setTopIndex(sourceControl.getTopIndex()-1);
else
sourceControl.setTopIndex(sourceControl.getTopIndex()+1);
}
});
But it turned out, that first of all if e.count equals to 3 or more, some rows are being missed. Secondly sometimes setTopIndex() not placing rows correctly.
Can it be done in more accurate way?
From what I can tell, adding a e.doit = false in the Listener works perfectly. Here is an example:
public static void main(String[] args)
{
final Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final Table table = new Table(shell, SWT.NONE);
for (int i = 0; i < 100; i++)
{
TableItem item = new TableItem(table, SWT.NONE);
item.setText("Item " + i);
}
table.addListener(SWT.MouseWheel, new Listener()
{
#Override
public void handleEvent(Event e)
{
e.doit = false;
if (e.count >= 0)
table.setTopIndex(table.getTopIndex() - 1);
else
table.setTopIndex(table.getTopIndex() + 1);
}
});
shell.pack();
shell.setSize(shell.getSize().x, 300);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
The only case where the TableItem at the top isn't displayed completely is when you reach the end of the Table and the table's height isn't an exact multiple of the TableItem's height.
I'm trying to hide a SWT shell when the Display is minimized. I'm missing something and would be most thankful for any help.
Additional Info: This shell is actually a popup that gets drawn when the user clicks on a composite. In the end, my goal is to hide this popup-shell when the composite is not visible (user minimized the window or switched between windows, say with Alt+Tab for example).
Here's my code:
static Shell middleClickNodeInfoShell ;
static Label nodeIdLabel ;
void init(){
...
/** Focused node on middle click*/
middleClickNodeInfoShell = new Shell(Display.getDefault(), SWT.BORDER | SWT.MODELESS);
middleClickNodeInfoShell.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
middleClickNodeInfoShell.setLayout(createNoMarginLayout(1, false));
nodeIdLabel = new Label(middleClickNodeInfoShell, SWT.NONE);
Display.getDefault().addListener(SWT.Iconify,new Listener() {
#Override
public void handleEvent(Event arg0) {
// TODO Auto-generated method stub
middleClickNodeInfoShell.setVisible(false);
}
});
}
#Override
public boolean onMouseClicked(Button button, ScreenPosition screenPos,
final GeoPosition arg2) {
...
nodeIdLabel.setText("Node Id: "+node.getId());
middleClickNodeInfoShell.setLocation(pos.getX()+displayX,pos.getY()+displayY+30);
middleClickNodeInfoShell.setVisible(true);
middleClickNodeInfoShell.pack();
}
Here is sample code that will help you do figure out what you are looking for
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(300, 200);
shell.setText("Shell Example");
shell.setLayout(new RowLayout());
final Button button = new Button(shell, SWT.PUSH);
button.setText("Click Me");
final Shell tip = new Shell(shell,SWT.MODELESS);
tip.setLayout(new FillLayout());
Label lbl = new Label(tip, SWT.NONE);
lbl.setText("***tooltip***");
tip.pack();
shell.addControlListener(new ControlListener() {
#Override
public void controlResized(ControlEvent e) {
changeTipLocation(display, button, tip);
}
#Override
public void controlMoved(ControlEvent e) {
changeTipLocation(display, button, tip);
}
});
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
changeTipLocation(display, button, tip);
tip.open();
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static void changeTipLocation(final Display display, final Button button, final Shell tip) {
Rectangle bounds = button.getBounds();
Point loc = button.getLocation();
tip.setLocation(display.map(button, null, new Point(loc.x+bounds.width, loc.y+bounds.height)));
}
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.
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();
}