恒定宽度SashForm

时间:2013-06-21 03:06:48

标签: java swt

我的应用程序有一个有两个孩子的SashForm。我希望在调整窗口大小时左边的孩子保持相同的大小。我想要Eclipse使用Package Explorer和主编辑器做同样的事情。调整窗口大小时,只有文本编辑器会更改大小。但是,包装资源管理器仍然可以通过窗扇调整大小。

我尝试使用以下

sashForm.addControlListener(new ControlAdapter() {
    @Override
    public void controlResized(ControlEvent e) {
        int width = sashForm.getClientArea().width;
        int[] weights = sashForm.getWeights();
        weights[1] = width - weights[0];
        sashForm.setWeights(weights);
    }
});

问题是左侧尺寸的宽度要么缩小到0还是要扩大太多。看起来在调用它之前更新了权重。

如果我将权重[0]设置为等于某个常数,则按我想要的那样。

3 个答案:

答案 0 :(得分:2)

我设法得到一个运行示例,应该让你知道如何解决你的问题。问题是,SashForm使用权重而不是像素。因此,您必须根据父级大小计算左侧孩子必须占用的百分比,并将其余孩子分配给正确的孩子。

在我的代码示例中,您可以指定左子项的宽度并为右侧子项设置最小大小,以便SashForm始终显示两者。

private static final int MIN_WIDTH_LEFT = 100;
private static final int MIN_WIDTH_RIGHT = 50;

public static void main(String[] args)
{
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new FillLayout());

    final SashForm form = new SashForm(shell, SWT.HORIZONTAL);

    Button button = new Button(form, SWT.PUSH);
    button.setText("Left");

    Button buttonR = new Button(form, SWT.PUSH);
    buttonR.setText("Right");

    form.setWeights(new int[] {1, 2});

    shell.addListener(SWT.Resize, new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            int width = shell.getClientArea().width;
            int[] weights = form.getWeights();

            if(width >= MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT)
            {
                weights[0] = 1000000 * MIN_WIDTH_LEFT / width;
                weights[1] = 1000000 - weights[0];
            }
            else
            {
                weights[0] = 1000000 * MIN_WIDTH_LEFT / (MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT);
                weights[1] = 1000000 * MIN_WIDTH_RIGHT / (MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT);
            }

            System.out.println(width + " " + Arrays.toString(weights));

            form.setWeights(weights);
        }
    });

    shell.pack();

    shell.setSize(600, 400);
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

这就是它的样子:

启动:

enter image description here

调整大小后:

enter image description here

当减小窗口大小直到它太小而不能显示最小尺寸时:

enter image description here

正如您在本案例中所看到的,忽略了左子项的最小大小,但仍然可以显示两个孩子。

答案 1 :(得分:2)

这是我能想到的最佳解决方案。

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
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 Main {
private static int leftWidth, oldWeight;

public static void main(String[] args) {
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new FillLayout());
    shell.setSize(600, 400);

    final SashForm form = new SashForm(shell, SWT.HORIZONTAL);

    final Button button = new Button(form, SWT.PUSH);
    button.setText("Left");

    button.addListener(SWT.Resize, new Listener() {
        @Override
        public void handleEvent(Event arg0) {
            int[] weights = form.getWeights();
            // oldWeights is used to distinguish between a window resize and
            // a sash move
            if (oldWeight != weights[0]) {
                System.out.println("Weights changed!");
                oldWeight = weights[0];
                leftWidth = (int) Math.round((double) form.getClientArea().width
                        * (double) weights[0]
                        / (double) (weights[0] + weights[1]));
            }
        }
    });

    Button buttonR = new Button(form, SWT.PUSH);
    buttonR.setText("Right");

    form.setWeights(new int[] { 200, 800 });
    leftWidth = 200;

    form.addListener(SWT.Resize, new Listener() {
        @Override
        public void handleEvent(Event arg0) {
            int width = form.getClientArea().width;
            int[] weights = form.getWeights();

            double perChange = (double) leftWidth / (double) width;

            weights[0] = (int) (perChange * 1000.0);
            weights[1] = 1000 - weights[0];

            // oldWeights must be set before form.setWeights
            oldWeight = weights[0];
            form.setWeights(weights);
        }
    });

    shell.open();
    while (!shell.isDisposed()) {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

由于四舍五入的问题,当窗口调整大小时窗扇跳转大约1px,但它似乎做了我想要的。

这是一个非常hacky的解决方案,我想知道是否有更好的解决方案。如果你让窗口小于左按钮,它也会崩溃,但这很容易修复。

答案 2 :(得分:0)

必须重写SashForm才能获得此行为。 <script src="https://code.jquery.com/jquery-1.12.1.min.js"></script> <table class="table"> <tbody> <tr class="parent" id="2479"> <td><span class="btn btn-default">expand</span></td> </tr> <tr class="child-2479"> <td>row 1</td> <td>row 1</td> <td>row 1</td> <td>row 1</td> <td>row 1</td> <td>row 1</td> </tr> <tr class="parent" id="2800"> <td><span class="btn btn-default">expand</span></td> </tr> <tr class="child-2800"> <td>row 2</td> <td>row 2</td> <td>row 2</td> <td>row 2</td> <td>row 2</td> <td>row 2</td> </tr> </tbody> </table>是旧行为; new SashForm(Composite parent, int style)使用以像素为单位指定的宽度/高度。

未使用SashForm的两个以上复合子项进行测试,如果在使用新行为时没有new SashForm(Composite parent, int style, false),则会出现奇怪行为,但不会破坏SashForm的现有用法

e.g:

setLength

第一个按钮默认为250像素,第二个按钮

SashForm.java:

public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final SashForm form = new SashForm(shell, SWT.HORIZONTAL);
Button button = new Button(form, SWT.PUSH);
button.setText("Left");
Button buttonR = new Button(form, SWT.PUSH);
buttonR.setText("Right");
form.setLengths(new int[] { 250, 25 });
shell.pack();
shell.setSize(600, 400);
shell.open();
while (!shell.isDisposed())
{
    if (!display.readAndDispatch())
        display.sleep();
}
display.dispose();
}

SashFormData.java:

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;

public class SashForm extends Composite {

    /**
    * The width of all sashes in the form.
    */
    public int SASH_WIDTH = 3;

    int sashStyle;
    final private boolean weighted;
    Sash[] sashes = new Sash[0];
    // Remember background and foreground
    // colors to determine whether to set
    // sashes to the default color (null) or
    // a specific color
    Color background = null;
    Color foreground = null;
    Control[] controls = new Control[0];
    Control maxControl = null;
    Listener sashListener;
    static final int DRAG_MINIMUM = 20;

public SashForm(Composite parent, int style) {
    super(parent, checkStyle(style));
    super.setLayout(new SashFormLayout());
    sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
    if ((style & SWT.BORDER) != 0) sashStyle |= SWT.BORDER;
    if ((style & SWT.SMOOTH) != 0) sashStyle |= SWT.SMOOTH;
    sashListener = new Listener() {
        public void handleEvent(Event e) {
            onDragSash(e);
        }
    };
    weighted = true;
}
public SashForm(Composite parent, int style, boolean weighted) {
    super(parent, checkStyle(style));
    super.setLayout(new SashFormLayout());
    sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
    if ((style & SWT.BORDER) != 0) sashStyle |= SWT.BORDER;
    if ((style & SWT.SMOOTH) != 0) sashStyle |= SWT.SMOOTH;
    sashListener = new Listener() {
        public void handleEvent(Event e) {
            onDragSash(e);
        }
    };
    this.weighted = weighted;
}
static int checkStyle (int style) {
    int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
    return style & mask;
}
Sash createSash() {
    Sash sash = new Sash(this, sashStyle);
    sash.setBackground(background);
    sash.setForeground(foreground);
    sash.setToolTipText(getToolTipText());
    sash.addListener(SWT.Selection, sashListener);
    return sash;
}

@Override
public int getOrientation() {
    //checkWidget();
    return (sashStyle & SWT.VERTICAL) != 0 ? SWT.HORIZONTAL : SWT.VERTICAL;
}
/**
 * Returns the width of the sashes when the controls in the SashForm are 
 * laid out.
 * 
 * @return the width of the sashes
 * 
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @since 3.4
 */
public int getSashWidth() {
    checkWidget();
    return SASH_WIDTH;
}
@Override
public int getStyle() {
    int style = super.getStyle();
    style |= getOrientation() == SWT.VERTICAL ? SWT.VERTICAL : SWT.HORIZONTAL;
    if ((sashStyle & SWT.SMOOTH) != 0) style |= SWT.SMOOTH;
    return style;
}
/**
 * Answer the control that currently is maximized in the SashForm.  
 * This value may be null.
 * 
 * @return the control that currently is maximized or null
 */
public Control getMaximizedControl(){
    //checkWidget();
    return this.maxControl;
}

public int[] getWeights() {
    checkWidget();
    Control[] cArray = getControls(false);
    int[] ratios = new int[cArray.length];
    for (int i = 0; i < cArray.length; i++) {
        Object data = cArray[i].getLayoutData();
        if (data != null && data instanceof SashFormData) {
            ratios[i] = (int)(((SashFormData)data).weight * 1000 >> 16);
        } else {
            ratios[i] = 200;
        }
    }
    return ratios;
}
Control[] getControls(boolean onlyVisible) {
    Control[] children = getChildren();
    Control[] result = new Control[0];
    for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Sash) continue;
        if (onlyVisible && !children[i].getVisible()) continue;

        Control[] newResult = new Control[result.length + 1];
        System.arraycopy(result, 0, newResult, 0, result.length);
        newResult[result.length] = children[i];
        result = newResult;
    }
    return result;
}
boolean getWeighted() {
    return weighted;
}
void onDragSash(Event event) {
    Sash sash = (Sash)event.widget;
    int sashIndex = -1;
    for (int i= 0; i < sashes.length; i++) {
        if (sashes[i] == sash) {
            sashIndex = i;
            break;
        }
    }
    if (sashIndex == -1) return;

    Control c1 = controls[sashIndex];
    Control c2 = controls[sashIndex + 1];
    Rectangle b1 = c1.getBounds();
    Rectangle b2 = c2.getBounds();

    Rectangle sashBounds = sash.getBounds();
    Rectangle area = getClientArea();
    boolean correction = false;
    if (getOrientation() == SWT.HORIZONTAL) {
        correction = b1.width < DRAG_MINIMUM || b2.width < DRAG_MINIMUM;
        int totalWidth = b2.x + b2.width - b1.x; 
        int shift = event.x - sashBounds.x;
        b1.width += shift;
        b2.x += shift;
        b2.width -= shift;
        if (b1.width < DRAG_MINIMUM) {
            b1.width = DRAG_MINIMUM;
            b2.x = b1.x + b1.width + sashBounds.width;
            b2.width = totalWidth - b2.x;
            event.x = b1.x + b1.width;
            event.doit = false;
        }
        if (b2.width < DRAG_MINIMUM) {
            b1.width = totalWidth - DRAG_MINIMUM - sashBounds.width;
            b2.x = b1.x + b1.width + sashBounds.width;
            b2.width = DRAG_MINIMUM;
            event.x = b1.x + b1.width;
            event.doit = false;
        }
        Object data1 = c1.getLayoutData();
        if (data1 == null || !(data1 instanceof SashFormData)) {
            data1 = new SashFormData();
            c1.setLayoutData(data1);
        }
        Object data2 = c2.getLayoutData();
        if (data2 == null || !(data2 instanceof SashFormData)) {
            data2 = new SashFormData();
            c2.setLayoutData(data2);
        }
        ((SashFormData)data1).weight = (((long)b1.width << 16) + area.width - 1) / area.width;
        ((SashFormData)data1).length = b1.width;
        ((SashFormData)data2).weight = (((long)b2.width << 16) + area.width - 1) / area.width;
        ((SashFormData)data2).length = b2.width;
    } else {
        correction = b1.height < DRAG_MINIMUM || b2.height < DRAG_MINIMUM;
        int totalHeight = b2.y + b2.height - b1.y;
        int shift = event.y - sashBounds.y;
        b1.height += shift;
        b2.y += shift;
        b2.height -= shift;
        if (b1.height < DRAG_MINIMUM) {
            b1.height = DRAG_MINIMUM;
            b2.y = b1.y + b1.height + sashBounds.height;
            b2.height = totalHeight - b2.y;
            event.y = b1.y + b1.height;
            event.doit = false;
        }
        if (b2.height < DRAG_MINIMUM) {
            b1.height = totalHeight - DRAG_MINIMUM - sashBounds.height;
            b2.y = b1.y + b1.height + sashBounds.height;
            b2.height = DRAG_MINIMUM;
            event.y = b1.y + b1.height;
            event.doit = false;
        }
        Object data1 = c1.getLayoutData();
        if (data1 == null || !(data1 instanceof SashFormData)) {
            data1 = new SashFormData();
            c1.setLayoutData(data1);
        }
        Object data2 = c2.getLayoutData();
        if (data2 == null || !(data2 instanceof SashFormData)) {
            data2 = new SashFormData();
            c2.setLayoutData(data2);
        }
        ((SashFormData)data1).weight = (((long)b1.height << 16) + area.height - 1) / area.height;
        ((SashFormData)data2).weight = (((long)b2.height << 16) + area.height - 1) / area.height;
    }
    if (correction || (event.doit && event.detail != SWT.DRAG)) {
        c1.setBounds(b1);
        sash.setBounds(event.x, event.y, event.width, event.height);
        c2.setBounds(b2);
    }
}

@Override
public void setOrientation(int orientation) {
    checkWidget();
    if (orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT) {
        super.setOrientation(orientation);
        return;
    }
    if (getOrientation() == orientation) return;
    if (orientation != SWT.HORIZONTAL && orientation != SWT.VERTICAL) {
        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
    }
    sashStyle &= ~(SWT.HORIZONTAL | SWT.VERTICAL);
    sashStyle |= orientation == SWT.VERTICAL ? SWT.HORIZONTAL : SWT.VERTICAL;
    for (int i = 0; i < sashes.length; i++) {
        sashes[i].dispose();
        sashes[i] = createSash();
    }
    layout(false);
}
@Override
public void setBackground (Color color) {
    super.setBackground(color);
    background = color;
    for (int i = 0; i < sashes.length; i++) {
        sashes[i].setBackground(background);
    }
}
@Override
public void setForeground (Color color) {
    super.setForeground(color);
    foreground = color;
    for (int i = 0; i < sashes.length; i++) {
        sashes[i].setForeground(foreground);
    }
}

@Override
public void setLayout (Layout layout) {
    checkWidget();
    return;
}

public void setMaximizedControl(Control control){
    checkWidget();
    if (control == null) {
        if (maxControl != null) {
            this.maxControl = null;
            layout(false);
            for (int i= 0; i < sashes.length; i++){
                sashes[i].setVisible(true);
            }
        }
        return;
    }

    for (int i= 0; i < sashes.length; i++){
        sashes[i].setVisible(false);
    }
    maxControl = control;
    layout(false);
}

public void setSashWidth(int width) {
    checkWidget();
    if (SASH_WIDTH == width) return;
    SASH_WIDTH = width;
    layout(false);
}
@Override
public void setToolTipText(String string) {
    super.setToolTipText(string);
    for (int i = 0; i < sashes.length; i++) {
        sashes[i].setToolTipText(string);
    }
}

public void setWeights(int[] weights) {
    checkWidget();
    Control[] cArray = getControls(false);
    if (weights == null || weights.length != cArray.length) {
        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
    }

    int total = 0;
    for (int i = 0; i < weights.length; i++) {
        if (weights[i] < 0) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        total += weights[i];
    }
    if (total == 0) {
        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
    }
    for (int i = 0; i < cArray.length; i++) {
        Object data = cArray[i].getLayoutData();
        if (data == null || !(data instanceof SashFormData)) {
            data = new SashFormData();
            cArray[i].setLayoutData(data);
        }
        ((SashFormData)data).weight = (((long)weights[i] << 16) + total - 1) / total;
    }

    layout(false);
}

public void setLengths(int[] lengths) {
    checkWidget();
    Control[] cArray = getControls(false);
    if (lengths == null || lengths.length != cArray.length) {
        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
    }

    int total = 0;
    for (int i = 0; i < lengths.length; i++) {
        if (lengths[i] < 0) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        total += lengths[i];
    }
    if (total == 0) {
        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
    }
    for (int i = 0; i < cArray.length; i++) {
        Object data = cArray[i].getLayoutData();
        if (data == null || !(data instanceof SashFormData)) {
            data = new SashFormData();
            cArray[i].setLayoutData(data);
        }
        ((SashFormData)data).length = lengths[i];
    }

    layout(false);
}
}

SashFormLayout.java:

class SashFormData {

    long weight;
    int length;

String getName () {
    String string = getClass ().getName ();
    int index = string.lastIndexOf ('.');
    if (index == -1) return string;
    return string.substring (index + 1, string.length ());
}

@Override
public String toString () {
    return getName()+" {length="+length+", weight="+weight+"}"; //$NON-NLS-2$
}
}