Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[albireo-dev] Initial scrolling of Swing text fields

SWT_AWT uses the following code (in new_Frame) to set the embedded frame size:

parent.getDisplay().asyncExec(new Runnable() {
	public void run () {
		if (parent.isDisposed()) return;
		final Rectangle clientArea = parent.getClientArea();
		EventQueue.invokeLater(new Runnable () {
			public void run () {
				frame.setSize (clientArea.width, clientArea.height);
				frame.validate ();
			}
		});
	}
});

The nested asyncExec and invokeLater means that it is possible that an invokeLater during the initialization of a Swing component will be executed before the size is set.

It turns out that the caret support used by JTextComponents uses invokeLater in an attempt to wait until the JTextComponent has a valid size. It is then able to scroll the text component so that the caret shows.

Since this will not (always) work in our environment, I've added some code to "re-scroll" text components when the embedded frame is finally sized for the first time.

We may find other similar cases.

### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.63
diff -u -r1.63 SwingControl.java
--- src/org/eclipse/albireo/core/SwingControl.java	21 Apr 2008 18:52:00 -0000	1.63
+++ src/org/eclipse/albireo/core/SwingControl.java	21 Apr 2008 22:42:24 -0000
@@ -16,6 +16,8 @@
 import java.awt.Dimension;
 import java.awt.EventQueue;
 import java.awt.Frame;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -31,6 +33,7 @@
 import javax.swing.LayoutFocusTraversalPolicy;
 import javax.swing.RootPaneContainer;
 import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
 
 import org.eclipse.albireo.internal.CleanResizeListener;
 import org.eclipse.albireo.internal.ComponentDebugging;
@@ -235,6 +238,7 @@
 
         initializeFocusManagement();
         initKeystrokeManagement();
+        initFirstResizeActions();
 
         if (HIDE_SWING_POPUPS_ON_SWT_SHELL_BOUNDS_CHANGE) {
             getShell().addControlListener(shellControlListener);
@@ -1277,4 +1281,40 @@
         return consumedKeystrokes.remove(key);
     }
     
+    // ============================= Post-first resize actions =============================
+    
+    // Swing components created in createSwingComponent are not always 
+    // initialized properly because the embedded frame does not have its 
+    // bounds set early enough. This can happen when the 
+    // component tries to do initialization with an invokeLater() call. 
+    // In a normal Swing environment that would delay the initialization until 
+    // after the frame and its child components had a real size, but not so in this
+    // environment. SWT_AWT sets the frame size inside an invokeLater, which 
+    // is itself nested inside a syncExec. So the bounds can be set after any
+    // invokeLater() in called as part of createSwingComponent().
+    
+    protected void initFirstResizeActions() {
+        frame.addComponentListener(new ComponentAdapter() {
+            public void componentResized(ComponentEvent e) {
+                scrollTextFields(frame);
+                // We care about only the first resize
+                frame.removeComponentListener(this);
+            }
+        });
+    }
+
+    // Scroll all the text fields (JTextComponent) so that the caret will be visible
+    // when they are focused. 
+    protected void scrollTextFields(Component c) {
+        if (c instanceof JTextComponent) {
+            JTextComponent tc = (JTextComponent)c;
+            // This scrolls the text component to the proper place
+            tc.setCaretPosition(tc.getCaretPosition());
+        } else if (c instanceof Container) {
+            Component[] children = ((Container)c).getComponents();
+            for (int i = 0; i < children.length; i++) {
+                scrollTextFields(children[i]);
+            }
+        }
+    }
 }

Back to the top