How to add a ToolTip to MapMarker in JMapViewer - java

I'm trying to add a ToolTip to a custom MapMarker on JMapViewer. But repeaded searches on are not helping me solve this.
The custom MapMarker is:
public class MapMarkerUnit extends MapObjectImpl implements MapMarker
and the Paint Method overide is
public void paint(Graphics g, Point position, int radio) {
String filename = "marker.png";
//System.out.print(filename);
BufferedImage x = null;
try {
x = ImageIO.read(getClass().getResource(filename));
} catch (IOException ex) {
Logger.getLogger(MapMarkerUnit.class.getName()).log(Level.SEVERE, null, ex);
}
g.drawImage(x, position.x-16, position.y-37,null);
//if(getLayer()==null||getLayer().isVisibleTexts()) paintText(g, new Point(position.x+20,position.y));
}
Thanks for any help your able to offer.

Override the getToolTipText() method of JMapViewer. In your implementation, use getPosition() to convert the MouseEvent coordinates into geodetic coordinates. The example below simply displays the unformatted coordinates; you'll want to find the nearest MapMarker and return the appropriate text.
JMapViewer map = new JMapViewer() {
#Override
public String getToolTipText(MouseEvent e) {
Coordinate c = getPosition(e.getX(), e.getY());
return c.getLat() + " " + c.getLon();
}
};
map.setToolTipText(""); // initialize
Addendum: Is there a way of adding a tooltip directly to an image?
No; JMapViewer is the enclosing JComponent that handles tool tips.
I have about 50 markers on the map…that's a lot of iterations.
You definitely can't load images in your MapMarker implementation; use a SWingWorker to load images in the background, for example.
As a concrete iteration example, JFreeChart easily handles tool tips for scores of entities in this way. Here's the enclosing panel's getToolTipText() implementation, and here's the loop that invokes Shape#contains(). A simplified example that illustrates the approach is seen here.

Related

How do you set a custom Tooltip location for JTable header?

How can I set the tooltip location for a JTable header? I have no issue displaying the tooltip, but I would like to place it directly over the column title rather than the default location (under mouse cursor).
I can do this successfully for JTable cells by overriding the getToolTipLocation method in the JTable class, but it doesn't seem to work for the table header.
As well, the JTableHeader class doesn't support the getToolTipLocation method. I've been toiling with this for a while now and any samples or insight would be greatly appreciated.
I was wrong about JTableHeader not supporting getToolTipLocation. It's buried in the JComponent class which JTableHeader is subclassed from. The code example I provided solves my problem. I implemented the code in a class that is subclassed from the JTable class. I'm still getting use to this site and my apologies if the example doesn't seem complete.
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(this.columnModel) {
Point p = null;
#Override
public String getToolTipText(MouseEvent e) {
int colIdx = this.columnAtPoint(e.getPoint());
Rectangle rect = this.getHeaderRect(colIdx);
p = rect.getLocation();
return this.columnModel.getColumn(colIdx).getHeaderValue().toString();
}
#Override
public Point getToolTipLocation(MouseEvent e) {
return p;
}
};
}

Add mouse event to JMapViewer mapMarker

How can I add mouseListener to a MapMarker (MepMarkerDot or MapMarkerCircle) that makes it like button?
I tried this soloution but it makes whole map clickable (mouse Event works on all the map).
You're on the right path to start with TrashGod's MouseListener solution, but you need to add a little more code, the key part being, that you need to get the Point location of where the user pressed, something the MouseEvent#getPoint() method will tell you, and then based on that information, and the bounds of the "active" area of the component decide whether to respond. Something like:
#Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint(); // this is where the user pressed
if (isPointValid(p)) {
// do something
}
System.out.println(map.getPosition(e.getPoint()));
}
private boolean isPointValid(Point p) {
// here you have code to decide if the point was pressed in the area of interest.
}
Note that if your code uses Shape derived objects, such as Ellipse2D or Rectangle2D, you can use their contains(Point p) method to easily tell you if the point press was within the Shape or not. Or if there are several locations that you want to check, you may have a collection of Shapes, iterate through them within your mousePressed or (if you have it) isPointValid method, and check containment within the for loop.
I found this nice example:
https://www.programcreek.com/java-api-examples/index.php?source_dir=netention-old1-master/swing/automenta/netention/swing/map/Map2DPanel.java
It has an interface MarkerClickable and its own LabeledMarker which implements MapMarker and MarkerClickable:
public boolean onClick(final Coordinate p, final MouseEvent e) {
for (final MapMarker x : getMap().getMapMarkerList()) {
if (x instanceof MarkerClickable) {
final MarkerClickable mc = (MarkerClickable)x;
final Rectangle a = mc.getClickableArea();
if (a == null)
continue;
if (a.contains(e.getPoint())) {
mc.onClicked(e.getPoint(), e.getButton());
return false;
}
}
}
return true;
}

Java Custom Button (not JButton) Problems

Ok, so, what I've been trying to figure out is how I can make a custom MouseListener for all my buttons that would not require listing every single one of them in the Handler, because I'm going to have a lot of them. Here's the code I have in my Listener as of now:
package com.dinobuilding.handler;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.menufeature.Button;
public class ButtonHandler implements MouseListener {
public BLANKWindow dbw;
public BLANK Screen dbs;
static Button button = new Button();
public int buttonX = button.x;
public int buttonY = button.y;
public int buttonSizeX = button.xSize;
public int buttonSizeY = button.ySize;
public ButtonHandler(BLANKWindow dbw, BLANKScreen dbs) {
this.dbw = dbw;
this.dbs = dbs;
}
public static void setButton(Button b) {
button = b;
}
public int mouseEventX;
public int mouseEventY;
Graphics g;
public void mouseClicked(MouseEvent e) {
mouseEventX = e.getLocationOnScreen().x;
mouseEventY = e.getLocationOnScreen().y;
if(mouseEventX <= buttonX && mouseEventX >= buttonX + buttonSizeX) {
if(mouseEventY <= buttonY && mouseEventY >= buttonY + buttonSizeY) {
button.onClicked(dbs, dbw, g);
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
And here's the code in the first button that I'm trying to implement:
package com.BLANK.menus;
import java.awt.Color;
import java.awt.Graphics;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.handler.ButtonHandler;
import com.BLANK.menufeature.Button;
public class MainMenuPlayButton extends Button {
public static int x;
public static int y;
public static int xSize;
public static int ySize;
public static String s;
public static Graphics g;
public MainMenuPlayButton(int x, int y, int xSize, int ySize, String s, Graphics g) {
super(x, y, xSize, ySize, s, g);
this.x = x;
this.y = y;
this.xSize = xSize;
this.ySize = ySize;
this.s = s;
this.g = g;
setColor(new Color(0, 226, 26));
draw();
}
public MainMenuPlayButton() {
}
public static void draw() {
drawButton(x, y, xSize, ySize, g, s);
ButtonHandler.setButton(new MainMenuPlayButton());
}
public void onClicked(BLANKScreen dbs, BLANKWindow dbw, Graphics g) {
setColor(new Color(216, 0, 0));
}
I think my main problem is that the code in the ButtonHandler gets called before the code in the Button class and therefore the ButtonHandler is utilizing the Button class itself, not the MainMenuPlayButton class. If you need the Button class as well, simply tell me, however I can't imagine why. Thank you in advance!
Edit
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
EDIT 1:
Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so...
EDIT 2:
It would seem that the getX method does not work either. If you could help me on that, I would very much appreciate that.
If you want to get the object that was pressed and tripped the MouseListener, use the MouseEvent's getSource() method. For example, this might work:
public void mouseClicked(MouseEvent e) {
(YourButton) button = (YourButton) e.getSource();
button.onClicked(...);
}
Other bits:
Rename your class from Button to something else, since the Button name clashes with the java.awt.Button class, and this can cause difficult to debug errors.
I cringe any time I see a Graphics field declared in a class, as it suggests possible inappropriate painting. Make sure that you really know what you're doing if you ever use one of these as a field since it's easy to get image loss or a NullPointerException if not used correctly, since the Graphics object is frequently changed by Java, and this change is completely out of your (the programmer's) control. Don't say that you haven't been warned.
Edit
Regarding your comments:
Yes, I do know what I'm doing with the Graphics field, however, if it makes you feel better, know that it's only temporary and I will be changing it to something else later.
OK, I've just been burned on this before. As long as you get it from a BufferedImage and don't try to get it by calling getGraphics() on a component or by pulling it out of a paint or paintComponent method, then you might be OK.
Also, I'm pretty sure that I'm getting the object it clicked correctly, but I can't get it to access the correct subclass of Button. It's only getting the Button class itself, not the MainMenuPlayButton.
Sorry, but this doesn't make sense since you don't get "classes" when you obtain a reference, an object pure and simple, and in fact you would get the very same object that the ButtonListener was added to and that tripped the listener, and the class of this reference will be whatever class your button is. I am assuming that you're adding your MouseListener directly to your "Button" object, correct? Again, time to do some debugging.
Edit 2
Regarding the most recent edit to your question:
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
No, there is no need to hard-code each button, trust me. That's the whole reason for using listeners that are added to the buttons.
EDIT 1: Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so... the
There's one of your problems. If you want to listen to your buttons, you're going to want to be able to register listeners on the button itself. If you have an array or collection of them registering listeners is easy. And no, I don't recommend using x and y on screen since it makes your program extremely fragile. If you did this, any changes to the structure of your GUI would require subsequent hard-code changes to your x and y handling. Ugh.
This begs the question of why create your own Button class, and why not instead use JButtons or a subclass of JButtons. You appear to be re-inventing the wheel, but (sorry to be blunt) creating one that is square.
Edit 3
But you cast the variable to a button, meaning that if I have multiple buttons I have to cast each and every one of them to a different thing.
No absolutely not as the magic of polymorphism should work here. But they're objects of the same type, no? Or do you have many different subclasses of your Button class? And regardless, inside of the mouseClicked(...) method, you appear to want to call only one method on your button, onClicked(...), which I imagine has to be an object of the super class, right? So by calling this method on the current button, It should call its own correct code.
The problem I have with JButton is that they already exist. I can't edit them and I can't customize them, ...
This is patently not true. You can change their appearance and behaviors by many means, including by subclassing or by a factory creation method. Plus they already come with the machinery for being able to register listeners and respond to mouse actions.
...Also, would I have to register/make a new handler for each and every one of the buttons?
Again, you appear to be forgetting that polymorphism should take care of all of this. One handler should do, depending on how well-behaved your code is.
I am going to have a LOT of buttons, and I don't think that that would be a viable solution. If not the getX how would I get it to do something when the thing is clicked?
I've given you my recommendation, other than sometimes it is better to re-write sections of code if the design can be improved, meaning again you may want to consider retrofitting your code to use JButtons.

Java mouseclick logger

Hi I want to build on java mouse click logger. I need to print the coordinates of mouse clicks in a file. Can you tell me how I can make this. Which APIs to use some examples or links. I need to get all the mouse clicks not only in one window.
you could implement the MouseListener interface and overwrite the mouseClicked function:
public class MyMouseListener implements MouseListener {
// [...]
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(e.getLocationOnScreen());
}
// [...]
}
Adapt that example to your needs. THe getLocationOnScreen Method returns a "Point" object which you can ask for x/y coordinates.

Update a BufferedImage in a JFrame

I have a BufferedImage displayed in a JFrame through my own class. I opted to display the BufferedImage using my own class so I can scale it. My paintComponent and update
public class MyBuffIm{
public void paintComponent(Graphics canvas) {
if (bi == null) {
} else {
//bi, maxWidth, and maxHeight were passed to constructor
canvas.drawImage(bi, 0, 0, maxWidth, maxHeight, null);
}
}
public void update(Graphics canvas) {
super.update(canvas);
if(bi != null){
//Got this from some tutorial in the net.
//Done out of desperation :|
paintComponent(bi.getGraphics());
}
}
}
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
In any case, I have the following code in my Runnable (does not work as I expect it to):
BufferedImage p = SomeMyBuffIm.getBuffIm();
Vector<Point> randomPixels = getRandomPixels(500);
int limit = randomPixels.size()
for (i = 0; i < limit; i++) {
Point rp = randomPixels.get(i)
p.setRGB(rp.x, rp.y, Color.red.getRGB());
}
SomeMyBuffIm.repaint();
mainFrame.repaint(); //JFrame call to repaint
I'd like to think that, since I'm scaling my image, I just can't discern the difference between the new and old images. But I've tried the largest values for getRandomPixels still to no effect. My test image, by the way, is just a white sheet so red pixels should stand out in it.
Anything wrong I'm doing?
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
No you should NOT override update(). You would do that with AWT but not with Swing.
If you update the BufferedImage then all you need to do is invoke repaint() on your instance of the MyBuffin class.
If you need more help than post your SSCCE that demonstrates the problem.

Categories