Popup - JFrame - Anchor

hesk

Erfahrenes Mitglied
Hallo!

Ich hab ein simples Frame mit einem Textfield. Rechts vom Textfield soll durch ein Popup ein Label angezeigt werden(so wie ein Tooltip). Dieser ist aber leider nicht "verbunden" mit dem frame.

Das heißt wenn ich das Frame verschiebe, so bleibt das popup-Label wo es ist.
Sobald das popup-Label komplett inerhalb des Frames liegt, wird es mitverschoben.

Kan mir da einer helfen?

Hier der code:

Java:
import java.awt.Color;
import java.awt.FlowLayout;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.UIManager;

public class Beispiel5
{
    public Beispiel5()
    {
        try
        {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        }
        catch (Exception e)
        {
        }

        JFrame frame = new JFrame("Beispiel 5");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 300);

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        JLabel label = new JLabel("Datum");
        JTextField field = new JTextField(30);

        PopupFactory factory = PopupFactory.getSharedInstance();

        panel.add(label);
        panel.add(field);
        frame.add(panel);
        frame.setSize(350, 250);

        frame.setVisible(true);

        int x = field.getLocationOnScreen().x + field.getPreferredSize().width - 2;
        int y = field.getLocationOnScreen().y - field.getPreferredSize().height + 2;

        JPanel errorPanel = new JPanel();
        JLabel errorLabel = new JLabel("Falsches Datum");
        errorPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        errorPanel.add(errorLabel);
        Popup popup = factory.getPopup(frame, errorPanel, x, y);
        popup.show();

    }

    public static void main(String[] args)
    {
        Beispiel5 beispiel = new Beispiel5();
    }
}
 

hesk

Erfahrenes Mitglied
Weil ich eine Fehlerausgabe für ein JTextField erzeugen will.

Aber ich bin drauf gekommen dass wenn das popup innerhalb des Frames gezeichnet wird, dann liegt es auf dem glass-pane und wird somit beim verschieben des Frames mitverschoben.

Liegt es nur ein wenig außerhalb, dann wird ein eigenständiges JWindow gemacht was dann natürlich stehen bleibt.
 

Fabio Hellmann

Erfahrenes Mitglied
Hi,
wenn du den Popup lieber auserhalb von deinem Fenster haben willst, musst du das "externe" JWindow mit setLocation relativ zum "Haupt"-Fenster ausrichten. Dann sollte das auch so funktionieren.

Gruß

Fabio
 

hesk

Erfahrenes Mitglied
Aber wird es dann auch mit verschoben wenn man das Hauptfenster verschiebt?
(Kann es gerade nicht testen)
 

Fabio Hellmann

Erfahrenes Mitglied
Nachdem ich da ein wenig rumgespielt habe, funktioniert es jetzt.
Java:
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowStateListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.UIManager;

public class Beispiel5
{
	public Beispiel5() {
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
		} catch(final Exception e) {
		}
		
		final JFrame frame = new JFrame("Beispiel 5");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(500, 300);
		
		final JPanel panel = new JPanel();
		panel.setLayout(new FlowLayout());
		final JLabel label = new JLabel("Datum");
		final JTextField field = new JTextField(30);
		
		final PopupFactory factory = PopupFactory.getSharedInstance();
		
		panel.add(label);
		panel.add(field);
		frame.add(panel);
		frame.setSize(350, 250);
		
		frame.setVisible(true);
		
		final int x = field.getLocationOnScreen().x + field.getPreferredSize().width - 2;
		final int y = field.getLocationOnScreen().y - field.getPreferredSize().height + 2;
		
		final JPanel errorPanel = new JPanel();
		final JLabel errorLabel = new JLabel("Falsches Datum");
		errorPanel.setBorder(BorderFactory.createLineBorder(Color.black));
		errorPanel.add(errorLabel);
		final Popup popup = factory.getPopup(frame, errorPanel, x, y);
		popup.show();
		
		frame.addComponentListener(new ComponentAdapter()
		{
			@Override
			public void componentResized(final ComponentEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					final int x = field.getLocationOnScreen().x + field.getPreferredSize().width - 2;
					final int y = field.getLocationOnScreen().y - field.getPreferredSize().height + 2;
					currentPopup.setLocation(x, y);
				}
			}
			
			@Override
			public void componentMoved(final ComponentEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					final int x = field.getLocationOnScreen().x + field.getPreferredSize().width - 2;
					final int y = field.getLocationOnScreen().y - field.getPreferredSize().height + 2;
					currentPopup.setLocation(x, y);
				}
			}
		});
		frame.addWindowListener(new WindowAdapter()
		{
			@Override
			public void windowClosing(final WindowEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					currentPopup.dispose();
				}
			}
		});
		frame.addWindowStateListener(new WindowStateListener()
		{
			@Override
			public void windowStateChanged(final WindowEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					currentPopup.setVisible(e.getWindow().isVisible());
				}
			}
		});
		frame.addWindowFocusListener(new WindowFocusListener()
		{
			@Override
			public void windowLostFocus(final WindowEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					currentPopup.setVisible(false);
				}
			}
			
			@Override
			public void windowGainedFocus(final WindowEvent e) {
				final Window currentPopup = findCurrentPopup();
				if(currentPopup != null) {
					currentPopup.setVisible(true);
				}
			}
		});
	}
	
	/**
	 * {@link javax.swing.Popup.HeavyWeightWindow#HeavyWeightWindow(Window)}
	 * 
	 * @return
	 */
	public static Window findCurrentPopup() {
		final Window[] windows = JFrame.getWindows();
		for(final Window window : windows) {
			// Der Name steht in der Klasse, die im Kommentar als Link markiert ist
			if(window.getName().equals("###overrideRedirect###")) {
				return window;
			}
		}
		return null;
	}
	
	public static void main(final String[] args) {
		new Beispiel5();
	}
}

Gruß

Fabio
 

hesk

Erfahrenes Mitglied
Danke, das ist einmal ein Ansatz:)

Was ich noch nicht ganz verstehe...woher bekomme ich den Window-Name des Popups?

Wenn ich deinen Code einfach ausführe, funktioniert es noch nicht.

Ich muss erst bei

Java:
if(window.getName().equals("###overrideRedirect###")) {

win0 eintragen.
 

Fabio Hellmann

Erfahrenes Mitglied
Der name wird in der Java-Library eingetragen. Die Klasse befindet sich innerhalb der Popup Klasse.
Java:
javax.swing.Popup.HeavyWeightWindow
Im Konstruktor wird der Name des Fensters gesetzt. Ich war eigentlich der Meinung, dass der Name überall gleich sein müsste, da er schließlich in der Java-Library fest verankert ist.