In GTK, SWT.ON_TOP causes unpredictable behaviour on .setfocus() - java

Here's what I want to achieve:
On some trigger (here: click of a button), a floating toolbar should appear. The focus should still be on the text input field after this.
When a button in the floating toolbar is clicked, the focus should remain with the text input field.
The floating toolbar should realised by a Shell that is always-on-top.
I have achieved (1) by introducing a ShellListener on the overlay shell that calls text.setFocus (based on this question).
I have achieved (2) by keeping a MouseListener on the button and calling text.setFocus on click.
Now, my problem is that each solution works fine on its own. However, when I use both listeners (as in the MWE below), I get weird behaviour:
The text field is correctly focussed after the overlay shell appears
Clicking the button in the overlay shell does not return the focus to the text field unless
You manually focus the main shell by clicking anywhere in it
You spam clicks on the button in the overlay shell, after some random amount of clicks, the text input is correctly focussed, and then also for each successive click.
This seems to a problem specific to Ubuntu (GTK). I am using SWT 4.16.
Consider the following MWE.
Note that everything works fine if we omit SWT.ON_TOP and replace it with SWT.SHELL_TRIM.
Weirdly enough, with SWT.ON_TOP, shellActivated on overlayShell does not always trigger when the button in the overlay shell is clicked, and when it does, it does not coincide with the focus being correctly transferred.
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class ShellWithoutTitleBarSO2 {
public static void main(String[] args) {
final Display display = new Display();
final Shell mainShell = new Shell(display, SWT.SHELL_TRIM);
mainShell.setSize(300, 200);
mainShell.setLayout(new GridLayout());
mainShell.open();
Text text = new Text(mainShell, SWT.BORDER);
final Shell overlayShell = new Shell(display, SWT.ON_TOP);
overlayShell.setSize(150, 150);
overlayShell.setLocation(400, 200);
overlayShell.setLayout(new GridLayout());
// (1) give back focus when overlay shell is first opened
overlayShell.addShellListener(new ShellListener() {
#Override public void shellActivated(ShellEvent arg0) {
text.setFocus();
}
#Override public void shellClosed(ShellEvent arg0) { }
#Override public void shellDeactivated(ShellEvent arg0) { }
#Override public void shellDeiconified(ShellEvent arg0) { }
#Override public void shellIconified(ShellEvent arg0) { }
});
Button button = new Button(mainShell, SWT.PUSH);
button.setText("open overlayShell");
button.addMouseListener(new MouseListener() {
#Override public void mouseDoubleClick(MouseEvent e) { }
#Override public void mouseDown(MouseEvent e) { }
#Override public void mouseUp(MouseEvent e) {
overlayShell.setVisible(true);
}
});
Button buttonInOverlay = new Button(overlayShell, SWT.PUSH | SWT.BORDER);
buttonInOverlay.setText("foo");
// (2) give back focus when button in overlay is clicked
// this seems to only work (randomly, race-condition like) when overlay shell
// has SWT.ON_TOP. If not, then no effect.
buttonInOverlay.addMouseListener(new MouseListener() {
#Override public void mouseDoubleClick(MouseEvent arg0) { }
#Override public void mouseDown(MouseEvent arg0) { }
#Override public void mouseUp(MouseEvent arg0) {
boolean didSetFocus = text.setFocus();
// notably, this is true even when focus is effectively not set
}
});
// Set up the event loop.
while (!mainShell.isDisposed()) {
if (!display.readAndDispatch()) {
// If no more entries in event queue
display.sleep();
}
}
display.dispose();
}
}
I've begun stepping through the SWT source code but I'm quite puzzled by it. Does anyone have any ideas what might cause this weird issue?

Related

Java wait code until JFrame keyPressed

I'm using a JFrame and I wanted to display an image and pause the code until the user presses ANY key. After that key being pressed the image would close and the code would continue running.
What I did:
Created a flag
final boolean[] flag = {true};
Added a addKeyListener to the JFrame object that would change the flag
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
frame.setVisible(false);
frame.dispose();
flag[0] = false;
}
});
Wait loop until flagged
while (flag[0]){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This is working, but I understand that it is a bit resourceful.
Is there any other way of making the wait loop? Is there any listener of the listener?
2nd try, using CountDownLatch:
Set the latch
final CountDownLatch latch = new CountDownLatch(1);
CountDown
for (JFrame frame : framesList) {
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
frame.setVisible(false);
frame.dispose();
latch.countDown();
}
});
Wait
latch.await();
So, you want to display an image and have the execution stop until the window is closed. This just screams modal dialog to me. A modal dialog will stop the code execution from where it is made visible, it will do it in such away so as not to block the Event Dispatching Thread and make your entire problem come to a screaming halt and hang the program. See How to use dialogs for more details...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
BufferedImage img = ImageIO.read(...);
ImageShower.show(null, img);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public static class ImageShower extends JPanel {
private JLabel label = new JLabel();
public ImageShower() {
setLayout(new BorderLayout());
add(label);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
am.put("close", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.windowForComponent(ImageShower.this);
if (window != null) {
window.dispose();
}
}
});
}
public void setImage(Image img) {
label.setIcon(new ImageIcon(img));
}
public static void show(Component owner, Image img) {
Window parent = null;
if (owner != null) {
parent = SwingUtilities.windowForComponent(owner);
}
JButton close = new JButton("Close");
close.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
Window window = SwingUtilities.windowForComponent(btn);
if (window != null) {
window.dispose();
}
}
});
JDialog dialog = new JDialog(parent, Dialog.ModalityType.APPLICATION_MODAL);
ImageShower shower = new ImageShower();
shower.setImage(img);
dialog.add(shower);
dialog.add(close, BorderLayout.SOUTH);
dialog.getRootPane().setDefaultButton(close);
dialog.pack();
dialog.setLocationRelativeTo(owner);
dialog.setVisible(true);
}
}
}
"But wait, may images are large and take time to load and I don't want to freeze the UI while the load"...
Okay, for that, I'd look towards using a SwingWorker, which can load the image in the background but which provides simple methods for ensuring the the image is displayed within the context of the EDT properly...
public class ImageLoadAndShow extends SwingWorker<Void, Image> {
#Override
protected Void doInBackground() throws Exception {
BufferedImage img = ImageIO.read(...);
publish(img);
return null;
}
#Override
protected void process(List<Image> chunks) {
Image img = chunks.get(chunks.size() - 1);
ImageShower.show(null, img);
}
}
Not, if the image fails to load, you won't know about it, as the doInBackground method will pass the Exception out of the method. You'd need to use a combination of a PropertyChangeListener and the SwingWorkers get method to trap it, just remember, get is blocking, so calling it inside the context of the EDT will block until the worker completes
"But I need to carry out other operations when the dialog is closed"
There are a few ways you might be able to achieve this, depending on what it is you want to do, for this example, I've stuck with the SwingWorker, because it was easy to copy and paste the basic structure, but you could use a Runnable wrapped in a Thread
public class ImageLoadShowAndWait extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
BufferedImage img = ImageIO.read(...);
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
ImageShower.show(null, img);
}
});
return null;
}
}
Now, if none of that does what you want...then I'd like to know what it is you're actually doing :P, have a look at Foxtrot which provides an API which allows you to execute code asynchronisly within the EDT without blocking it (entirly), but which will stop the code execution at the point it's called until it completes
The thing is that I wanted it to close the JFrame when ANY key is pressed
KeyListener is going to give you issues, maybe not today, maybe not tomorrow, but it will blow up in your face eventually. The example I've provide binds the Escape key to dispose of the window. It also makes the "Close" button the default button, which provides Space and/or Enter keys as well and a nice visual queue to the user.
If you want to use KeyListener, that's up to you, but your core problem doesn't seem to revolve around it, but the ability to display a window and pause the code execution till it's closed

cannot always load the picture on click and hover

I am making a launcher application, i wish to change the button depending on the action taken, right now i want to change the button when the following actions happen, either the player hovers over the image, clicks on the image, releases the image click or exits the hover. The issue i have is that it doesn't always load correctly, which is odd.
package LostStory;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class LaunchPanel extends JComponent {
Image image;
JButton play;
SystemTray tray;
ImageIcon icon = new ImageIcon("res/images/buttons/playNonHover.png");
ImageIcon iconHover = new ImageIcon("res/images/buttons/playHover.png");
ImageIcon iconClick = new ImageIcon("res/images/buttons/playClick.png");
public LaunchPanel(Image img) {
this.image = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
init();
}
public void init() {
play = new JButton("Play Lost Story", icon);
play.setBounds(85, 210 - 75, getWidth() - 165, 50);
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Runtime run = Runtime.getRuntime();
try {
run.exec("notepad");
if (SystemTray.isSupported()) {
tray = SystemTray.getSystemTray();
play.setIcon(play.getIcon());
// Main.getClient().getJFrame().setVisible(false);
// tray.add(img);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
play.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent arg0) {
} // no use
#Override
public void mouseEntered(MouseEvent e) {
if (iconHover.getImageLoadStatus() == 8) {
play.setIcon(iconHover);
play.setIcon(play.getIcon());
System.out.println("Entered");
}
System.out.println(iconHover.getImageLoadStatus());
} // use
#Override
public void mouseExited(MouseEvent arg0) {
if (icon.getImageLoadStatus() == 8) {
play.setIcon(icon);
play.setIcon(play.getIcon());
System.out.println("Exited");
}
System.out.println(icon.getImageLoadStatus());
} // use
#Override
public void mousePressed(MouseEvent arg0) {
if (iconClick.getImageLoadStatus() == 8) {
play.setIcon(iconClick);
play.setIcon(play.getIcon());
System.out.println("Pressed");
}
System.out.println(iconClick.getImageLoadStatus());
} // use
#Override
public void mouseReleased(MouseEvent arg0) {
if (icon.getImageLoadStatus() == 8) {
play.setIcon(icon);
play.setIcon(play.getIcon());
System.out.println("Released");
}
System.out.println(icon.getImageLoadStatus());
} // use
});
add(play);
}
}
The first button always loads (because it is the default one) it returned an '8' when i tried using the IconImage.getImageLoadStatus() so i expected that to be '8' if it was succesfully loaded. (This is not the case though, it will always return 8 as far as i know).
So TL;DR: How do i make sure the ImageIcons are always loaded and will apply correctly?
Don't try to manipulate the icon using the setIcon() method.
A JButton has methods to set the icon for various states setRolloverIcon, setPressedIcon, etc.
Read the API for other properties.
Also, a painting method is for painting only. Never create components from a painting method. Get rid of the init() method from your paintComponent() method.
Components should be created and added to the panel in the constructor of the panel.

New JFrame is opening in disabled state when opened on a button click

I am stuck with a very unusual situation. I have a class "ScreenSizeSelector" which has a method 'getSelectedScreenSize'. The method's work is to create a UI, user drags the UI and method return back size of window.
Now I am calling the method of class in following ways:
A simple class (non GUI)
On the button click from a JFrame
In the first case, it is working perfectly fine (i.e. size selector window opens, user drags it, resize it and it is giving back window coordinates) but in second case, window opens but in disabled mode, user is not able to perform any operation on the window, not even able to close the window.
Here is the code I am using
ScreenSizeSelector class :
package screenrecorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;
class ScreenSizeSelector {
private JFrame sizeSelectorWindow;
private JButton btnOk;
private Border emptyBorder;
private Rectangle screenArea = null;
private static Object lock = new Object();
public Rectangle getSelectedScreenSize(){
screenSizeSelectorUI();
Thread t = new Thread() {
public void run() {
synchronized(lock) {
while (sizeSelectorWindow.isVisible())
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return screenArea;
}
public void screenSizeSelectorUI() {
emptyBorder = BorderFactory.createEmptyBorder();
sizeSelectorWindow = new JFrame("Select screen area");
btnOk = new JButton("Start");
sizeSelectorWindow.setUndecorated(true);
sizeSelectorWindow.getRootPane().setWindowDecorationStyle(3);
sizeSelectorWindow.setBackground( new Color(0, 0, 0, 0) );
sizeSelectorWindow.setSize(400,400);
sizeSelectorWindow.addWindowListener(new WindowEventHandler());
sizeSelectorWindow.setAlwaysOnTop(true);
sizeSelectorWindow.setLocationRelativeTo(null);
btnOk.setToolTipText("Click this button after deciding the screen area");
btnOk.addActionListener(new ButtonEventHandler());
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.setBackground(new Color(0,0,0,0));
buttonPanel.add(btnOk);
sizeSelectorWindow.add(buttonPanel,BorderLayout.SOUTH);
sizeSelectorWindow.setVisible(true);
sizeSelectorWindow.setEnabled(true);
}
class ButtonEventHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int x = (int)(sizeSelectorWindow.getBounds().getX());
int y = (int) (sizeSelectorWindow.getBounds().getY());
int width = sizeSelectorWindow.getWidth();
int height = sizeSelectorWindow.getHeight();
screenArea = new Rectangle(x,y,width,height);
sizeSelectorWindow.dispatchEvent(new WindowEvent(sizeSelectorWindow, WindowEvent.WINDOW_CLOSING));
}
}
class WindowEventHandler implements WindowListener{
#Override
public void windowOpened(WindowEvent e) {
}
#Override
public void windowClosing(WindowEvent e) {
synchronized (lock) {
sizeSelectorWindow.setVisible(false);
lock.notify();
}
}
#Override
public void windowClosed(WindowEvent e) {
}
#Override
public void windowIconified(WindowEvent e) {
sizeSelectorWindow.setState(JFrame.NORMAL);
Toolkit.getDefaultToolkit().beep();
}
#Override
public void windowDeiconified(WindowEvent e) {}
#Override
public void windowActivated(WindowEvent e) {}
#Override
public void windowDeactivated(WindowEvent e) {}
}
}
Test1 class :
package screenrecorder;
import java.awt.Rectangle;
public class Test1{
public static void main(String[] args){
System.out.println(new ScreenSizeSelector().getSelectedScreenSize());
}
}
Test2 class :
package screenrecorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Test2 extends JFrame{
public Test2(){
JButton btn = new JButton("Click ME");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(new ScreenSizeSelector().getSelectedScreenSize());
}
});
getContentPane().add(btn);
setSize(100,100);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args){
new Test2();
}
}
Any help is appreciated.
when you click the button, the action listener waits for the getSelectedScreenSize() function to return. and the getSelectedScreenSize() function is waiting for the second window created by screenSelectorUI() to be invisible. screenSelectorUI() does create a second window, but you set the color like this:
sizeSelectorWindow.setBackground( new Color(0, 0, 0, 0) );
if you look at the color constructor javadocs:
public Color(int r,
int g,
int b,
int a)
Creates an sRGB color with the specified red, green, blue, and alpha values in the range (0 - 255).
Parameters:
r - the red component
g - the green component
b - the blue component
a - the alpha component
you set the alpha value to 0, making it completely invisible. (alpha value is transparency) also, this second window is undecorated and does not exit on close, so you don't even know it's there at all.
what I don't get is how test1 worked at all.
side note: when I try test 1 on mac it only shows the button and all I can do is click it. the button will disappear, but the application will still be running.
This is basically a total guess, but a lot of the swing components make requests to the operating system, not commands. sort of like saying, "hey can I please be resized to 400, 400?" the OS doesn't technically have to do what you say. and I was reading How does Java handle multithreading? which says that multithreading really depends on the OS. I have a feeling it just messes up somewhere when screenSelectorUI() is called by itself, but somehow gets it right when it's inside the thread of some button.

Pressing both mouse buttons not working correctly

i have to check if i pressed left, right or both buttons on my mouse, here is a sample code:
package sandbox;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Sandbox extends JFrame {
public static void main(String[] args) {
Sandbox s = new Sandbox();
s.setVisible(true);
}
public Sandbox() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 200);
setResizable(false);
setTitle("Frame");
setLayout(null);
JButton but = new JButton("click me");
but.setBounds(0, 0, 120, 50);
but.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
if(SwingUtilities.isLeftMouseButton(e) | SwingUtilities.isRightMouseButton(e))
System.out.println("both");
else if(SwingUtilities.isLeftMouseButton(e))
System.out.println("left");
else if(SwingUtilities.isRightMouseButton(e))
System.out.println("right");
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
add(but);
}
}
i have to make it using SwingUtilities, but there is a problem if i press left or right single button it will print "both", not "left" or "right", if i used MouseEvent class it was working properly but i need it with SwingUtilities class if it's possible, thanks.
EDIT: using MouseEvent class it's working right:
if(e.getModifiersEx() == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK))
...
Don't check using OR (|) but use AND (& or better the short cut version &&) instead:
if(SwingUtilities.isLeftMouseButton(e) && SwingUtilities.isRightMouseButton(e))
...
Update:
For checking if both buttons are pressed, SwingUtilities doesn't seem to be the right tool. The isXxxxMouseButton(...) methods do the same as you do, they check the button masks, but use different masks which seem not be set when both buttons are pressed.
As an example, isRightMouseButton() is implemented as follows:
public static boolean isRightMouseButton(MouseEvent anEvent) {
return ((anEvent.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK);
}
As you can see, the implementation isn't that complext, so you might be better off to just do the mask check yourself.
mouse listene event on button
but.addMouseListener(new MouseListener() {
mouse listener event on fame.
this.addMouseListener(new MouseListener() {
Please check with '||' not '|', don't use the && because it is not possible to press both buttons at the same time
if(SwingUtilities.isLeftMouseButton(e) || SwingUtilities.isRightMouseButton(e))
You will get result
both
left
both
left
both
right

SWT remove all listener from StyledText

How do I remove all listener from a SWT StyledText if I'm missing the instances? I tried to use the StyledText.getListeners(int) method to get all the instances, being able to remove them afterwards. But it's exhausting to find all the required int values. Is this the most straightforward way? Thank you!
Here is my temporary solution:
public void removeAllListener(StyledText st) {
int[] eventTypes = { 3007, 3011, SWT.Resize, SWT.Move, SWT.Dispose,
SWT.DragDetect, 3000, SWT.FocusIn, SWT.FocusOut, SWT.Gesture,
SWT.Help, SWT.KeyUp, SWT.KeyDown, 3001, 3002, SWT.MenuDetect,
SWT.Modify, SWT.MouseDown, SWT.MouseUp, SWT.MouseDoubleClick,
SWT.MouseMove, SWT.MouseEnter, SWT.MouseExit, SWT.MouseHover,
SWT.MouseWheel, SWT.Paint, 3008, SWT.Selection, SWT.Touch,
SWT.Traverse, 3005, SWT.Verify, 3009, 3010 };
for (int eventType : eventTypes) {
Listener[] listeners = st.getListeners(eventType);
for (Listener listener : listeners) {
st.removeListener(eventType, listener);
}
}
}
I had to copy some of the values since they are part of StyledText class declared with the default modifier. So I cannot access them.
I hope, I didn't miss any int values ;)
In general, there is no mechanism to do this. However, I managed to get it working by subclassing StyledText. The new class is called StyledTextWithListeners. You can just rename it if you want ;) . However, you will have to use
styledText.addListenerByUser(int eventType, Listener listener);
to add you Listeners rather than
styledText.addListener(int eventTyle, Listener listener);
This is necessary to discriminate between Listeners added by you and those added by SWT upon creation.
To remove all listeners added by the user (you) just call
styledText.removeAllListeners();
Here is the code:
import java.util.HashMap;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
public class MiniExample {
public static void main(String[] args) {
Display display = Display.getDefault();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
StyledTextWithListeners text = new StyledTextWithListeners(shell, SWT.BORDER);
text.setText("TEXT");
text.addListenerByUser(SWT.Verify, new Listener() {
#Override
public void handleEvent(Event arg0) {
}
});
text.removeAllListeners();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
public static class StyledTextWithListeners extends StyledText
{
HashMap<Integer, Listener> listeners;
public StyledTextWithListeners(Composite parent, int style) {
super(parent, style);
}
public void addListenerByUser(int eventType, Listener listener)
{
addListener(eventType, listener);
System.out.println("Adding: " + listener.getClass().toString());
if(listeners == null)
listeners = new HashMap<Integer, Listener>();
listeners.put(eventType, listener);
}
public void removeAllListeners()
{
for(Integer type : listeners.keySet())
{
System.out.println("Removing: " + listeners.get(type).getClass().toString());
removeListener(type.intValue(), listeners.get(type));
}
listeners = new HashMap<Integer, Listener>();
}
}
}
It basically saves all the Listeners you add in a HashMap and removes them when you call removeAllListeners.
Keep in mind that I didn't take care of the case where you add a second Listener with the same eventType to the StyledText as done before. In this case, the old Listener will be replaced in the HashMap, but not removed from the StyledText. If this case can occur in your scenario, just add some code yourself.

Categories

Resources