Eigene JComponent Klasse mit permanentem Tooltip

Hi,

ich bin dabei eine eigene JComponent-Klasse zu erstellen. Hintergrund ist der, dass ich gerne eine Art rundes JLabel hätte. Die runden Label sollen dann Knoten in einer visualisierten Datenbankquery repräsentieren.
In zum Label gehörenden Tooltip befinden sich genauere Informationen über den Knoten
Der Benutzer soll nun die Möglichkeit haben, per Menübutton die Tooltips permanent anzeigen zu lassen und diese auch wieder auszuschalten. Werden die Tooltips nicht permanent angezeigt sollen sie ganz normal mit mouseover erscheinen.

Ich komm grad nicht drauf wie ich das umsetzen kann.
Ich hab meiner JComponent-Klasse schon eine Variable vom Typ Tooltip hinzugefügt, der per Buttonklick in der GUI sichtbar und unsichtbar (setVisilbe()) geschalten wird, der erscheint aber erst gar nicht. Irgendwie steig ich nicht ganz durch wie das mit ToolTips im Allgemeinen funktioniert, die Java API bietet in der Richtung auch nicht sonderlich viel.

Hier mal meine vorläufige Klasse mit nicht funktionierendem ToolTip

public class MonsterLabel extends JComponent {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5862053117396352997L;
	
	private Icon icon;
	private boolean showNodeToolTip;
	private JToolTip tooltip;
	
	public MonsterLabel(Icon icon, String tooltipText){
		this.icon = icon;
		tooltip = new JToolTip();
		tooltip.setComponent(this);
		tooltip.setTipText(tooltipText);
	}
	
	public MonsterLabel(Icon icon){
		this.icon = icon;
	}		
	
	@Override
	protected void paintComponent(Graphics g) {
		
		g.setColor(getBackground());
		g.fillOval(0, 0, getSize().width, getSize().height);
		
		if(icon != null)
			icon.paintIcon(this, g, 0, 0);
				
		g.setColor(Color.BLACK);
		g.drawOval(0, 0, getSize().width - 1, getSize().height - 1);
//		super.paintComponent(g);
		
	
	}
		
	public void setShowToolTip(boolean b){
		this.showNodeToolTip = b;
		tooltip.setVisible(b);
		System.out.println("tooltipvisible: : " + tooltip.isVisible());
		repaint();
	}
	
}

edit
Um mein Vorhaben nochmal zu verdeutlichen: Man soll nur die ToolTips der runden “JLabels” permanent sichtbar machen können, alle anderen ToolTips (Buttons, Menüs etc) sollen weiterhin normal zu funktionieren.
Da mein Vorhaben mit JToolTip gar nicht umsetzbar zu sein scheint, versuch ich mal ein undecorated Window oder n Dialog erscheinen zu lassen

Wie man ToolTips hinzufügt bzw. einsetzt weisst du ja sicher. Wenn nicht… schau dir mal entsprechende Themen z.B. auf Gallileo (“auf der Insel” klingt hier irgendwie blöd) an.
Für dein Vorhaben wirst du aber wohl oder übel einen eigenen ToolTipManager implementieren müssen.

[QUOTE=Spacerat]Wie man ToolTips hinzufügt bzw. einsetzt weisst du ja sicher.
[/QUOTE]
Jap, das is mir klar. Das was ich vorhabe scheint aber über die Möglichkeiten der Standardtooltips hinauszugehen.

Auf der Insel bin ich schon gewsen :slight_smile: (und musste mit Entsetzen feststellen, dass meine gedruckte Version gar nichts über ToolTips enthält…Frechheit!). Dort steht auch nur das Standardzeugs

[QUOTE=Spacerat;68122]
Für dein Vorhaben wirst du aber wohl oder übel einen eigenen ToolTipManager implementieren müssen.[/QUOTE]
Sowas in die Richtung hab ich befürchtet :smiley:
Ich versuch meine Tooltips grade mit nem JWindow umzusetzen. Was ich bisher hab gefällt mir auch recht gut, allerdings nimmt das doofe JWindow nicht die Größe seiner Komponenten an und versuch das grad noch irgendwie zu deixeln

edit:
oO das pack() vergessen. Dann nehm ich meine letzte Aussage über JWindow zurück und behaupte das Gegenteil

Tooltips sind etwas eigen. Das ist eine Funktionalität, die gewissen “Konventionen” folgt, die im wesentlichen von den Fenstermanagern vorgegeben werden. Insbesondere:

  • Das Tooltip erscheint nach einer gewissen Zeit
  • Es erscheint an der Mausposition
  • Es verschwindet nach einer Weile (oder wenn man die Maus bewegt)
  • Es gibt immer nur EIN Tooltip (!)

Das, was du beschrieben hast, klingt, als wären das keine “Tooltips” in diesem Sinne. Ob man da durch irgendwelche TooltipManager-Hacks was vernünftiges hinbekommt, ist fraglich. Aber vielleicht findet man eine Lösung, wenn du die Anforderungen bezüglich der genannten Punkte genauer beschreibst.

Ich versuchs nochmal genauer zu erläutern:
Ich habe eine eigene JComponent-Klasse, nennen wir sie mal PaintedNode.
Es soll zwischen zwei Modi unterschieden werden.
Im normalen Modus sollen wenn man sich mit der Maus über einem PaintedNode befindet ganz normal ein ToolTip angezeigt werden und auch wieder verschwinden wenn die Maus den PaintedNode verlässt.
Der Benutzer soll nun die Möglichkeit haben, per Button, Menü whatever, den zweiten Modus zu aktivieren. Im zweiten Modus sollen alle PaintedNodes permanent ihre “ToolTips” anzeigen (ich nenns mal weiterhin Tooltips, obwohl das ja eigentlich keine mehr sind). Ein MouseOver hat im zweiten Modus keinen Effekt mehr, da der entsprechende ToolTip eh schon angezeigt wird

Werd demnächst meinen bisherigen Code hochladen

Ja, WO sollen die permanenten Tooltips erscheinen, was soll passieren, wenn man mit der Maus drüberfährt oder einen Knoten bewegt, auf welcher Ebene sollen sie erscheinen, wie sollen sie aussehen … man kann natürlich irgendwas basteln mit einer LayeredPane und/oder GlassPane, aber das ist doch etwas Stochern im Trüben.

Also Glass-, Layered- oder überhaupt irgend 'ne Pane fallen aus, denk ich mal und denke dabei an Komponenten, die sich am rechten Rand befinden, wo die ToolTips über diesen hinausragen.
Ich hatte damals mal versucht, einen ToolTip-Manager für AWT nachzubauen. Dafür habe ich ToolTip die Klasse Frame erweitern lassen welche ich mit “setUndecorated(true)” instanzierte. Leider klappte das damals nicht, wie es sollte, für Applets und ich habe das Ganze dann gelassen. Code existiert dazu leider auch nicht mehr.

Hier mal meine bisherige Klasse:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.MouseInfo;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;

public class PaintedNode extends JComponent{

	/**
	 * 
	 */
	private static final long serialVersionUID = 5862053117396352997L;
	
	private Icon icon;
	private boolean showTip;
	private JWindow tipWindow;
	private boolean mouseOver;
	
	
	public PaintedNode(Icon icon, String tipText){
		this.icon = icon;

		initTipWindow(tipText);
		
	}
	
	public void initTipWindow(String tipText){
		tipWindow = new JWindow();
		JPanel content = new JPanel(new BorderLayout());
		JLabel tipLabel = new JLabel(tipText);
		tipLabel.setHorizontalAlignment(JLabel.CENTER);
		tipLabel.setVerticalAlignment(JLabel.CENTER);
		content.add(tipLabel);
		content.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		
		tipWindow.setContentPane(content);
		tipWindow.setLocation(getX() + getWidth(), getY() + getHeight());
		tipWindow.pack();
	}
	
	public PaintedNode(Icon icon){
		this.icon = icon;
	}
	
	@Override
	protected void paintComponent(Graphics g) {
		
		g.setColor(getBackground());
		g.fillOval(0, 0, getSize().width, getSize().height);
		
		if(icon != null)
			icon.paintIcon(this, g, 0, 0);
		
		g.setColor(Color.BLACK);
		g.drawOval(0, 0, getSize().width - 1, getSize().height - 1);
		
		if(showTip && tipWindow != null){
			tipWindow.setVisible(showTip);
			Container parent = getRoot();
			tipWindow.setLocation(parent.getX() + getX() + getWidth(),
					parent.getY() + getY() + getHeight());
		}
		if(mouseOver && !showTip){
			tipWindow.setVisible(true);
			
			tipWindow.setLocation(MouseInfo.getPointerInfo().getLocation().x + 10, 
					MouseInfo.getPointerInfo().getLocation().y + 5);
		}
		else if(!mouseOver && !showTip){
			tipWindow.setVisible(false);
		}	
	}
	
	public Container getRoot(){
		Container parent = this;
		while(parent.getParent() != null)
			parent = parent.getParent();

		return parent;
	}
	
	public void setShowToolTip(boolean b){
		showTip = b;
		repaint();
	}
	
	@Override
	public boolean contains(int x, int y){
		double xM = getWidth() / 2;
		double yM = getHeight() / 2;
		double radius = xM;

		double distance = Math.sqrt(Math.pow(xM - new Double(x).doubleValue(),	2) + 
				Math.pow(yM - new Double(y).doubleValue(), 2));
		
		 if(distance <= radius){
			 mouseOver = true;
			 repaint();
			 return mouseOver;
		 }
		
		 mouseOver = false;
		 repaint();
		 return mouseOver;	
	}
}

Die Permatipps sollen an einer bestimmten vorher festgelegten Stelle erscheinen, z.B. an der rechten unteren Ecke des theoretischen Rechtecks, das ein rundes PaintedNode Objekt beschreibt (das versuch ich auch im Code oben). Fährt man mit der Maus drüber und die permanten Tipps sind gerade aktiviert, erscheint kein Tooltip. Bewegt sich ein solcher PaintedNode sollen die Permatipps sich mitbewegen sofern aktiviert, wenn nicht führt ein MouseOver wieder zum Tooltip. Die Tooltips sollen auf oberster Ebene liegt, heißt andere Komponenten überlagern.

Folgendes funktioniert bereits:

  • Permanente Tooltipps ein/ausblenden
  • Tooltip erscheint bei MouseOver an der Position beim Mauszeiger
  • Sind permanente Tipps aktiviert ist kein MouseOver-Tooltip möglich
  • Bei Animation bewegen sich permantene Tooltips mit
  • Bei Animation funktioniert der MouseOver-Tooltip

Was nicht funktioniert:
-Da die (permanenten) Tooltips nun als JWindow realisiert sind und deren Positionierung über absolute Bildschirmkoordinaten funktioniert, schaff ichs nicht sie richtig zu positionieren, da die Position des PaintedNode, die die Position des zu ihm gehörenden Tooltips bestimmt, nicht in absoluten Koordinaten vorliegt
-Bewegt sich das Fenster in dem sich der PaintedNode befindet und permanente Tips werden gerade angezeigt, bewegt sich der Tooltip nicht mit. Erst wenn sich die Maus wieder innerhalb des Fensters bewegt wird die Tippposition aktualisiert.

Wenn euch sonst noch Anregungen einfallen, immer her damit

Mal so als Stichworte HierarchieBoundsListener und “getLocationOnScreen()” in den Raum werf…

@Spacerat : Danke für die Hinweise. Funktioniert bestens

Wieso nicht einfach alleine programmieren? Sind doch eh nichts als stinknormale “kästchen” mit text

[QUOTE=mymaksimus]…Sind doch eh nichts als stinknormale “kästchen” mit text[/QUOTE]Sicher? Hast du meinen Einwurf über den rechten Rand oben gelesen?

habe ich, und bin trozdem davon überzeugt das es in vereinfachter form geht ^^
ich versuch das jedenfalls auch mal

Die “Tooltips” an sich funktionieren wunderbar. Jetzt steh ich aber vor dem unvorhergesehenen Problem, dass sich manche Tips überlagern können, wenn sie dauerhaft angezeigt werden.
Bisher hab ichs so, dass die dauerhaften Tips an einer bestimmten Stelle des PaintedNodes stehen und würde das auch gern beibehalten. Den Aufwand hier etwas zu basteln, das die Überlagerung erkennt und dann den Tip auch noch dynamisch so verschiebt, dass es keine Überlagerung gibt schätze ich mal als sehr hoch ein und für meine Zwecke ist das den Aufwand auch nicht wert.

Gibts vllt einfachere Lösungen?
Sowas wie z.B. dass wenn man über einen der beiden Tips mit der Maus drüberfährt, dieser eindeutig auf dem anderen liegt würde für meine Zwecke schon reichen. Allerdings weiß ich nich wie ich da unterscheide bzw. den einen über den anderen “zeichne”, da beide Tooltips in der paintcomponent() des jeweiligen PaintedNodes gesetzt werden

Sicher sind die Tooltips auch alles irgendwo Fenster… und soweit ich weiss, kommen Fenster in den Vordergrund (als oberstes) sobald sie den Fokus bekommen. Evtl. lässt sich da also etwas mit 'nem MouseListener (“mouseEntered()”) machen. Wahrscheinlich aber nur mit 'ner zusätzlich gedrückten Taste, als Signal, dass man sie auswählen oder sichtbar machen will. Ich wüsste auch nicht, was geschieht, wenn das darunterliegende Fenster wieder aktiv wird. Kommt wohl wieder in den VG und verdeckt alle anderen. Würde bedeuten, dass man alle Tooltips erneut (ohne Fokus) zeichnen muss und das angewählte dabei als letztes.