I implemented my own JFreeChart XYToolTipGenerator and, as the chart it is used on is almost full screen, sometimes the tooltip position (on screen) hides the point it is related to (e.g. in the bottom right corner, since it seems that tooltip is configured to be positioned South-East of the mouse / data point). This is a problem because the user needs to be able to click on the chart's data points (as it generates a specific action).
Is there a way to either define dynamically the position of the tooltip (e.g. for data points bottom right I would ask the tooltip to be shown North-West) or, alternatively, to define a systematic position (e.g. North-West instead of South-East as it is by default)?
This problem has given me headaches for the last few days - any help or hint is more than welcome.
Many thanks!
Thomas
Here's the answer I posted on the JFreeChart forum:
JFreeChart is using the standard Swing tool tip mechanism. In the ChartPanel class, the getToolTipText(mouseEvent) method is overridden to return the appropriate text for the tooltip, and that's it.
Swing also gives you the option to override the getToolTipLocation(mouseEvent) method, and that's probably what you need here.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm trying to set up a pane such that objects placed within that pane use a coordinate system other than JavaFX "scene pixels". For example,
1024 units in my coordinate system might correspond to 1 "scene pixel"
(is there a better name for the units that JavaFX uses?). However: The
objects that are inside the objects that I add to the pane need to
work in "scene pixels" (for example; Labels seem to want to work in
pixel positions when rendering text).
The gist below shows a simple example of the setup I'm looking for, but it has problems.
I create one container group (actually a Pane) that adds a transform
such that 1 unit == 32 pixels. I add objects to this container. Each
object I add has an external pane with a size and position specified
in units, and an internal pane that solely exists to invert the scale
of the transform of the external pane. Inside this internal pane, I
can add Labels and so on and these all render correctly.
I set up bindings between the transforms so that I can effectively
scale and pan the view inside the pane by adjusting the transform on the group container. However: Something about this setup seems to be confusing
something inside JavaFX; the results I'm seeing onscreen don't seem to
match what JavaFX believes the bounds of various objects are. This
causes visual issues when I try to do things like set borders on
objects, and also seems to confuse ScenicView.
https://gist.github.com/io7m/20b071e11da2dcd96896a43fad6df644
Here's a shot with the container group selected (looks correct):
Here's a shot with the external pane of the bottom object selected:
Note that, although the object actually renders onscreen as the right
size (one of the pale grey boxes), ScenicView seems to believe that the
object's bounds are 1x1: They are 1x1, but they're 1x1 when expressed
in my custom coordinate system, not in JavaFX "scene pixels". You can just barely see this in the screenshot: There's a tiny single pixel in the top left corner of the object that ScenicView is highlighting to show what it thinks the bounds are.
Here's a shot with the internal pane of the bottom object selected:
This looks correct in the sense that the bounds encompass the label and
nothing else.
Am I doing something wrong here? I can't tell if I'm basically abusing
transforms or not.
I am doing something very similar in my projects. In contrast to your approach I am not using panes. I only use groups instead and haven't noticed any problems so far. Maybe there is just a bug in ScenicView.
I don't know whether this is relevant for you too but at least in my case I also had to apply the inverse scaling to all relevant shape attributes like, e.g., the stroke width. I only wanted to have the placement of the outer geometry to be scaled but I still wanted to specify the stroke width in pixels.
This can quite easily become very complicated to handle but technically I have not experienced any problem with this approach.
This program will have an infinite canvas (ie as long as the user scrolls, it becomes bigger) with a tiled background image, and you can drag and drop blocks and draw arrows between blocks. Obviously I won't use a layout manager for placing blocks and lines, since they will be absolutely positioned (any link on this, possibily with a snapping feature?). The problem arises with blocks and lines. Basically I'll have two options:
Using a simple layout for each building block. This is the simplest and clearest approach, but does it scale well when you have hundreds of objects? This may not be uncommon, just imagine a database with 50 tables and dozens of relationships
Drawing everything with primitives (rectangles, bitmaps, etc). This seems too complicated (especially things like text padding and alignment) but may be more scalable if you have a large number of objects. Also there won't be any event handler
Please give me some hints based on your experience. I have never drawn with Java before - well I did something rather basic with PHP and on Android. Here is a simple preview
DISCLAIMER
You are not forced to answer this. I am looking for someone who did something like this before, what's the use of writing I can check an open source project? Do you know how difficult it is to understand someone else's code? I'm talking about implementations details here... Moreover, there is no guarantee that he's right. This project is just for study and will be funny, I don't want to sell it or anything and I don't need your authorization to start it.
Measuring and drawing text isn't such a pain, since java has built in classes for doing that. you may want to take a look at the 2D Text Tutorial for more information. In fact, I did some text drawing computations with a different graphics engine which is much more primitive, and in the end it was rather easy (at least for the single-line drawing, for going multiline see the previous link).
For the infinite canvas problem, that's also something I always wanted to be able to do. A quick search here at stackoverflow gives this which sounds nice, althought I'm not sure I like it. What you can do, is use the way GIMP has a scroll area that can extend as you move - catch the click of the middle mouse button for marking the initial intention to move the viewport. Then, when the mouse is dragged (while the button is clicked) move the viewport of the jscrollpane by the offset between the initial click and the current position. If we moved outside the bounds of the canvas, then you should simply enlarge the canvas.
In case you are still afraid of some of the manual drawing, you can actually have a JPanel as your canvas, with a fixed layout. Then you can override it's paint method for drawing the connectors, while having child components (such as buttongs and text areas) for other interaction (and each component may override it's own paint method in case it wants to have a custom-painted rect).
In my last drawing test in java, I made an application for drawing bezier curves (which are basically curves made of several control points). It was a JPanel with overidden paint method that drew the curve itself, and buttons with custom painting placed on the location of the control points. Clicking on the control point actually was clicking on a button, so it was easy to detect the matching control point (since each button had one control point associated with it). This is bad in terms of efficiency (manual hit detection may be faster) but it was easy in terms of programming.
Anyway, This idea can be extended by having one child JPanel for each class rectangle - this will provide easy click detection and custom painting, while the parent will draw the connectors.
So in short - go for nested JPanels with custom drawing, so that you can also place "on-canvas" widgets (and use real swing widgets such as text labels to do some ready drawing) while also having custom drawing (by overriding the paint method of the panels). Note that the con of this method is that some swing look-and-feel's may interfere with your drawing, so may need to mess a bit with that (as far as I remember, the metal and nimbus look-and-feel's were ok, and they are both cross-platform).
I am looking for ways to zoom in a Java Swing application. That means that I would like to resize all components in a given JPanel by a given factor as if I would take an screenshot of the UI and just applied an "Image scale" operation. The font size as well as the size of checkboxes, textboxes, cursors etc. has to be adjusted.
It is possible to scale a component by applying transforms to a graphics object:
protected Graphics getComponentGraphics(Graphics g) {
Graphics2D g2d=(Graphics2D)g;
g2d.scale(2, 2);
return super.getComponentGraphics(g2d);
}
That works as long as you don't care about self-updating components. If you have a textbox in your application this approach ceases to work since the textbox updates itself every second to show the (blinking) cursor. And since it doesn't use the modified graphics object this time the component appears at the old location. Is there a possibility to change a components graphics object permanently? There is also a problem with the mouse click event handlers.
The other possibility would be to resize all child components of the JPanel (setPreferredSize) to a new size. That doesn't work for checkboxes since the displayed picture of the checkbox doesn't change its size.
I also thought of programming my own layout manager but I don't think that this will work since layout managers only change the position (and size) of objects but are not able to zoom into checkboxes (see previous paragraph). Or am I wrong with this hypothesis?
Do you have any ideas how one could achieve a zoomable Swing GUI without programming custom components? I looked for rotatable user interfaces because the problem seems familiar but I also didn't find any satisfying solution to this problem.
Thanks for your help,
Chris
You could give a try to the JXLayer library.
There are several tools in it, which could help you to make a zoom. Check the examples shown here. I would recommend you to read more about the TransformUI, from this library. From the example, it seems like it could help solving your problem.
Scaling the view is easy enough; transforming mouse coordinates is only slightly more difficult. Here's an elementary example. I'd keep JComponents out, although it might make sense to develop an analogous ScaledComponent that knows about the geometry. That's where #Gnoupi's suggestion of using a library comes in.
hey you can try this if you want to zoom a image like any other image viewer the use a JPanel draw an image using drawImage() method now create a button and when you click the button increase the size of the panel on the frame it appears as if the image is being viewed in Zoom
You might find Piccolo2D.java API useful: http://code.google.com/p/piccolo2d/
It is very simple.
It touts in particular its smooth zooming. You essentially make a "canvas" that can contain various elements, and can then zoom by just holding right-click and panning the mouse back and forth.
I worked on a team that used it to create this: http://sourceforge.net/apps/mediawiki/guitar/index.php?title=WebGuitar#EFG.2FGUI_Visualizer
The nodes you see there are clickable links themselves.
Since Java 9, there are VM arguments (actually meant to be used for high dpi scaling) that can render a application with a higher scaling factor:
java -Dsun.java2d.uiScale=2.0 -jar MyApplication.jar
Or:
java -Dsun.java2d.win.uiScaleX=2.0 -Dsun.java2d.win.uiScaleY=2.0 -jar MyApplication.jar
We are currently using Eclipse Draw2D/GEF for an information page describing a process in our application. This basically consists of a matrix of large squares, each containing a matrix of smaller squares. We originally had all the squares as GEF objects, but because of the large volume of them being shown, we found that this did not scale very well and the view took a very long time to open. We then changed it so that only the large squares are Figures and we then draw the smaller squares using the graphic in paintFigure.
The problem that we are running into is that we still want the tooltip to change depending on which small square you are hovering over. I tried to do this by adding a mouseMotionListener and setting the tooltip, through setTooltip, depending on where the mouse currently is. The problem is that once the tooltip is displayed, it does not change any more when setTooltip is called.
Does any one know of an alternative way of doing this? Is there a way of getting the viewpart's PopupHelper and using that? Any help would be appreciated.
Thanks
Hmnn.. interesting problem. Since you paint your own Grid within the Figure, I would think that you have two options.
Try posting SWT events to fool Eclipse. I'd try a focus lost followed by a focused gained, to trigger tooltip machinery, at which point you could get the coordinates and display the appropriate contents.
Don't use the Figure#getTooltip strategy at all. Just show your own composite.
To dynamically change the tooltip, you can hold an instance of the tooltip Figure in your parent Figure. In the constructor of the parent Figure, create a new tooltip Figure (e.g. a Label) and use setToolTip() method to set the tooltip Figure to parent Figure.
When data model is changed, the updated tooltip text/icon can be set to the tooltip Figure. Then you just call setToolTip(tooltipFigure) method again.
You can have a method like:
protected Label toolTipLabel;
protected void updateToolTip(String text, Image icon){
toolTipLabel.setText(text);
toolTipLabel.setIcon(icon);
setToolTip(toolTipLabel);
}
The updateToolTip() method can be invoked in parent Figure's conturctor to initialize the tooltip. And this method can be invoked each time after the data model is changed.
I encountered the same problem in my code and solved it with that method. In my code, I invoked the updateToolTip() in the parentFigure.paintFigure() method.
How would I go about writing my own scrollbar using standard Java 2D.
I really don't want to use swing, and I've already made up my own component parts for everything else such as buttons etc.
I'm not really looking for code, rather the math involved in the event changes and the drawing.
Why on earth would you want to write your own java GUI toolkit? You already have the choice of Swing and SWT, can you really do better than these two teams?
If you've already written the rest of the toolkit, I don't understand why the scrollbar would stump you. Without knowing anything about your event system, or how your custom components are structured, it's impossible to give much advise. I don't see this being particularly maths intensive - just maintain the height of the scrollable component, and the view it's in, and the scrollbar size should match the proportion of the component that is visible. The position of the scrollbar should match which part of the component is visible (this will have to be scaled). Specifically, what do you want to know?
Java is now open. I'd go look at the source for the Swing and/or SWT as they are already implemented. The math seems fairly straight forward. You have a Bar and a Container. To simplify we will only discuss length (the dimension in which the scrollbar moves). The container is of a certain length. The bar is of a length that is equal to or less than the container. It is useful to define the center and the two endpoints of the scrollbar. You can have the scrollbar start at 0 at the top and 1 at the bottom or 0 at the top and 100 at the bottom with the important part being defining your scrollbar in the same manner. Then you can check the endpoints for collision with the edge to stop the bar from moving. If the mouse is held down with the cursor over the coordinates inside the bar, the bar starts caring about where the cursor is and will paint the scrollbar and whatever the scrollbar is ultimately supposed to be affecting. So, you would take the page to be affected and map it to 0 and 1 * the scale in pixels of the scrollbar. Then you get to worry about the arrows at either end and how big of a jump each click is and dealing with mousedown events etc.etc. Use what is given don't reinvent the wheel.
While not Java2D, this straightforward code snippet might help:
http://processing.org/learning/topics/scrollbar.html