FormLayout and FormData
FormLayout通过为小窗口部件创建四边的Form附加值(attachment)来进行工作,并且把这些Form附加值存储在布局数据中。一个附加值让一个小窗口部件指定的一边粘贴(attach)到父Composite的一个位置或者这个布局中的另一个小窗口部件上。这为布局提供了极大的便利,并且这也允许你指定布局中单个小窗口部件的放置。
MarginWidth, MarginHeight
FormLayout中的margin域类似于GridLayout中的相同域。左边和右边边距(margin)被定义成marginWidth,而顶部和底部的边距被定义成marginHeight。边距也能根据每个小窗口部件的附加值来定义。FormLayout边距在默认情况下为0。
为了设置这些边距,我们创建一个FromLayout,然后设置它的边距域。下面这段代码会在父Composite的四个边都设置5个象素的边距。
Display display = new Display ();
Shell shell = new Shell (display);
FormLayout layout= new FormLayout ();
layout.marginHeight = 5;
layout.marginWidth = 5;
shell.setLayout (layout);
FormData对象域
FormData对象用于指定FormLayout中的每一个小窗口部件怎么样放置。每一个FormData对象定义了小窗口部件四个边的附加值值。这些附加值决定在哪里定位小窗口部件的四个边。你可以用setLayoutData方法来设定一个小窗口部件的FormData对象。例如:
Button button1 = new Button(shell, SWT.PUSH);
button1.setText("B1");
button1.setLayoutData(new FormData());
但是,这段代码创建了一个没有附加值的FormData对象。在这个例子中,定义了默认的附加值值,这没有体现出FormLayout的目的和效用。默认的附加值值让小窗口部件粘贴到父Composite的左边和顶部。如果FormLayout中的每一个小窗口部件都使用了默认的附加值值,它们就会全部被重叠的放置在父Composite的左上角。
Left, Right, Top和Bottom
FormLayout中的left, right, top和bottom域分别指定了与小窗口部件的左边,右边,顶部和底部相关联的Form附加值对象。这些域被象下面的例中一样设定:
FormData formData = new FormData();
formData.top = new FormAttachment (0,60);
formData.bottom = new FormAttachment (100,-5);
formData.left = new FormAttachment (20,0);
formData.right = new FormAttachment (100,-3);
button1.setLayoutData(formData);
注意到如果多于一个小窗口部件被定义为没有任何附加值的时候,这些小窗口部件都会被放置到窗口中相同的默认位置上,并且会发生重叠。Form附加值在Form附加值对象这一节中将进行更仔细的叙述。
FormData中的width和height域用来指定小窗口部件所需的宽度和高度。如果所请求的宽度和高度与附加值设置的约束发生冲突,那么这些请求的高度和宽度就不能遵从了。虽然通过设置附加值也以决定宽度和高度值,但有些情况下你不希望为小窗口部件的所有边都定义附加值值。在这种情况下,它们就可以很有用的象下面这样设定小窗口部件的宽度和高度值:
FormData formData = new FormData(20,30);
formData.top = new FormAttachment (0,60);
formData.left = new FormAttachment (20,0);
button1.setLayoutData(formData);
如果你希望只设定宽度和高度值,你可以直接设置FromData对象的宽度和高度值:
FormData formData = new FormData ();
formData.width = 30;
formData.top = new FormAttachment (0,60);
formData.bottom = new FormAttachment (100,-5);
formData.left = new FormAttachment (20,0);
button1.setLayoutData(formData);
From附加值是一个用来定义小窗口部件的指定边的附加值的对象。不需要总是为小窗口部件的四个边都设置附加值。通常只指定一个或者多个小窗口部件的边就能完全指定它的放置。为了更适当的放置你的小窗口部件,你必须至少为FormData中left或者right之一,以及top或者bottom之一定义附加值。如果你只希望粘贴小窗口部件的左边而不是右边,那么这个小窗口部件将用它的边来进行定位,并且这个小窗口部件会采用它的正常大小(或者当设置了请求大小时,采用它的请求大小)。如果你没有贴粘左边或者右边,默认的定义会把你的小窗口部件粘贴到窗体的左边。对于顶部和底部也是采用了相同的逻辑。
存在很多种类型的附加值。第一种就是粘贴到相对于父Composite的一个位置。通过定义一个100以内的百分值就能实现.
FormData formData = new FormData();
formData.top = new FormAttachment (50,0);
button1.setLayoutData(formData);
这里设置Button的顶部到相对于父Composite(一个Shell)高度的50%的位置,偏移量为0。当这个Shell进行缩放的时候,Button的顶部会始终在50%的位置.
如果我们选择设定一个偏移值,Button的上部就会被设置为父Composite的50%加上或者减去为偏移量设置的象素数。
我们也能定义不使用百分比定义按钮的位置,例如:
FormData formData = new FormData();
formData.top = new FormAttachment (30,70,10);
button1.setLayoutData(formData);
如果父Composite的高度被定义为70个单位,这里设置了Button的顶部在父Composite顶部以下30个单位,再加上10个象素的地方。
相对于父Composite进行粘贴
第二种类型的附加值是相对于父Composite的边缘进行粘贴。这与相对于一个位置进行粘贴的实现方法差不多,但是这个位置值只能是0%或者100%。当处于垂直样式的时候,0这个位置被定义为父Composite的顶部,但处于水平样式的时候被定义为左边。右边和底部边缘被定义为100。因此,如果我们要粘贴一个小窗口部件到父Composite的右边,我们只需要简单的创建一个附加值,然后设置它的位置值为100:
FormData formData = new FormData();
formData.right = new FormAttachment (100,-5);
button1.setLayoutData(formData);
这里把Button的右边粘贴到了父Composite(一个Shell)的右边缘,并有一个5个象素的偏移值。注意,附加值是往一个方向增加的。如果你要让一个小窗口部件向下或者所右偏移,偏移值必须是正的。如果要小窗口部件向上或者向左偏移,这个偏移值必须是负的。现在当这个Shell被缩放时,这个Button就总是偏离右边缘5个象素.
相对于另一个小窗口部件进行粘贴
第三种类型的附加值是相对于父Composite中的另一个控件进行粘贴。小窗口部件的边可以被粘贴到另一个控件的相邻边(默认),粘贴到另一个控件的相对边,或者小窗口部件可以相对于另一个控件居中,这些都认使用或者不使用偏移值。
相对于另一个控件进行粘贴最常用的方法是粘贴到它的相邻边。例如下面的代码:
FormData formData = new FormData();
formData.top = new FormAttachment (20,0);
button1.setLayoutData(formData); FormData formData2 = new FormData();
formData2.top = new FormAttachment (button1,10);
button2.setLayoutData(formData2);
把按钮2的顶部粘贴到了按钮1的底部,这是因为按钮1的底部和按钮2的顶部是相邻的。
注意到当窗口被缩放时,按钮1会移动让它的顶部总是定位在Shell的20%的位置,而按钮2也是会移动让它的顶部总是在按钮1的相邻边(底部)以下10个象素的位置。
虽然默认的情况下是相对于一个控件的相邻边进行粘贴,FromAttachment也能被创建用来相对一个控件的相对边进行粘贴。当要排列小窗口部件的时候这就非常的有用了。在这种情况下,你可以用TOP, BOTTOM, LEFT或者RIGHT排列(alignment)创建相对于另一个控件的附加值,例如:
formData2.top = new FormAttachment (button1,0,SWT.TOP);
在接下来的例子中,按钮1的顶部边被定位在Shell的20%的地方。按钮2使用了TOP排列,它的顶部边和按钮1的顶部边对齐。这意味着按钮2的顶部也被定位在这个Shell的20%的位置。注意到当指定了顶部附加值,只有小窗口部件的垂直放置会被定义。仍然需要为按钮2设置左边附加值以得Button不会发生重叠。
FormData formData = new FormData(50,50);
formData.top = new FormAttachment (20,0);
button1.setLayoutData(formData); FormData formData2 = new FormData();
FormData2.left = new FormAttachment (button1,5);
formData2.top = new FormAttachment (button1,0,SWT.TOP);
button2.setLayoutData(formData2);
最后一个相对于另一个控件进行粘贴的方法是相对于另一个控件居中。当两个控件有不同的大小的时候,这就显得很有用了。在这种情况下,你用CENTER排列(aligmnet)创建相对于另一个控件的附加值,例如:
formData.top = new FormAttachment (button1,0,SWT.CENTER);
这会放置这个小窗口部件的顶部在一个允许这个小窗口部件相对于另一个控件居中的位置上,并且有一个值为0的偏移值。只设定顶部,或者底部,或者它们两者为居中附加值会导致相同的结果。这个小窗口部件的顶部边不会居中,但是整个小窗口部件会居中,所以这只需要指定一次。这里有一个例子:
FormData formData1 = new FormData (50,50);
button1.setLayoutData(formData1) FormData formData2 = new FormData ();
formData2.left = new FormAttachment (button1,5);
formData2.top = new FormAttachment (button1,0,SWT.CENTER);
button2.setLayoutData (formData2);
使用不同类型的附加值允许布局以不同的方法来定义。FormLayout解决了一些FillLayout,RowLayout或者GridLayout不能解决的问题,让它成为定义布局很有用的类。
到目前为止,所有使用FormLayout的例子都只是围绕着一两个Button,为了展示FormAttachment是如何工作 的。下面,我们会举一个有更多的Button的例子来展示使用附加值如何安排布局。我们会从画一张描绘我们要创建的附加值的基本草图开始。
FormData data1 = new FormData();
data1.left = new FormAttachment (0,5);
data1.right = new FormAttachment (25,0);
button1.setLayoutData(data1); FormData data2 = new FormData();
data2.left = new FormAttachment (button1,5);
data2.right = new FormAttachment (100,-5);
button2.setLayoutData(data2); FormData data3 = new FormData(60,60);
data3.top = new FormAttachment (button1,5);
data3.left = new FormAttachment (50,-30);
data3.right = new FormAttachment (50,30);
button3.setLayoutData(data3); FormData data4 = new FormData();
data4.top = new FormAttachment (button3,5);
data4.bottom = new FormAttachment (100,-5);
data4.left = new FormAttachment (25,0);
button4.setLayoutData(data4); FormData data5 = new FormData();
data5.bottom = new FormAttachment (100,-5);
data5.left = new FormAttachment (button4,5);
button5.setLayoutData(data5);
在这个例子中,因为没有为按钮1和按钮2定义顶部附加值,它们粘贴到了布局的顶部上。钮3在左边和右边使用了百分比和偏移值而在布局中居中。按钮4和按钮5粘贴到了布局的底部,并有5个象素的偏移量。
当我们进行缩放时,附加值就更显得明显了。按钮1的左边和右边都相对进行粘贴,所以当窗口被缩放时它也增大了。注意到它的右边总是在窗口的25%的位置。相同的缩放效果也被应用到按钮2上,因为它的两边也都相对进行了粘贴。左边相对按钮1进行了粘贴,所以它总是会在窗口的25%加上5个象素的位置。按钮3水平地保持在窗口的中间。按钮4的顶部和底部都相对进行粘贴,因此当窗口被缩放的时候它垂直地增大了,但是它只相对于左边进行了粘贴而对右边则没有,因此水平方向上它没有增大。按钮5不会增大或者缩小,但它的左边会保持在离按钮4有5个象素远,离窗口底部5个象素远的地方。
一个复杂的FormLayout的例子
为了举例说明FormLayout如何能够用于更复杂的布局,我们用FormLayout来重做上面为GridLayout举例的“狗狗展示条目”的例子。这段代码创建一个一样的布局,但是用不同的观念来实现它。
我们会从修改为网格布局所作的设计草图开始。我们会画出如何做,而不仅仅画出我们希望做成什么样。这人例子会用到所有的附加值类型。
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*; public class ComplexFormLayoutExample {
static Display display;
static Shell shell;
static Image dogImage;
static Text dogNameText;
static Combo dogBreedCombo;
static Canvas dogPhoto;
static List categories;
static Text nameText;
static Text phoneText; public static void main(String[] args){
display = new Display();
shell = new Shell(display);
FormLayout layout= new FormLayout();
layout.marginWidth = 5;
layout.marginHeight = 5;
shell.setLayout(layout);
shell.setText("Dog Show Entry"); Group ownerInfo = new Group(shell, SWT.NONE);
ownerInfo.setText("Owner Info");
FormLayout ownerLayout = new FormLayout();
ownerLayout.marginWidth = 5;
ownerLayout.marginHeight = 5;
ownerInfo.setLayout(ownerLayout); Label dogName = new Label(shell, SWT.NONE);
dogName.setText("Dog's Name:");
dogNameText = new Text(shell, SWT.SINGLE | SWT.BORDER);
Label dogBreed = new Label(shell, SWT.NONE);
dogBreed.setText("Breed:");
dogBreedCombo = new Combo(shell, SWT.NONE);
dogBreedCombo.setItems(new String [] {"Collie", "Pitbull", "Poodle", "Scottie"});
Label photo = new Label(shell, SWT.NONE);
photo.setText("Photo:");
dogPhoto = new Canvas(shell, SWT.BORDER);
Button browse = new Button(shell, SWT.PUSH);
browse.setText("Browse...");
Button delete = new Button(shell, SWT.PUSH);
delete.setText("Delete");
Label cats = new Label (shell, SWT.NONE);
cats.setText("Categories");
categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
categories.setItems(new String [] {
"Best of Breed", "Prettiest Female", "Handsomest Male",
"Best Dressed", "Fluffiest Ears", "Most Colors",
"Best Performer", "Loudest Bark", "Best Behaved",
"Prettiest Eyes", "Most Hair", "Longest Tail",
"Cutest Trick"});
Button enter = new Button(shell, SWT.PUSH);
enter.setText("Enter"); FormData data = new FormData();
data.top = new FormAttachment (dogNameText,0,SWT.CENTER);
dogName.setLayoutData(data); data = new FormData();
data.left = new FormAttachment (dogName,5);
data.right = new FormAttachment (100,0);
dogNameText.setLayoutData(data); data = new FormData();
data.top = new FormAttachment (dogBreedCombo,0,SWT.CENTER);
dogBreed.setLayoutData(data); data = new FormData();
data.top = new FormAttachment (dogNameText,5);
data.left = new FormAttachment (dogNameText,0,SWT.LEFT);
data.right = new FormAttachment (categories,-5);
dogBreedCombo.setLayoutData(data); data = new FormData(80,80);
data.top = new FormAttachment (dogBreedCombo,5);
data.left = new FormAttachment (dogNameText,0,SWT.LEFT);
data.right = new FormAttachment (categories,-5);
data.bottom = new FormAttachment (ownerInfo,-5);
dogPhoto.setLayoutData(data);
dogPhoto.addPaintListener(new PaintListener() {
public void paintControl(final PaintEvent event) {
if (dogImage != null) {
event.gc.drawImage(dogImage, 0, 0);
}
}
}); data = new FormData();
data.top = new FormAttachment (dogPhoto,0,SWT.TOP);
photo.setLayoutData(data); data = new FormData();
data.top = new FormAttachment (photo,5);
data.right = new FormAttachment (dogPhoto, -5);
browse.setLayoutData(data);
browse.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
String fileName = new FileDialog(shell).open();
if (fileName != null) {
dogImage = new Image(display, fileName);
}
}
}); data = new FormData();
data.left = new FormAttachment (browse,0,SWT.LEFT);
data.top = new FormAttachment (browse,5);
data.right = new FormAttachment (dogPhoto, -5);
delete.setLayoutData(data);
delete.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
if (dogImage != null) {
dogImage.dispose();
dogImage = null;
dogPhoto.redraw();
}
}
}); data = new FormData(90,140);
data.top = new FormAttachment (dogPhoto,0,SWT.TOP);
data.right = new FormAttachment (100,0);
data.bottom = new FormAttachment (enter,-5);
categories.setLayoutData(data); data = new FormData();
data.bottom = new FormAttachment (categories,-5);
data.left = new FormAttachment (categories,0,SWT.CENTER);
cats.setLayoutData(data); data = new FormData();
data.right = new FormAttachment (100,0);
data.bottom = new FormAttachment (100,0);
enter.setLayoutData(data);
enter.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
System.out.println("\nDog Name: " + dogNameText.getText());
System.out.println("Dog Breed: " + dogBreedCombo.getText());
System.out.println("Owner Name: " + nameText.getText());
System.out.println("Owner Phone: " + phoneText.getText());
System.out.println("Categories:");
String cats[] = categories.getSelection();
for (int i = 0; i < cats.length; i++) {
System.out.println("\t" + cats[i]);
}
}
}); data = new FormData();
data.bottom = new FormAttachment (enter,-5);
data.left = new FormAttachment (0,0);
data.right = new FormAttachment (categories,-5);
ownerInfo.setLayoutData(data); Label name = new Label(ownerInfo, SWT.NULL);
name.setText("Name:");
Label phone = new Label(ownerInfo, SWT.PUSH);
phone.setText("Phone:");
nameText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
phoneText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER); data = new FormData();
data.top = new FormAttachment (nameText,0,SWT.CENTER);
name.setLayoutData(data); data = new FormData();
data.top = new FormAttachment (phoneText,0,SWT.CENTER);
phone.setLayoutData(data); data = new FormData();
data.left = new FormAttachment (phone,5);
data.right = new FormAttachment (100,0);
nameText.setLayoutData(data); data = new FormData();
data.left = new FormAttachment (nameText,0,SWT.LEFT);
data.right = new FormAttachment (100,0);
data.top = new FormAttachment (55,0);
phoneText.setLayoutData(data); shell.pack();
shell.open(); while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
有时候,你可能需要编写你自己的布局类。有可能你的布局的需求很复杂。或者你有些地方你可能需要相同的外观,而你希望改进代码的重用率。或者你希望扩大领域知识来创建一个很有效率的布局类。不管原因是什么,在编写一个新的类之前,有几件事情是你要考虑的:
• 这个布局能够用GridLayout或者FormLayout,以及可能是一些嵌套布局来实现吗?
• 希望达到的效果可以更容易的用一个缩放监听器来实现吗?
• 你定义了一个通用的布局算法还是只是布置了小窗口部件?
首先,我们会先来看看布局是怎么样工作的,然后我们再创建一个新的布局类。另一个编写你自己的而已的例子可以在“用SWT创建你自己的小窗口部件”(Creating Your Own Widgets Using SWT)中的“复合小窗口部件示例”(Compound Widget Example)一节中找到,它显示了如何用一个缩放监听器或者一个新布局类达到相同的外观。
Layout是所有布局的超类。它只有两个方法computeSize和layout。这个类的定义如下:
public abstract class Layout {
protected abstract Point computeSize(Composite composite, int widthHint, int heightHint, boolean flushCache);
protected abstract void layout(Composite composite, boolean flushCache);
}
既然一个布局控制着小窗口部件在一个Composite中的大小和放置,Composite中也有一些方法可以和布局一起使用。
public void setLayout(Layout layout);
public Layout getLayout();
一个应用程序可以强制一个布局重新计算子组件的大小,并通过调用父Composite的layout()方法重新定位这些子组件。
public void layout(boolean changed);
public void layout();
// calls layout(true);
你需要在你改变了任何子组件,可能导致子组件的大小和位置发生改变的时候做这件事情,比如改变了子组件的字体,改变了子组件的文本或者图片,增加了新的子组件,或者为子组件增加了子组件。(如果子组件可以适应这个变化,布局可能不会成功—例如,改变一个可滚动的多行的Text的字体或者文本)。既然这些改变都是通过编程来实现的,它们不会触发事件。从而,父构件不会知道这些变化,必须通过layout方法来告许它。这个策略导致了闪动,这是因为应用程序可能作了好几个改变然后才告诉父构件重新布局,并且子组件只被重画一次而不是每次改变都重画一次。如果没有调用layout()并改变是在shell打开后发生的,那么子组件可能不会被正确的放置直到shell由于某种原因进行了缩放。注意shell.open()导致一个布局过程的发生。
Composite的computeSize方法计算Composite的合适大小,这是它由这个布局决定的客户区(client)的大小加上它的修剪(trim)。
public Point computeSize(int widthHint, int heightHint, boolean changed);
public Point computeSize(int widthHint, int heightHint);
// calls computeSize(widthHint, heightHint, true);
Composite的clientArea是包含所有的子组件的矩形区。一个布局在客户区中放置子组件。
public Rectangle getClientArea ();
Composite的trim(修剪)是客户区外的区域。对于一些Composite,修剪的大小是零。修剪可以通过传递客户区的尺寸给computeTrim计算出来。
public Rectangle computeTrim (int x, int y, int width, int height);
调用Composite的pack方法将把它缩放到它的合适大小。
public void pack(boolean changed);
// calls setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT, changed));
public void pack();
// calls pack(true);
缓存可以改进性能,但它也可能是有欺骗性的。你可以选择完全不缓存 — 事实上,最好不要试力用缓存,直到你的代码已经稳定。当你考虑缓存什么时,确保你没有缓存任何小窗口部件状态,例如一个标签的文本,或者一个列表的项的数目。
如果在你的应用程序中你有一些垂直导向的Composite小窗口部件,你可能会选择编写ColumnLayout。我们将会展示一个简单的布局类版本,它把Composite子组件放置到一个单列中。这个类有固定的修剪和间距。子组件被赋予相同的宽度,但它们能有自己自然的高度。(注意,在*2.0*中,RowLayout已经被扩展为有ColumnLayout的功能,如果它的类型被设为SWT.VERTICAL的话。正因为如此,这个例子只是作为一个例子。事实上,如果你现在需要把小窗口部件放在一列中,你可以用RowLayout来实现。)
这段ColumnLayout类的例子就在下面。注意,我们缓存了小窗口部件子组件的宽度,子组件的高度和(加上了间距),而且这些值被用来计算大小和放置子组件。如果flushCache是true,它们会被重新计算。
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*; public class ColumnLayout extends Layout {
// fixed margin and spacing
public static final int MARGIN = 4;
public static final int SPACING = 2; // cache
Point [] sizes;
int maxWidth, totalHeight; protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Control children[] = composite.getChildren();
if (flushCache || sizes == null || sizes.length != children.length) {
initialize(children);
}
int width = wHint, height = hHint;
if (wHint == SWT.DEFAULT) width = maxWidth;
if (hHint == SWT.DEFAULT) height = totalHeight;
return new Point(width + 2 * MARGIN, height + 2 * MARGIN);
} protected void layout(Composite composite, boolean flushCache) {
Control children[] = composite.getChildren();
if (flushCache || sizes == null || sizes.length != children.length) {
initialize(children);
}
Rectangle rect = composite.getClientArea();
int x = MARGIN, y = MARGIN;
int width = Math.max(rect.width - 2 * MARGIN, maxWidth);
for (int i = 0; i < children.length; i++) {
int height = sizes[i].y;
children[i].setBounds(x, y, width, height);
y += height + SPACING;
}
} void initialize(Control children[]) {
maxWidth = 0;
totalHeight = 0;
sizes = new Point [children.length];
for (int i = 0; i < children.length; i++) {
sizes[i] = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
maxWidth = Math.max(maxWidth, sizes[i].x);
totalHeight += sizes[i].y;
}
totalHeight += (children.length - 1) * SPACING;
}
}
这里有一些简单的测试代码来测试ColumnLayout。Grow和shrink按钮展示了在改变了其中一个子组件的宽度后调用Shell的layout()方法强制一个重新布局的过程。调用layout()和调用layout(true)是一样的,它告诉ColumnLayout在设定子组件的边界的时候冲掉它的缓存。Shell在放置好子组件后也调用pack()方法。这强制让Shell采用新的大小。
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.events.*; public class ColumnLayoutTest {
static Shell shell;
static Button button3; public static void main(String[] args) {
Display display = new Display();
shell = new Shell(display);
shell.setLayout(new ColumnLayout());
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Very Wide Button 2");
(button3 = new Button(shell, SWT.PUSH)).setText("Button 3");
Button grow = new Button(shell, SWT.PUSH);
grow.setText("Grow Button 3");
grow.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
button3.setText("Extreemely Wide Button 3");
shell.layout();
shell.pack();
}
});
Button shrink = new Button(shell, SWT.PUSH);
shrink.setText("Shrink Button 3");
shrink.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
button3.setText("Button 3");
shell.layout();
shell.pack();
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
}
}
如果我们运行这段测试代码,窗口会像左图看起来那样。按下Grow Button 3按钮会导致窗口如右图所示。用鼠标缩放窗口的大小也能使按钮变宽(或者变窄)但是它们不会变高。
如果你正在编写自己的小窗口部件,就像“用SWT创建你自己的小窗口部件”(Creating Your Own Widgets Using SWT)中描述的那样,并且你子类化了Composite,那么你的实现要几点要考虑:
• 如果在你的新Composite中提供了修剪(trimming),确保你重载了computeTrim和getClientArea。
• 绝对不要重载layout(),但是你可以重载layout(boolean)。
• 重载setLayout让它不做任何事。
• 重载layout(boolean)让它调用你的布局代码。
• 重载computeSize让它正确的计算出你的Composite的大小。
FormLayout and FormData的更多相关文章
- SWT中的布局之-----FormLayout(表格式布局)
表格式(FormLayout类) 表格式布局管理器,通过创建组件各个边的距离来布局组件,和GridLayout一样强大. 用GridLayout与FormLayout都可以实现相同的界面效果,但有时使 ...
- 三种上传文件不刷新页面的方法讨论:iframe/FormData/FileReader
发请求有两种方式,一种是用ajax,另一种是用form提交,默认的form提交如果不做处理的话,会使页面重定向.以一个简单的demo做说明: html如下所示,请求的路径action为"up ...
- form表单中enctype="multipart/form-data"的作用
在我们使用php导入和导出excel表格的时候经常会见到 enctype="multipart/form-data",哪他的作用是什么呢? ENCTYPE="multip ...
- 通过Ajax使用FormData对象无刷新上传文件
写在前面:本文说的这个方案有浏览器兼容性问题:所有主流浏览器的较新版本已经支持这个对象了,比如Chrome 7+.Firefox 4+.IE 10+.Opera 12+.Safari 5+,对兼容性比 ...
- multipart/form-data和application/x-www-form-urlencoded的区别
在Form元素的语法中,EncType表明提交数据的格式 用 Enctype 属性指定将数据回发到服务器时浏览器使用的编码类型. 下边是说明: application/x-www-form-urle ...
- H5 FormData对象的使用
XMLHttpRequest Level2 添加了一个新的接口--FormData .[ 主要用于发送表单数据,但也可以独立使用于传输键控数据.与普通的Ajax相比,它能异步上传二进制文件 ] 利用F ...
- form表单编码方式设置为multipart/form-data,后台参数出现乱码情况
一般在上传图片过程中,form中的编码方式一般采用multipart/form-data方式编码,但是后台这取参数时,可能会出现乱码情况:这里后台要采用转换编码方式: 页面: 后台:获取表单元素时,
- jquery 通过ajax FormData 对象上传附件
之前上传附件都是用插件,或者用form表单体检(这个是很久以前的方式了),今天突发奇想,自己来实现附件上传,具体实现如下 html: <div> 流程图: <input id=& ...
- html5 formData上传 针对app端
function uploadFile() { if ((document.getElementById("file").files[0].size / 1024).toFixed ...
随机推荐
- Java类库的源码
Java类库中的类,包括System.String.Scanner.Math.Random等:这些类也是用Java编写的. Java类库中包含数千个文件,其中的很多文件都包含数千行代码:因为Java类 ...
- ubuntu16.04基本设置
1. ubuntu16.04开启ssh https://jingyan.baidu.com/article/f54ae2fc6f9eef1e93b8497a.html 2. windows 远程桌面连 ...
- EXPLAIN说明
列名 类型 解释 id SELECT语句的ID编号,优先执行编号较大的查询,如果编号相同,则从上向下执行 select_type SIMPLE 一条没有UNION或子查询部分的SELECT语句 P ...
- Google play中下载apk
在 Google play中下载apk:先在Google play中找到该apk,再去找APK downloader(https://www.allfreeapk.com/),Google play的 ...
- XTOJ 1267:Highway(树的直径)***
http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1267 题意:给出一棵树,每条树边有权值,现在要修建n-1条边,边的权值为边 ...
- HDU 4283:You Are the One(区间DP)
http://acm.hdu.edu.cn/showproblem.php?pid=4283 题意:有n个数字,不操作的情况下从左到右按顺序输出,但是可以先让前面的数字进栈,让后面的数字输出,然后栈里 ...
- MySQL错误:The user specified as a definer (XXX@XXX) does not exist (1449错误)最简解决方案
背景:从同事处通过备份和还原备份方法导入mysql数据库,导入成功后启动项目,发现出现以下错误:The user specified as a definer (XXX@XXX) does not e ...
- LSI 9211-8I阵列卡IR模式Update为IT模式操作步骤!
以下是DOS系统环境下操作(也可以在windows.linux环境下,只要找到对应的tool就可以)相对应的tool官网可以下载 链接:https://www.broadcom.com/support ...
- 那些有实力进入 BAT 的本科生,都做对了什么事?
作者:黄小斜 文章来源:微信公众号[黄小斜] 最近这段时间,我们部门来了几个年纪轻轻的本科生,最小的比我们小五岁左,这对于我来说还是比较有冲击力的. 想想我也是九0出头的老腊肉了,想当年我上大学的时候 ...
- 跟我学SpringCloud | 第十二篇:Spring Cloud Gateway初探
SpringCloud系列教程 | 第十二篇:Spring Cloud Gateway初探 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如 ...