【问题标题】:SWT Drawing a "transparent" rectangle on a shellSWT 在外壳上绘制“透明”矩形
【发布时间】:2012-03-06 14:58:02
【问题描述】:

我想创建一个“选择区域”工具。 这个工具应该允许用鼠标在屏幕上绘制一个矩形区域。

我使用全屏、半透明、变暗的 swt Shell 作为背景,在其上绘制一个白色矩形来表示所选区域。

我的问题是我没有找到刷新矩形区域的有效方法。 直到现在我都用redraw的方法,但是视觉效果很丑,甚至以为我试图只重绘他需要的区域:

    public ManualScreenAreaSelector(final Display display) {
        shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP);
        shell.setBounds(display.getClientArea());
        // shell.setFullScreen(true);
        shell.setAlpha(180);
        shell.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
        shell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
    }

    @Override
    public void mouseMove(final MouseEvent e) {
        if (editionMode) {
            // retrieve the rectangular area corresponding to mouse selection
            final Rectangle r = makeRectangleFromSelection(clickCoordinates, new Point(e.x, e.y));
            // make the ugly 'tint' effect
            shell.redraw();

            GC gc = new GC(shell);
            gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE));
            gc.setAlpha(150);

            gc.fillRectangle(r.x, r.y, r.width, r.height);

            gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
            gc.fillRectangle(0, 0, r.x, r.y);
            gc.fillRectangle(0, 1080 - r.y, r.x, 1080 - r.y);
            gc.dispose();

            lastX = e.x;
            lastY = e.y;
        }
    }

    @Override
    public void mouseDown(final MouseEvent e) {
        // Right click = reset selection
        if (e.button == 3) {
            shell.redraw();
            selectedArea = null;
            if (editionMode) {
                editionMode = false;
                shell.removeMouseMoveListener(ManualScreenAreaSelector.this);
            }
        } else if (e.button == 1) {
            // left-click enter edition mode
            // Reset previous selection
            selectedArea = null;
            editionMode = true;
            clickCoordinates = new Point(e.x, e.y);
            lastX = e.x;
            lastY = e.y;
            shell.addMouseMoveListener(ManualScreenAreaSelector.this);
        }
    }

    @Override
    public void mouseUp(final MouseEvent e) {
        // left click, only if edition was set
        if ((e.button == 1) && editionMode) {
            editionMode = false;
            shell.removeMouseMoveListener(ManualScreenAreaSelector.this);
            selectedArea = makeRectangleFromSelection(clickCoordinates, new Point(e.x, e.y));
            shell.dispose();
        }
    }

所以我想知道SWT中是否存在更有效的解决方案,而不必使用重绘方法。


编辑 我使用了 3 张图片来进行选择:

  • 首先是屏幕截图(截图)
  • 第二个是屏幕图像 + alpha 混合的深色矩形
  • 第三个是缓冲区,我在该缓冲区上绘制 alpha 混合图像 + 从屏幕截图图像复制的矩形。

性能可以接受,因为只有一个 alpha 混合操作(用于第二张图像)。

只剩下一个问题,当我第一次使用外壳的图形控件绘制外壳时,没有将 alpha 混合图像用作外壳背景,发送鼠标事件时其他一切正常:

public ManualScreenAreaSelector(final Display display) {

    screenWidth = display.getClientArea().width;
    screenHeight = display.getClientArea().height;
    // create a new Image of the screen
    backGround = new Image(display, display.getBounds());
    GC gc = new GC(display);
    gc.copyArea(backGround, 0, 0);
    gc.dispose();

    // Copy background image and add alpha blended effect
    aplhaBackGround = new Image(backGround.getDevice(), backGround.getImageData());
    GC alphaGC = new GC(aplhaBackGround);
    alphaGC.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
    alphaGC.setAlpha(200);
    alphaGC.fillRectangle(0, 0, screenWidth, screenHeight);
    alphaGC.dispose();

    // create the shell
    shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_BACKGROUND);
    shell.setBounds(display.getClientArea());

    // get shell graphics control
    shellGraphics = new GC(shell);
    // set the shell image to screen image <-- does nothing
    shellGraphics.drawImage(aplhaBackGround, 0, 0);

    // Image for the shell
    bufferImage = new Image(shell.getDisplay(), shell.getBounds());

    shell.print(shellGraphics);
}
public void mouseMove(final MouseEvent e) {
    if (editionMode) {
        // Get selected area
        final Rectangle selectedArea = makeRectangleFromSelection(clickCoordinates, new Point(
                e.x, e.y));
        // Copy alpha blended background into the buffer
        GC gc1 = new GC(aplhaBackGround);
        gc1.copyArea(bufferImage, 0, 0);
        gc1.dispose();
        // Paint "normal" background over selected area
        GC gc2 = new GC(bufferImage);
        gc2.drawImage(backGround, selectedArea.x, selectedArea.y, selectedArea.width,
                selectedArea.height, selectedArea.x, selectedArea.y, selectedArea.width,
                selectedArea.height);

        // draw the painted image on the shell
        shellGraphics.drawImage(bufferImage, 0, 0);
        gc2.dispose();
    }
}

【问题讨论】:

    标签: java graphics swt


    【解决方案1】:

    试试这个方法:

    • 代替shell.redraw();,调用shell.print(gc) 一次并将GC 附加到图像缓冲区。这会给你一个外壳的图像。

    • 获取 SWT 或 jogl 的 OpenGL 扩展。将图像放在背景中并为选择创建一个 3D 矩形。使用 OpenGL 进行 alpha 操作和合成。

    原因是 SWT 中的 alpha 操作很慢,通常需要使用 CPU 来完成。您的显卡可以每秒执行数百次相同的操作而不会费力。

    【讨论】:

    • 我更喜欢使用 print() 方法而不是 OpenGL 扩展或 jogl。我会试试 shell.print(gc)。
    • 您可以尝试使用图像来加速重绘,但我的直觉是 SWT alpha 实现对于全屏操作来说太慢了。
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 2011-07-11
    • 2016-03-12
    • 2016-05-25
    • 1970-01-01
    • 2021-04-10
    • 2016-10-05
    • 1970-01-01
    相关资源
    最近更新 更多