【问题标题】:How to properly update a transparent swing overlay?如何正确更新透明的摆动覆盖?
【发布时间】:2017-02-25 07:15:41
【问题描述】:

我使用了基于答案的透明点击覆盖(使用 jna 启用点击) https://stackoverflow.com/a/28772306/1093872。 然而,实际可见的叠加层总是落后一步,即。当在组件上调用 repaint() 时,将显示应在上一次更新中显示的更新。

起初我怀疑是因为线程不同导致内存不一致问题。但我也尝试了使用SwingWorkersure-to-be-correct 方法,但仍然遇到同样的问题。

AWTUtilities.setWindowOpaque(w, false); 似乎以某种方式导致了问题,因为在我将其注释掉或将其设置为 true 后,问题就消失了,但不幸的是窗口也不透明(显然)。

我怀疑问题可能与双缓冲有关(仅在下一次绘制之前绘制后才交换缓冲区),但我真的不知道。我还尝试在组件上调用setDoubleBuffered(false)setDoubleBuffered(true),但这并没有改变任何东西。

我也意识到问题与 jna 部分无关,因为删除它后,问题仍然完全相同。

请注意,索引打印与绘图同时发生,因此我知道paintComponent 会及时调用,但可见更新仅在下一次调用时发生。

关于可能是什么原因以及如何解决此问题的任何想法?

import com.sun.awt.AWTUtilities;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;

import javax.swing.*;
import java.awt.*;

public class OverlayUpdateTest {

    private static MyJComponent myJComponent;

    public static void main(String[] args) {
        setupOverlayWindow();

        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                myJComponent.increaseIndex();
                myJComponent.repaint();

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private static void setupOverlayWindow() {
        Window w = new Window(null);

        myJComponent = new MyJComponent();
        w.add(myJComponent);
        w.pack();
        w.setLocationRelativeTo(null);
        w.setVisible(true);
        w.setAlwaysOnTop(true);
        /**
         * This sets the background of the window to be transparent.
         */
        AWTUtilities.setWindowOpaque(w, false);
        setTransparent(w);
    }

    private static void setTransparent(Component w) {
        WinDef.HWND hwnd = getHWnd(w);
        int wl = User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
        wl = wl | WinUser.WS_EX_LAYERED | WinUser.WS_EX_TRANSPARENT;
        User32.INSTANCE.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, wl);
    }

    /**
     * Get the window handle from the OS
     */
    private static WinDef.HWND getHWnd(Component w) {
        WinDef.HWND hwnd = new WinDef.HWND();
        hwnd.setPointer(Native.getComponentPointer(w));
        return hwnd;
    }

    private static class MyJComponent extends JComponent {
        private int index = 0;

        /**
         * This will draw a black cross on screen.
         */
        protected void paintComponent(Graphics g) {
            g.setColor(Color.BLACK);
            g.fillRect(0, getHeight() / 2 - 10, getWidth(), 20);
            g.fillRect(getWidth() / 2 - 10, 0, 20, getHeight());
            g.setColor(Color.RED);
            g.drawString("i: " + index, 10, getFont().getSize() + 10);
            System.out.println("i: " + index);
        }

        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

        void increaseIndex() {
            index++;
        }
    }
}

【问题讨论】:

    标签: java swing overlay swingworker


    【解决方案1】:

    经过多次尝试和错误,我找到了一个可行的解决方案......


    Window w = new Window(null); 更改为Window w = new JWindow(); 解决了这个问题。我不知道为什么,但我很高兴。

    【讨论】:

      猜你喜欢
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 2017-01-18
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      相关资源
      最近更新 更多