Pytanie Java: kliknięcie okna (w tym tekst / obrazy)


Chcę utworzyć nakładkę w Javie przezroczysty, Zawsze na górze, i że mogę kliknięcie. Znalazłem trochę podobny  posty o tym problemie, ale nawet po uzyskaniu odpowiedzi, mam jeden problem.

Mój problem polega na tym, że całe okno kliknięcie. Nie mam żadnego problemu z działaniem z JFrame, ale kiedy ja dodaj dowolne komponenty do niego (JLabel lub ImagePanel), Atrybut click-through nie jest przenoszony do nich.

Ponieważ chcę mieć obraz tła dla mojej aplikacji, w zasadzie czyni to kod bezużyteczny, widząc, jak okno staje się skupione za każdym razem, gdy klikam obszar, który obejmuje tekst / obraz.

Zanim pokażę kod, którego używam, najpierw chciałbym się odnieść te  wątki który zasadniczo opisuje dokładnie to, czego chcę, z wyjątkiem C #.

Moim celem jest stworzenie nakładki z przezroczystym obrazkiem .png i tekstem, który zmieni się na kluczowych wydarzeniach. Jeśli używa JFrame lub jakiejkolwiek innej biblioteki nie ma znaczenia. Potrzebuję go tylko kompatybilnego z Windows.

Chciałbym również wspomnieć, że mam trochę doświadczenia z Javą, ale jestem początkującym użytkownikiem JFrame.

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

import com.sun.jna.platform.WindowUtils;


public class Overlay {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Overlay Window");
        frame.setUndecorated(true);
        frame.setAlwaysOnTop(true);
        frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);
        frame.setLocation(400, 400);
        frame.getContentPane().setLayout(new java.awt.BorderLayout());

        JLabel textLabel = new JLabel("I'm a label in the window", SwingConstants.CENTER);
        frame.getContentPane().add(textLabel, BorderLayout.CENTER); 
        frame.pack();

        System.setProperty("sun.java2d.noddraw", "true");
        WindowUtils.setWindowTransparent(frame, true);
        WindowUtils.setWindowAlpha(frame, 1.0f);

        //Using AWTUtilities gives the same result as WindowUtils
        //AWTUtilities.setWindowOpaque(frame, false);
        //AWTUtilities.setWindowOpacity(frame, 1.0f);

        frame.setVisible(true);
    }
}

Zauważ, że problem jest nie o tym, że okno jest skupione (choć jest to wynikiem problemu), ale o JLabel i ImagePanel nie są klikane.


10
2018-06-27 00:07


pochodzenie


Prawdopodobnie musisz ustawić flagę WS_EX_TRANSPARENT w oknie JFrame, aby upewnić się, że zdarzenia myszy są przekazywane przez to okno. Oto przykład: codeproject.com/Articles/12877/Transparent-Click-Through-Forms - technomage
Czy chcesz, aby wszystkie kliknięcia trafiały do ​​pojedynczego komponentu w ramce JFrame, czy też przekazywać je do dowolnego elementu znajdującego się pod ramą JFrame (łącznie z pulpitem)? - technomage


Odpowiedzi:


Problem polegający na tym, że okno ma być "kliknięte", oznacza, że ​​jest on obsługiwany na poziomie systemu, poza zakresem standardowych interfejsów API. Oznacza to, że dowolny kod napisany w celu "kliknięcia" okna będzie zależny od systemu. W związku z tym proces realizacji tego w systemie Windows jest dość prosty.

W systemie Windows 2000 i nowszych ustawieniach flag WS_EX_LAYERED i WS_EX_TRANSPARENT w oknie okno zostanie kliknięte. Używany przykładowy kod JNA aby to osiągnąć:

public static void main(String[] args) {
    Window w = new Window(null);

    w.add(new JComponent() {
        /**
         * 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());
        }

        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }
    });
    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 HWND getHWnd(Component w) {
    HWND hwnd = new HWND();
    hwnd.setPointer(Native.getComponentPointer(w));
    return hwnd;
}

3
2018-02-27 18:57





Dlaczego po prostu nie skorzystać z istniejących JLayeredPane? Ten post na blogu demonstruje umieszczanie szerokiej gamy nakładek na JFrame, w tym tekst, obrazy i dynamicznie rysowane piksele.


1
2018-03-01 20:21





Próbowałem wykonać okno "przezroczyste dla zdarzeń" (kliknij, jak to nazywasz), ale wydaje się, że istnieją pewne rodzime ograniczenia tej sztuczki.

Sprawdź ten przykład okna:

public static void main ( String[] args )
{
    Window w = new Window ( null );

    w.add ( new JComponent ()
    {
        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 () );
        }

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

        public boolean contains ( int x, int y )
        {
            return false;
        }
    } );

    AWTUtilities.setWindowOpaque ( w, false );
    AWTUtilities.setWindowOpacity ( w, 0.5f );

    w.pack ();
    w.setLocationRelativeTo ( null );
    w.setVisible ( true );
}

Okno i komponent NIE ma żadnych:

  1. Słuchacze myszy
  2. Słuchacze ruchu myszy
  3. Słuchawki z myszką
  4. Kluczowi słuchacze

Również komponent powinien ignorować jakiekolwiek zdarzenia myszy, NAWET jeśli istnieją jakieś detektory ze względu na zmodyfikowane contains metoda.

Jak widać - obszar, w którym nic nie jest malowane na komponencie, jest przezroczysty, ale wypełniony obszar nie jest. Pechowo nie znalazłem żadnego rozwiązania, które mogłoby zmienić to zachowanie. Wydaje się, że niektóre metody java "niskiego poziomu" blokują zdarzenia.

A to tylko podstawowy przykład oparty na JComponentach. Nie mówię nawet o bardziej skomplikowanych komponentach Swingowych, takich jak etykiety, przyciski e.t.c. które mogą mieć własne detektory zdarzeń, które mogą blokować zdarzenia.


0
2018-06-27 14:52



ładny przykład +1 - mKorbel