Eclipse SWT: Can't scroll over Text when vertical scrolling is enabled - java

I have a Text inside a Group, which is inside a Composite and that resides inside a ScrolledComposite. All Elements are inside an EditorPart.
ScrolledComposite mySc
|- Composite myComposite
|- Group myGroup
|- Text myText
I can scroll (using the mouse wheel) over all Elements in the EditorPart, but when the cursor is over the Text area, the scrolling stops.
I want to scroll inside the Text only when it has keyboard focus.
Instantiation of the Text myText:
myText = new Text(myGroup, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
Without SWT.V_SCROLL it works, but then I don't have scroll bars and the possibility to scroll in the Text.
I thought I could maybe use forceFocus() on the parent in case the Text has no Focus Control:
myText.addListener(SWT.MouseWheel, new Listener() {
#Override
public void handleEvent(Event event) {
if (!commandText.isFocusControl()) {
System.out.println("no focus");
Control wheelControl = myText.getParent();
Point cursorPos = wheelControl.toControl(event.display.getCursorLocation());
event.x = cursorPos.x;
event.y = cursorPos.y;
event.widget = wheelControl;
wheelControl.forceFocus();
wheelControl.notifyListeners(SWT.MouseWheel, event);
} else {
System.out.println("Focus control");
}
}
});
But it doesn't work. No change at all. It only prints "Focus control" and "no focus" correctly.
EDIT:
Here is a minimal working example:
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
public class MyEditor extends EditorPart {
private Text myText;
private boolean dirty = false;
public MyEditor() {
super();
}
#Override
public void init(IEditorSite site, IEditorInput input) {
setSite(site);
setInput(input);
}
#Override
public void doSave(IProgressMonitor monitor) {
return;
}
#Override
public void doSaveAs() {
return;
}
#Override
public boolean isDirty() {
return dirty;
}
#Override
public boolean isSaveAsAllowed() {
return false;
}
#Override
public void createPartControl(Composite parent) {
parent.setLayout(new FillLayout());
ScrolledComposite mySc = new ScrolledComposite(parent, SWT.V_SCROLL);
Composite myComposite = new Composite(mySc, SWT.BORDER);
myComposite.setLayout(new GridLayout(1, false));
// Set the child as the scrolled content of the ScrolledComposite
mySc.setContent(myComposite);
// Expand both horizontally and vertically
mySc.setExpandHorizontal(true);
mySc.setExpandVertical(true);
Group myGroup = new Group(myComposite, SWT.NONE);
myGroup.setText("Hello or something");
myGroup.setLayout(new GridLayout(1, false));
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.verticalIndent = 10;
myGroup.setLayoutData(gd);
Label aLabel = new Label(myGroup, SWT.NONE);
aLabel.setText("You can write here: ");
myText = new Text(myGroup, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
myText.setText("Some Default Text");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 300;
gd.horizontalIndent = 10;
myText.setLayoutData(gd);
myText.addListener(SWT.MouseWheel, new Listener() {
#Override
public void handleEvent(Event event) {
if (!myText.isFocusControl() ) {
System.out.println("no focus");
Control wheelControl = myText.getParent();
Point cursorPos = wheelControl.toControl(event.display.getCursorLocation());
event.x = cursorPos.x;
event.y = cursorPos.y;
event.widget = wheelControl;
wheelControl.forceFocus();
wheelControl.notifyListeners(SWT.MouseWheel, event);
myText.setCapture(false);
} else {
System.out.println("Focus control");
myText.setCapture(true);
}
}
});
mySc.setMinSize(myComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
}
#Override
public void setFocus() {
// TODO Auto-generated method stub
}
}

The solution I found was to disable the vertical scrollbar. This also disables scrolling by mouse wheel. Also use SWT's addMouseWheelListener() and mouseScrolled() methods instead of addListener(). Than just scroll the ScrolledComposite by using its getOrigin() method.
myText.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseScrolled(MouseEvent e) {
if (!myText.isFocusControl() ) {
myText.getVerticalBar().setEnabled(false);
if (e.count == 3) {
mySc.setOrigin(sc.getOrigin().x, mySc.getOrigin().y - 30);
} else if (e.count == -3) {
mySc.setOrigin(sc.getOrigin().x, mySc.getOrigin().y + 30);
}
} else {
myText.getVerticalBar().setEnabled(true);
}
}
});
count always returns 3 or -3, depending on the scroll direction. The value of 30 for scrolling up/down is good for me, might be more or less for other purposes. I didn't check the behavior on a Windows machine yet.

Related

Can't update label inside keyPressed()

I just started to learn Java. I have already looked Swing and at the moment I'm trying to do something with SWT.
But I have the next problem. Key Listener that I added for Text field is working, but inside this listener I can't change for example my label.
I have seen a few demos they worked, but I don't see any differences.
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class FirstClass {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("First Application");
GridLayout layout = new GridLayout(2, false);
shell.setLayout(layout);
Text word = new Text(shell,SWT.SINGLE | SWT.BORDER | SWT.FILL);
GridData wordGrDt = new GridData();
wordGrDt.heightHint = 130;
wordGrDt.minimumHeight = 130;
wordGrDt.horizontalAlignment = SWT.FILL;
wordGrDt.verticalAlignment = SWT.FILL;
wordGrDt.horizontalSpan = 2;
word.setLayoutData(wordGrDt);
GridData statusGrDt = new GridData();
statusGrDt.grabExcessHorizontalSpace = true;
statusGrDt.horizontalSpan = 1;
statusGrDt.horizontalAlignment = SWT.LEFT_TO_RIGHT;
Label status = new Label(shell, SWT.PUSH);
status.setEnabled(true);
status.setText("");
status.setLayoutData(statusGrDt);
GridData checkGrDt = new GridData();
checkGrDt.widthHint = 150;
checkGrDt.horizontalSpan = 1;
checkGrDt.horizontalAlignment = SWT.RIGHT_TO_LEFT;
Button check = new Button(shell, SWT.PUSH);
check.setText("Check");
check.setLayoutData(checkGrDt);
word.addKeyListener(new org.eclipse.swt.events.KeyAdapter() {
public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
if (e.keyCode == SWT.CR) {
System.out.println("worked!!!");
status.setText("ababahalamaha");
}
}
});
shell.setMinimumSize(400, 300);
shell.open();
shell.pack();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Add a layout() call to the parent of the Label:
word.addKeyListener(new org.eclipse.swt.events.KeyAdapter() {
public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
if (e.keyCode == SWT.CR) {
System.out.println("worked!!!");
status.setText("ababahalamaha");
status.getParent().layout();
}
}
});
The label originally has a width of 0, as it doesn't contain any text. When you add content, the parent has to know to re-layout its children.
As a note:
Please check which style you use with which widget. A Label does not know what to do with the style SWT.PUSH for example.

Record SWT MouseEnter/Exit events on a Composite with a FillLayout

I have a Composite on which I'd like to track SWT.MouseEnter and SWT.MouseExit events. The Composite, however, has another Composite inside it which consumes the entirety of the region, due to a FillLayout.
Some sample code to illustrate what it is I'm doing:
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
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 EventListenerTest {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
// Set up the outer Composite
Composite outerComp = new Composite(shell, SWT.BORDER);
FillLayout fl = new FillLayout();
// fl.marginHeight = 15;
// fl.marginWidth = 15;
outerComp.setLayout(fl);
// Set up a nested Composite
Composite innerComp = new Composite(outerComp, SWT.BORDER);
// Set a listener on the outer Composite for a MouseEnter event
outerComp.addListener(SWT.MouseEnter, new Listener() {
#Override
public void handleEvent(Event e) {
System.out.println("Mouse ENTER event");
}
});
// Similarly, for a MouseExit event
outerComp.addListener(SWT.MouseExit, new Listener() {
#Override
public void handleEvent(Event e) {
Composite comp = (Composite) e.widget;
// Don't report if positioned over a child control
for (Control child : comp.getChildren()) {
if (!child.getBounds().contains(new Point(e.x, e.y)))
System.out.println("Mouse EXIT event");
}
}
});
outerComp.pack();
outerComp.layout();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
return;
}
}
Unfortunately, due to the fact that innerComp fills the entirety of its parent, outerComp never does record the mouse enter/exit events unless I expose a little bit of its "area".
I'm able to expose a little bit of outerComp by creating some margins on its FillLayout (commented out lines 21-22), but this is really not ideal. For aesthetic reasons, I can't have huge margins on outerComp, and reducing the margin size to 1 doesn't consistently detect the mouse events if I'm moving my mouse over the composite quickly (I have to move my mouse very slowly over the 1px margin for it to trigger).
From a design perspective on my project, I'm not actually supposed to know what outerComp contains (or how deep the controls nest), so setting the event listeners on its children also isn't ideal.
Is there any way I can still track these mouse events on the outerComp if it has a FillLayout consuming all of its area?
What you can do is add a filter to the Display and in the handler, check if the Widget that is the source of the Event is a child of your Composite.
This should give you an idea of how to do it:
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell();
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(2, true));
final Composite left = new Composite(shell, SWT.NONE);
Composite right = new Composite(shell, SWT.NONE);
left.setLayout(new GridLayout(3, true));
right.setLayout(new GridLayout(3, true));
for (int i = 0; i < 6; i++)
{
new Label(left, SWT.NONE).setText("label-" + i);
new Label(right, SWT.NONE).setText("label-" + i);
}
display.addFilter(SWT.MouseMove, new Listener()
{
#Override
public void handleEvent(Event e)
{
if (isChildOrSelf(e.widget, left))
System.out.println(e);
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
private static boolean isChildOrSelf(Widget child, Composite parent)
{
if(child == parent)
return true;
for (Control c : parent.getChildren())
{
if (c instanceof Composite)
{
boolean result = isChildOrSelf(child, (Composite)c);
if (result)
return true;
}
else if (c == child)
return true;
}
return false;
}

Overriding Cut/Copy/Paste in SWT Text control

What is the correct way to override the cut(), copy(), and paste() methods of the Text control? What triggers the execution of these methods?
I have created an example application with a custom class that overrides these methods. Unfortunately, nothing seems to execute these overridden methods, including the act of using Ctrl+X / Ctrl+C / Ctrl+V or selecting cut/copy/paste from the context menu.
Custom Text Class:
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
public class TextCopyable extends Text{
public TextCopyable(Composite parent, int style) {
super(parent, style);
}
#Override
public void checkSubclass() {
}
#Override
public void cut() {
System.out.println("Cut!");
}
#Override
public void copy() {
System.out.println("Copy!");
}
#Override
public void paste() {
System.out.println("Paste!");
}
}
Test Shell:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.layout.GridData;
public class CopyPasteTest extends Shell {
private TextCopyable text;
public static void main(String args[]) {
try {
Display display = Display.getDefault();
CopyPasteTest shell = new CopyPasteTest(display);
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public CopyPasteTest(Display display) {
super(display, SWT.SHELL_TRIM);
createContents();
}
protected void createContents() {
setText("SWT Application");
setSize(450, 300);
GridLayout gridLayout = new GridLayout();
setLayout(gridLayout);
text = new TextCopyable(this, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
}
My expectation was that the copy() method would be called any time that I use the Ctrl+C command to copy text from the textbox. However, the methods do not trigger at all. Is my assumption faulty?

how to catch event of change focus of row in tableViewer?

I created a tableViewer.
The tableViewer could be update.
The update of the table is in inline mode meaning in change of row Ii will update the table.
The problem that if I changed the focus to different view ( outline , tasks... ) or to different windows I want to catch the event that the focus of the table was changed.( the row still mark and this is the reason that the selectionChanegd event is not trigger )
This is the event that for the selectionChanged
gridController.addSelectionChangedListener(new ISelectionChangedListener() {
.. do update
}
The event is not trigger when I changed the focus to different window,view.
Do you know on different way to catch the change of the focus of the table ?
Try this :
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class TestCase {
private static List<String> model = new ArrayList<String>();
private static TableViewer viewer;
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
// viewer = new TableViewer(shell, SWT.SINGLE | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
viewer = new TableViewer(shell, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setLinesVisible(true);
viewer.setUseHashlookup(true);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.setLabelProvider(new LabelProvider());
model.add("element2");
model.add("element1");
model.add("element0");
viewer.setInput(model);
viewer.setSelection(new StructuredSelection(model.get(1)));
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(SelectionChangedEvent event) {
System.out.println("selection changed");
}
});
addContent();
shell.setSize(400, 400);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
private static void addContent() {
Display.getCurrent().timerExec(2000, new Runnable() {
#Override
public void run() {
model.add(0, "element" + model.size());
viewer.refresh();
addContent();
}
});
}
}

Show Page loading no browser until page is fully loaded

I want to hide the content of html page until its fully loaded. The idea is I want to get the content of html page do some processing and set the content back again. For doing so I am able to retrieve the text and do some processing on it. But the problem is , till the time processing is not complete, I want to hide the original html page and instead wanna show some dummy page.
I want to hover a shell on browser window and remove it when the loading is complete. I tried to hide the browser widget but that is not working as per the expectations.
Here is the snippet for the same.
package browserapp;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.extended.LocationEvent;
import org.eclipse.swt.browser.extended.LocationListener;
import org.eclipse.swt.browser.extended.ProgressEvent;
import org.eclipse.swt.browser.extended.ProgressListener;
import org.eclipse.swt.browser.extended.Browser;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class MyBrowser_1 {
/**
* Runs the application
*/
Display display = new Display();
protected boolean done;
public void run() {
final Shell shell = new Shell(display);
shell.setText("Simple Browser");
createContents(shell);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
/**
* Creates the main window's contents
*
* #param shell the main window
*/
private void createContents(final Shell shell) {
shell.setLayout(new FormLayout());
// Create the composite to hold the buttons and text field
Composite controls = new Composite(shell, SWT.NONE);
FormData data = new FormData();
data.top = new FormAttachment(0, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
controls.setLayoutData(data);
// Create the web browser
final Browser browser = new Browser(shell, SWT.NONE);
browser.addLocationListener(new LocationListener() {
#Override
public void changing(LocationEvent event) {
// TODO Auto-generated method stub
//browser.setVisible(false);
Image image = new Image(display,
"C:\\Documents and Settings\\My
Documents\\Pictures\\loadingAnimation.gif");
///shell.setBackgroundImage(image);
}
#Override
public void changed(LocationEvent event) {
// TODO Auto-generated method stub
}
});
browser.addProgressListener(new ProgressListener()
{
public void completed(ProgressEvent event)
{
}
public void changed(ProgressEvent event)
{
int progressWorked=0;
if (event.total == 0)
return;
done = (event.current == event.total);
int percentProgress = event.current * 100 / event.total;
System.out.println("Loading...");
if (done)
{
progressWorked = 0;
System.out.println("Loading completed...");
//browser.setVisible(true);
//maskPage(browser, maskedMap);
} else if (progressWorked == 0)
{
progressWorked = percentProgress;
} else
{
progressWorked = event.current;
}
}
});
data = new FormData();
data.top = new FormAttachment(controls);
data.bottom = new FormAttachment(100, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
browser.setLayoutData(data);
// Create the controls and wire them to the browser
controls.setLayout(new GridLayout(7, false));
// Create the back button
Button button = new Button(controls, SWT.PUSH);
button.setText("Back");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
browser.back();
}
});
// Create the forward button
button = new Button(controls, SWT.PUSH);
button.setText("Forward");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
browser.forward();
}
});
// Create the refresh button
button = new Button(controls, SWT.PUSH);
button.setText("Refresh");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
browser.refresh();
}
});
// Create the stop button
button = new Button(controls, SWT.PUSH);
button.setText("Stop");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
browser.stop();
}
});
// Create the address entry field and set focus to it
final Text url = new Text(controls, SWT.BORDER);
url.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
url.setText("https://netbanking.hdfcbank.com/netbanking/");
url.setFocus();
// Create the go button
button = new Button(controls, SWT.PUSH);
button.setText("Go");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
browser.setUrl(url.getText());
}
});
GridData gridData2 = new GridData(SWT.FILL, SWT.FILL, true, false);
Label status = new Label(controls, SWT.BORDER);
status.setLayoutData(gridData2);
// Allow users to hit enter to go to the typed URL
shell.setDefaultButton(button);
}
/**
* The application entry point
*
* #param args the command line arguments
*/
public static void main(String[] args) {
MyBrowser_1 browser=new MyBrowser_1();
browser.run();
}
}

Categories