将透明复合材料放置在 SWT 中的其他复合材料上

问题描述 投票:0回答:2

我正在寻找一种在应用程序中的某些复合材料上添加叠加层的方法。覆盖层将包含一个带有文本“无可用数据”的标签。需要显示底层组合,但用户无法执行任何操作。我的应用程序在一个屏幕中包含不同的复合部件,因此我需要一种仅将覆盖层放置在其中一个复合部件上的方法。有没有办法在SWT中实现这个?

java swt transparent composite
2个回答
10
投票

一个可能的解决方案是在您想要覆盖的

Shell
上放置一个没有任何装饰的半透明
Composite

棘手的部分是更新覆盖层

Shell
以持续匹配
Composite
及其父级的大小、位置和可见性(因为它们也可能影响子级边界和可见性)。

所以我决定尝试开设一个课程

Overlay
来做到这一点;它可用于覆盖任何
Control
,并使用控制和绘制侦听器来跟踪和匹配底层
Control
。这些侦听器还附加到
Control
的整个父级层次结构中。

您可以使用相应的方法设置

Overlay
上的颜色、透明度和文本。

我做了一些简单的测试,看起来工作正常,但我不能保证任何事情。您可能想尝试一下。

使用它的简单示例:

public class OverlayTest {

    public static void main(String[] args) {

        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout(SWT.VERTICAL));
        shell.setSize(250, 250);

        // create the composite
        Composite composite = new Composite(shell, SWT.NONE);
        composite.setLayout(new FillLayout(SWT.VERTICAL));

        // add stuff to the composite
        for (int i = 0; i < 5; i++) {
            new Text(composite, SWT.BORDER).setText("Text " + i);
        }

        // create the overlay over the composite
        Overlay overlay = new Overlay(composite);
        overlay.setText("No data available");

        // create the button to show/hide the overlay
        Button button = new Button(shell, SWT.PUSH);
        button.setText("Show/hide overlay");
        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent arg0) {
                // if the overlay is showing we hide it, otherwise we show it
                if (overlay.isShowing()) {
                    overlay.remove();
                }
                else {
                    overlay.show();
                }
            }
        });

        shell.open();
        while (shell != null && !shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

}

还有

Overlay
班:

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.Label;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Shell;

/**
 *  A customizable overlay over a control.
 *  
 *  @author Loris Securo
 */
public class Overlay {

    private List<Composite> parents;
    private Control objectToOverlay;
    private Shell overlay;
    private Label label;
    private ControlListener controlListener;
    private DisposeListener disposeListener;
    private PaintListener paintListener;
    private boolean showing;
    private boolean hasClientArea;
    private Scrollable scrollableToOverlay;

    public Overlay(Control objectToOverlay) {

        Objects.requireNonNull(objectToOverlay);

        this.objectToOverlay = objectToOverlay;

        // if the object to overlay is an instance of Scrollable (e.g. Shell) then it has 
        // the getClientArea method, which is preferable over Control.getSize
        if (objectToOverlay instanceof Scrollable) {
            hasClientArea = true;
            scrollableToOverlay = (Scrollable) objectToOverlay;
        }
        else {
            hasClientArea = false;
            scrollableToOverlay = null;
        }

        // save the parents of the object, so we can add/remove listeners to them
        parents = new ArrayList<Composite>();
        Composite parent = objectToOverlay.getParent();
        while (parent != null) {
            parents.add(parent);
            parent = parent.getParent();
        }

        // listener to track position and size changes in order to modify the overlay bounds as well
        controlListener = new ControlListener() {
            @Override
            public void controlMoved(ControlEvent e) {
                reposition();
            }

            @Override
            public void controlResized(ControlEvent e) {
                reposition();
            }
        };

        // listener to track paint changes, like when the object or its parents become not visible (for example changing tab in a TabFolder)
        paintListener = new PaintListener() {
            @Override
            public void paintControl(PaintEvent arg0) {
                reposition();
            }
        };

        // listener to remove the overlay if the object to overlay is disposed
        disposeListener = new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
                remove();
            }
        };

        // create the overlay shell
        overlay = new Shell(objectToOverlay.getShell(), SWT.NO_TRIM);

        // default values of the overlay
        overlay.setBackground(objectToOverlay.getDisplay().getSystemColor(SWT.COLOR_GRAY));
        overlay.setAlpha(200);

        // so the label can inherit the background of the overlay
        overlay.setBackgroundMode(SWT.INHERIT_DEFAULT);

        // label to display a text
        // style WRAP so if it is too long the text get wrapped
        label = new Label(overlay, SWT.WRAP);

        // to center the label
        overlay.setLayout(new GridLayout());
        label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));

        showing = false;
        overlay.open();
        overlay.setVisible(showing);
    }

    public void show() {

        // if it's already visible we just exit
        if (showing) {
            return;
        }

        // set the overlay position over the object
        reposition();

        // show the overlay
        overlay.setVisible(true);

        // add listeners to the object to overlay
        objectToOverlay.addControlListener(controlListener);
        objectToOverlay.addDisposeListener(disposeListener);
        objectToOverlay.addPaintListener(paintListener);

        // add listeners also to the parents because if they change then also the visibility of our object could change
        for (Composite parent : parents) {
            parent.addControlListener(controlListener);
            parent.addPaintListener(paintListener);
        }

        showing = true;
    }

    public void remove() {

        // if it's already not visible we just exit
        if (!showing) {
            return;
        }

        // remove the listeners
        if (!objectToOverlay.isDisposed()) {
            objectToOverlay.removeControlListener(controlListener);
            objectToOverlay.removeDisposeListener(disposeListener);
            objectToOverlay.removePaintListener(paintListener);
        }

        // remove the parents listeners
        for (Composite parent : parents) {
            if (!parent.isDisposed()) {
                parent.removeControlListener(controlListener);
                parent.removePaintListener(paintListener);
            }
        }

        // remove the overlay shell
        if (!overlay.isDisposed()) {
            overlay.setVisible(false);
        }

        showing = false;
    }

    public void setBackground(Color background) {
        overlay.setBackground(background);
    }

    public Color getBackground() {
        return overlay.getBackground();
    }

    public void setAlpha(int alpha) {
        overlay.setAlpha(alpha);
    }

    public int getAlpha() {
        return overlay.getAlpha();
    }

    public boolean isShowing() {
        return showing;
    }

    public void setText(String text) {
        label.setText(text);

        // to adjust the label size accordingly
        overlay.layout();
    }

    public String getText() {
        return label.getText();
    }

    private void reposition() {

        // if the object is not visible, we hide the overlay and exit
        if (!objectToOverlay.isVisible()) {
            overlay.setBounds(new Rectangle(0, 0, 0, 0));
            return;
        }

        // if the object is visible we need to find the visible region in order to correctly place the overlay

        // get the display bounds of the object to overlay
        Point objectToOverlayDisplayLocation = objectToOverlay.toDisplay(0, 0);

        Point objectToOverlaySize;

        // if it has a client area, we prefer that instead of the size 
        if (hasClientArea) {
            Rectangle clientArea = scrollableToOverlay.getClientArea();
            objectToOverlaySize = new Point(clientArea.width, clientArea.height);
        }
        else {
            objectToOverlaySize = objectToOverlay.getSize();
        }

        Rectangle objectToOverlayBounds = new Rectangle(objectToOverlayDisplayLocation.x, objectToOverlayDisplayLocation.y, objectToOverlaySize.x,
                objectToOverlaySize.y);

        Rectangle intersection = objectToOverlayBounds;

        // intersect the bounds of the object with its parents bounds so we get only the visible bounds
        for (Composite parent : parents) {

            Rectangle parentClientArea = parent.getClientArea();
            Point parentLocation = parent.toDisplay(parentClientArea.x, parentClientArea.y);
            Rectangle parentBounds = new Rectangle(parentLocation.x, parentLocation.y, parentClientArea.width, parentClientArea.height);

            intersection = intersection.intersection(parentBounds);

            // if intersection has no size then it would be a waste of time to continue
            if (intersection.width == 0 || intersection.height == 0) {
                break;
            }
        }

        overlay.setBounds(intersection);
    }

}

0
投票
  1. 在父级上将布局设置为 null

  2. 在父级上添加一个样式为 SWT.TRANSPARENT 的新 Composite,位于要绘制的复合体之前

  3. 手动将复合材料的边界设置为同一区域,如果可以更改,请使用调整大小侦听器。

© www.soinside.com 2019 - 2024. All rights reserved.