Events unterdrücken

Status
Nicht offen für weitere Antworten.

Tobias

Top Contributor
Hallo,

ich möchte folgendes tun:

In meinem aktuellen Projekt gibt es einen Dialog, der dazu dient, Eingabehilfen für Touchscreens anzubieten. Dieser Dialog wird durch Anklicken einer Komponente mit der Maus (bzw eigentlich durch "Anpatschen" mit dem Finger) aktiviert. Dummerweise löst das Anklicken zumeist auch die eigentlich Aktion der Komponente aus (Buttons werden gedrückt, Listen klappen aus etc.). Dies soll unterdrückt werden.

Die einzige mir bislang eingefallene Methode ist die GlassPane des Fensters zu modifizieren, was mir jedoch nicht besonders gut gefällt, weil es a) viel Aufwand bedeutet und b) unnötig und bei Weiterentwicklungen fehlerträchtig in das Verhalten des eigentlich nicht mir unterstellten JFrames eingreift (die GlassPane müßte ja dauerhaft installiert werden und nicht nur solange der Dialog geöffnet ist). Am liebsten wäre mir die Installation einer Art GlassPane nur über den einzelnen Formular-Komponenten, die Eingabehilfe erhalten sollen, aber das scheint nicht so einfach machbar zu sein.

Aber vielleicht hat ja einer von euch einen anderen Vorschlag!?!

mpG
Tobias
 

Marco13

Top Contributor
Hm... nur damit das klarer wird: Ist dieser "Dialog" sowas wie ein "Aufgebohrter Tooltip, der durch Klicken aktiviert wird"??? ???:L
 

Tobias

Top Contributor
Nein, der Dialog ist ein echter Dialog abgeleitet von JDialog.

Es sind beim Kunden einige Touchscreens im Einsatz (hauptsächlich Point of Sale, also Kassencomputer). Die Dinger sind oft ein bißchen älter und nicht unbedingt zielgenau. Das Auswählen eines Items einer JList würde sich also mitunter schwierig gestalten (vor allem, wenn es schnell gehen muss). Deshalb soll, wenn die JList angeklickt wird, der Dialog aufgehen und die einzelnen Items der JList in Form ausreichend großer Buttons darstellen, die dann einfach angeklickt werden können.

Die Originalkomponente darf aber auf das Anpatschen nicht auch direkt reagieren, weshalb ich den Eingabeevent unterdrücken will.

Jetzt klarer *hoff*?

mpG
Tobias
 

Marco13

Top Contributor
Hmja, vom Prinzip her war das das, was ich dachte - es war nur nicht klar, unter welchen Bedinungen der Dialog aufgeht, (ich nehme an, dass man "mausKlick" und "fingerDatscher" als "gleich" ansehen kann...) und was man mit dem Dialog dann macht.

Die Bedenken gegen die GlassPane sind verständlich. Man verdeckt ja den kompletten Frame, und es ist (glaubich) nicht möglich, das Verhalten des Frames und seines Inhaltes vollkommen unbeeinflusst zu lassen. Hab trotzdem mal testweise die GlassPaneDemo von
http://java.sun.com/docs/books/tuto...DemoProject/src/components/GlassPaneDemo.java
ein bißchen aufgebohrt, aber vmtl. ist es nicht 100% das was du willst....

Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.List;
import java.util.*;


class InputHelpProvider implements MouseListener, MouseMotionListener
{
    private List<Component> components = new ArrayList<Component>();
    private JFrame frame;
    private JPanel glassPane;

    public InputHelpProvider(JFrame frame)
    {
        this.frame = frame;

        glassPane = new JPanel();
        glassPane.setOpaque(false);
        glassPane.addMouseListener(this);
        glassPane.addMouseMotionListener(this);
        frame.setGlassPane(glassPane);
        glassPane.setVisible(true);
    }

    public void addComponent(Component component)
    {
        components.add(component);
    }

    public void removeComponent(Component component)
    {
        components.add(component);
    }

    public void mouseMoved(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mouseDragged(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mouseClicked(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mouseEntered(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mouseExited(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mousePressed(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    public void mouseReleased(MouseEvent e)
    {
        redispatchMouseEvent(e);
    }

    private void redispatchMouseEvent(MouseEvent e)
    {
        Point glassPanePoint = e.getPoint();
        Container container = frame.getContentPane();
        Point containerPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, container);
        if (containerPoint.y >= 0)
        {
            Component component =
                SwingUtilities.getDeepestComponentAt(container, containerPoint.x, containerPoint.y);
            if (component != null)
            {
                if (components.contains(component))
                {
                    if (e.getID() == MouseEvent.MOUSE_CLICKED)
                    {
                        JOptionPane optionPane = new JOptionPane("Does it work?",
                            JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_OPTION);
                        JDialog dialog = optionPane.createDialog(frame, "Test");
                        dialog.setResizable(true);
                        Rectangle bounds = component.getBounds();
                        bounds = SwingUtilities.convertRectangle(frame.getContentPane(), bounds, glassPane);
                        bounds.x += frame.getX() + frame.getInsets().left;
                        bounds.y += frame.getY() + frame.getInsets().top;
                        dialog.setBounds(bounds);
                        dialog.setVisible(true);
                    }
                }
                else
                {
                    Point componentPoint =
                        SwingUtilities.convertPoint(glassPane, glassPanePoint, component);
                    component.dispatchEvent(
                        new MouseEvent(component, e.getID(), e.getWhen(), e.getModifiers(),
                                       componentPoint.x, componentPoint.y, e.getClickCount(),
                                       e.isPopupTrigger()));
                }
            }
        }
        frame.repaint();
    }

}




public class GlassPaneTest
{
    public static void main(String[] args)
    {
        new GlassPaneTest();
    }

    InputHelpProvider inputHelpProvider;

    public GlassPaneTest()
    {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.getContentPane().setLayout(null);

        JButton button = new JButton("No input helper");
        frame.getContentPane().add(button);
        button.setBounds(100,200,200,100);

        JTree tree = new JTree();
        frame.getContentPane().add(tree);
        tree.setBounds(400,50,200,200);

        String[] data = {"This", "has", "an", "input", "helper"};
        JList list = new JList(data);
        frame.getContentPane().add(list);
        list.setBounds(500,300,200,200);

        inputHelpProvider = new InputHelpProvider(frame);
        inputHelpProvider.addComponent(list);


        frame.setVisible(true);
    }

}


Wenn du vollkommene Kontrolle über diese Components hast, dann könnte man theoretisch(!) vielleicht (!) auch eine "Leere" JComponent basteln, die nur einen MouseListener zum Öffnen des Dialogs enthält, und ansonsten ein verstecktes Delegate, das "fake-mäßig" gezeichnet wird... grob sowas wie
Code:
class FakeComponent<Content extends Component> implements MouseListener
{
    Content content;
    
    void mouseClicked(...) { openDialog(); }

    public void paintComponent(Graphics g)
    {
        content.paintComponent(g);
    }
    ...
}
Hm. Das wäre aber auch Hack³, und aufwändig, weil man ja etliche Methoden (von getPreferredSize bis ... ???) "durchrouten" müßte... sorry, aber sonst hab ich jetzt spontan keine Idee mehr...
 

Tobias

Top Contributor
Ok,

ich habe jetzt mal folgendes Progrämmchen zu Testzwecken zusammengehackt. Funktioniert ganz gut. Es verfolgt den von mir ursprünglich angenommenen Ansatz, eine GlassPane über den einzelnen Komponenten zu installieren (über die habe ich ein wenig Macht). Das ganze ist ein simples, lauffähiges Beispiel.

Code:
// Uses InputEventConsumer
public class FAContainerFrame extends JFrame implements ActionListener {

	class FAContainer extends JPanel {

		private JRootPane root;

		public FAContainer() {
			super();
			setLayout(new BorderLayout());

			root = new JRootPane();
			super.addImpl(root, BorderLayout.CENTER, 0);
		}

		@Override
		protected void addImpl(Component comp, Object constraints, int index) {
			root.getContentPane().add(comp, constraints, index);
		}

		public void setGlassPane(Component gp) {
			root.setGlassPane(gp);
		}

		public Component getGlassPane() {
			return root.getGlassPane();
		}

	}

	private FAContainer faContainer;

	private InputEventConsumer iec = new InputEventConsumer();

	private JButton lock;

	private JButton unlock;

	public FAContainerFrame() {
		super("FAContainerFrame");
		setSize(400, 400);
		setLayout(new BorderLayout());

		faContainer = new FAContainer();
		faContainer.add(makeButton("In FAContainer"));
		lock = makeButton("Sperren");
		unlock = makeButton("Entsperren");
		unlock.setEnabled(false);

		add(faContainer, BorderLayout.CENTER);
		add(lock, BorderLayout.EAST);
		add(unlock, BorderLayout.WEST);

		setVisible(true);
	}

	private JButton makeButton(String text) {
		JButton butt = new JButton(text);
		butt.setActionCommand(text);
		butt.addActionListener(this);

		return butt;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new FAContainerFrame();
	}

	/**
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		String ac = e.getActionCommand();

		if (ac.equals("In FAContainer")) {
			JOptionPane.showMessageDialog(this, "In FAContainer gedrueckt!");
		} else if (ac.equals("Sperren")) {
			faContainer.getGlassPane().addMouseListener(iec);
			faContainer.getGlassPane().addKeyListener(iec);
			faContainer.getGlassPane().setVisible(true);
			faContainer.setCursor(new Cursor(Cursor.WAIT_CURSOR));

			lock.setEnabled(false);
			unlock.setEnabled(true);
		} else if (ac.equals("Entsperren")) {
			faContainer.getGlassPane().removeMouseListener(iec);
			faContainer.getGlassPane().removeKeyListener(iec);
			faContainer.getGlassPane().setVisible(false);
			faContainer.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));

			unlock.setEnabled(false);
			lock.setEnabled(true);
		}
	}

}

Und hier noch die Klasse InputEventConsumer aus meiner Commons-Bibliothek:

Code:
class InputEventConsumer implements KeyListener, MouseListener {

	/**
	 * Defines whether the computer should beep if the component
	 * InputEventConsumer is attached to receives mouse- or keyboard-input.
	 */
	// FIXME Must be configurable
	private boolean beep = true;

	/**
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	public void keyPressed(KeyEvent e) {
		consume(true, e);
	}

	/**
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	public void keyReleased(KeyEvent e) {
		consume(false, e);
	}

	/**
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	public void keyTyped(KeyEvent e) {
		consume(false, e);
	}

	/**
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	public void mouseClicked(MouseEvent e) {
		consume(true, e);
	}

	/**
	 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
	 */
	public void mouseEntered(MouseEvent e) {
		consume(false, e);
	}

	/**
	 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
	 */
	public void mouseExited(MouseEvent e) {
		consume(false, e);
	}

	/**
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	public void mousePressed(MouseEvent e) {
		consume(false, e);
	}

	/**
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e) {
		consume(false, e);
	}

	/**
	 * Consumes the overgiven InputEvent.
	 * 
	 * @param beep
	 *            if this parameter and the instance-variable <code>beep</code>
	 *            are true, a beep will sound.
	 * @param e
	 *            the InputEvent to consume.
	 */
	private void consume(boolean beep, InputEvent e) {
		if (beep && this.beep) {
			Toolkit.getDefaultToolkit().beep();
		}
		e.consume();
	}

}

Vielleicht kann es ja jemand gebrauchen oder einer von euch hat noch ein paar Anmerkungen dazu.

Danke an Marco für deine Hilfsbereitschaft und das schöne Beispiel, welches ich aus den oben erörterten Sorgen von wegen Eingriff in fremde "Einflusssphären" nicht benutzen möchte.

mpG
Tobias
 

Marco13

Top Contributor
OK, sieht aus wie eine (einfacherer, aber besser durchdachte und weniger gehackte) Mischung aus meinen beiden Ansätzen... aber ... wenn ich das richtig sehe, leigen da ja jetzt ALLE "geblockten" Components jeweils(!) als EIN FAContainer im Frame - und FAContainer überschreibt z.B. NICHT "getPreferredSize" und dandere Methoden, die notwendig wären, damit er sich (abgesehen vom Abfangen der Eingaben) so verhält, wie die eingewickelte Component (er könnte wohl einige Methodenaufrufe an die eingewickelte Component weiterreichen...!?) ... hm, naja, aber wenn's für deine Zwecke OK ist, ist's ja gut...
 

Tobias

Top Contributor
Mh, ja, das mit dem Weiterreichen der Methodenaufrufe stimmt wohl. Ich weiß noch nicht, ob ich das wirklich brauche, oder ob es ausreicht, die Komponente vor dem Einwickeln vollständig zu konfigurieren. Naja, die Praxis wird es zeigen. Das da oben ist bloß der Prototyp, der spätere Produktivcode wird sich davon (bis auf das verfolgte Konzept) erheblich unterscheiden.

mpG
Tobias

Edit: Wo siehst du die Schwierigkeiten darin, das jede Komponente von einem eigenen Container umwickelt wird?
 

Marco13

Top Contributor
Wo siehst du die Schwierigkeiten darin, das jede Komponente von einem eigenen Container umwickelt wird?

Naja, die potentiellen(!) Probleme sehe ich hauptsächlich in den Methodenaufrufen, die nicht weitergereicht werden - das fängt beim Layout an (und ist da wohl am ehesten "sichtbar"), kann sich aber bis zu so "fiesen" Sachen wie Focus-Verhalten durchziehen... :?

OB es ein Problem sein kann, wenn ein heavyweight-container (d.h. ein JFrame) mehrere JRootPanes enthält, weiß ich nicht - diese Klasse nimmt ja schon eine ziemliche Sonderrolle ein, aber ich habe noch nicht konkret mit dieser Klasse gearbeitet, darum weiß ich nicht, WO da die Probleme liegen könnten. Etwas weniger Bauchschmerzen hätte ich, wenn es "nur" eine JLayeredPane wäre, aber um das fundiert begründen zu können, müßte man sich nochmal die Details des Zusammenspiels von JFrames, JRootPanes und JLayeredPanes ansehen...
 

Tobias

Top Contributor
Bisher habe ich diesbezüglich keine Probleme feststellen können - ich habe da aber auch noch keine größeren Tests zu gefahren. Ich werde meine Erfahrungen hier mitteilen.

mpG
Tobias
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
G mouse events AWT, Swing, JavaFX & SWT 6
Heldderschatten Java Events und Interfaces AWT, Swing, JavaFX & SWT 18
T Swing Änderung des ActionListener Events nach Klick auf JButton AWT, Swing, JavaFX & SWT 2
D Swing Events vom JLayer abfangen AWT, Swing, JavaFX & SWT 2
D Transparentes Hauptfenster Events AWT, Swing, JavaFX & SWT 1
M Swing Hinter die Kulissen von Events (addActionListener) AWT, Swing, JavaFX & SWT 6
N JTextArea Events weiterleiten AWT, Swing, JavaFX & SWT 3
R SWT Eigene Events erstellen und werfen AWT, Swing, JavaFX & SWT 59
S Mouse Events in einer sortierten JTable unterscheiden AWT, Swing, JavaFX & SWT 18
C Swing Simulation von Drag and Drop Events AWT, Swing, JavaFX & SWT 3
J Events und Sleep? AWT, Swing, JavaFX & SWT 4
C MouseMotionListener fired keine Events mehr wenn in Button AWT, Swing, JavaFX & SWT 2
E JFace ListSelectionDialog & Mouse-Events? AWT, Swing, JavaFX & SWT 2
N Variablen in Events AWT, Swing, JavaFX & SWT 4
P AWT MouseListener unklare abhandlung von Events AWT, Swing, JavaFX & SWT 3
L Swing Auslöser eines Events finden? AWT, Swing, JavaFX & SWT 6
R JTable - eigener Editor - Mouse events AWT, Swing, JavaFX & SWT 2
C keine weiteren Events während Drag&Drop Operation möglich? AWT, Swing, JavaFX & SWT 5
Weltall 7 AWT Maus-Events werden doppelt ausgeführt AWT, Swing, JavaFX & SWT 12
0 Events werden nicht ausgelöst AWT, Swing, JavaFX & SWT 2
V Swing Auslösen von zwei Events hintereinander AWT, Swing, JavaFX & SWT 4
T Swing Control und Events AWT, Swing, JavaFX & SWT 8
MrMilti Gezeichnete Java2D Elemente mit Events versehen AWT, Swing, JavaFX & SWT 3
R Events - Nur auf eines reagieren AWT, Swing, JavaFX & SWT 3
T JComboBox: ActionListener/ItemListener wie nur auf bestimmte Events reagieren? AWT, Swing, JavaFX & SWT 7
B Swing setDefaultButton geht nicht - Komponente fängt Events ab AWT, Swing, JavaFX & SWT 5
R Key und Mouse Events AWT, Swing, JavaFX & SWT 2
K Alle Events abfangen mit GlassPane AWT, Swing, JavaFX & SWT 7
T SWT - Table Events AWT, Swing, JavaFX & SWT 3
hdi Events nicht plattform-unabhängig? AWT, Swing, JavaFX & SWT 14
M SWT: eigene Events AWT, Swing, JavaFX & SWT 9
G Reihenfolge von Events AWT, Swing, JavaFX & SWT 4
D Events bei Tabs in einem Editor AWT, Swing, JavaFX & SWT 2
F Probleme mit MouseWheel events in SWT AWT, Swing, JavaFX & SWT 13
M Globale Events in Windows abfangen AWT, Swing, JavaFX & SWT 2
T Hilfe zu Events? AWT, Swing, JavaFX & SWT 6
S Events abfangen, nicht durchlassen AWT, Swing, JavaFX & SWT 2
G An die Quelle einen events kommen AWT, Swing, JavaFX & SWT 2
M Problem mit verschachtelten Events und kein ausweg in sicht AWT, Swing, JavaFX & SWT 3
W Vom JPanel bekomme ich keine Events AWT, Swing, JavaFX & SWT 5
V Events an untere Layers weitergeben AWT, Swing, JavaFX & SWT 2
V events skippen AWT, Swing, JavaFX & SWT 14
M Events auslagern? AWT, Swing, JavaFX & SWT 6
F Events AWT, Swing, JavaFX & SWT 8
N SWT: GUI Windows Events AWT, Swing, JavaFX & SWT 8
I Globale Tastatur-Events abfragen AWT, Swing, JavaFX & SWT 3
D Events werden zu oft aufgerufen AWT, Swing, JavaFX & SWT 4
G Events AWT, Swing, JavaFX & SWT 2
K Mouse Events der Scrollbar/pane AWT, Swing, JavaFX & SWT 2
S Events fremdauslösen AWT, Swing, JavaFX & SWT 17
K Doppelte Events AWT, Swing, JavaFX & SWT 4
A Combobox Focus-Events, Tab in Tabelle AWT, Swing, JavaFX & SWT 7
D Events, Listener, GUI . Größeres Projekt AWT, Swing, JavaFX & SWT 4
A Vielschichtige GUI und Events? AWT, Swing, JavaFX & SWT 4
V JList mit Events Steuern ? AWT, Swing, JavaFX & SWT 15
S Rechner zu schnell für Events? AWT, Swing, JavaFX & SWT 14
G JTable und Events AWT, Swing, JavaFX & SWT 4
S Events bei 2 gleichen Jtree abfangen AWT, Swing, JavaFX & SWT 3
ShapeShifter JButton erzeugt zwei Events AWT, Swing, JavaFX & SWT 4
B Eigenes Events AWT, Swing, JavaFX & SWT 3
T JScrollPane-Events AWT, Swing, JavaFX & SWT 2
M JTable und Events AWT, Swing, JavaFX & SWT 4
K JComboBox: Endlosschleife durch Events AWT, Swing, JavaFX & SWT 4
K [JComboBox] ENTER löst zwei events aus? AWT, Swing, JavaFX & SWT 2
M Glasspane und dispatchen von Events AWT, Swing, JavaFX & SWT 6
H Events manuell aufrufen AWT, Swing, JavaFX & SWT 4
F JComboBox setEditable( true ) auf Tastatur Events reagieren AWT, Swing, JavaFX & SWT 4
C SWT MenuBar & MenuItems Fokus wenn F10 unterdrücken/entfernen AWT, Swing, JavaFX & SWT 9
A bei TableCells editieren unterdrücken AWT, Swing, JavaFX & SWT 5
S Kontextmenu im JInternalFrame unterdrücken AWT, Swing, JavaFX & SWT 5
T Alt+F4 unterdrücken - mal anders AWT, Swing, JavaFX & SWT 5
A Repaint unterdrücken bei DrawLine in JPanel AWT, Swing, JavaFX & SWT 4
E [KeyListener] unterdrücken möglich? AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben