I realize that there's another question relating to "infinite" JScrollPanes, however I think that what I'm looking for is something that is subtly different.
Basically, I have a collection of objects which can be dragged in any direction, and the extent of the scrolling viewport should always encompass the bounding rect of all those objects. To put it another way, the document has no fixed "origin". Thus, if you drag an object to the left, off the edge of the screen, then the viewport extent should expand in the negative direction to encompass that object's new position. (It should also auto-scroll as you drag, but that's a separate problem I realize.)
I'm not sure how to do this using the JScrollPane API, which seems to want you to set the preferred size of the underlying component, but doesn't seem to have the concept of an offset or origin for that component. (The underlying JViewport seems like it would be able to do it, but I can't really figure out the JViewport API.)
The scroll pane and view port actually have nothing to do with it. What you need to is change the preferred size of the view ports view and let the scroll pane/view port take care of this rest.
Basically, what you need to do, is calculate the widest and highest points on your component and invalidate the view port, to force to recalculate it's layout requirements.
Create yourself a custom component (using a JPanel for example) and override the getPreferredSize method. This method should return the required size of your component.
When the size requirements change, call revalidate()
OK so it turns out that the simple answer is that scroll panes cannot scroll to negative coordinates. What you have to do, as #MadProgrammer suggested, is maintain a separate offset coordinate which is a Point. The offset stores the top/left coordinates of the entire document. When rendering individual objects, set the transform of the Graphics2D object such that they are shifted down and to the right by the offset amount, so that all object are drawn at coordinates that are positive numbers even though in reality they may be located at negative coordinates. Similarly, when calculating the preferredSize for the scroll pane, add in the offset to the document width and height. Coordinates from scroll bar events also need to be offset as appropriate.
This allows you to maintain the illusion that the document bounds are not constrained to be positive numbers, and the document's boundary can expand infinitely in any direction.
Related
I am working on a game engine mostly using ECS (not pure ECS) and I've run into a problem.
Some entities will need a Bounds component (e.g. a component that has a Rectangle that represents position, width, and height). Like buttons.
Many entities also need a component that contains the position but not necessarily bounds.
How do I reconcile the overlap?
1) If an entity has both a Bounds component and a position component, there will be two positions. Not good
2) Entity only has Bounds component which inherits from position component. Ugly because I have to override the utility methods like translate from the position component and have it update the bounds object's position. Also then the entity won't have a position component, which is weird.
3) Bounds component just contains width and height. I don't like this because then I can't use things like a Rectangle class to represent the bounds.
Any ideas? Thank you.
I would go for 3, with a requirement to have a Transform component if you have a Bound component and express the bounds in local frame.
Using a Rectangle with lower-left and upper-right corners would still make sense since the origin of the bounds are not always the same as the origin of the component.
I'm using JChart2D for visualization. I would like to make the X and Y axis equal in terms of pixels. By doing so its much easier to see how far the points are from each other in euclidean distance (see image). As it is now, the x-axis is more stretched out. They already have the same range in terms of values.
The framesize defines the pixel values right now, i.e:
jFrame.setSize(800,600);. Everything then dynamically fits inside the frame where the Chart2D resize itself to make space. I find the pixels manually, but that seems stupid. Also, if i have a scenario with a lot of clusters, the legends line will wrap and thus resize the chart.
I've googled a lot and looked at the documentation, but I've been unable to find a solution.
So how do i set the chart to a fixed size, that's independent from the other items in the frame?
Image example:
What do you expect if you would make it and still insist on the JFrame to be non-rectanguar to be displayed in the remaining 200 px in x range? The void grey?
You could achieve this e.g. by setting a GridBagLayout to the JFrame.getContentPane() and define a grid of two vertical cells - one grid to take 600px x 600px and the second to take 200px x 600px. But then you have the void in the 2nd pane. HTH, Achim
By doing so its much easier to see how far the points are from each
other in euclidean distance
not really, the Euclidean Distance requires at the end the position of the 2 points you are calculating and you have it... otherwise you wouldnt be able to plot anything in the canvas..
another aproach that you can use is implement a ViewPort over the canvas but that makes sense only for zoom in/out images and tht is not your case...
I have written a hex viewer.
However, I found a limitation in Swing. If you have a 3GB file and you're rendering at 20 pixels per row, the total height of the component is:
(3GB / 16 bytes per row) * 20 pixels per row = 3.75GB
At this point, Swing fails to render anything because the value overflows Integer.MAX_VALUE.
This is my best idea so far:
Clone enough of Java2D and JComponent to make an alternative to JComponent which does all rendering in long coordinates.
Clone JViewport so that you have a way to render the view of the component/
Put that alternative JViewport into a JScrollPane like you would normally do.
This seems like a lot of work, but such a component might be useful for things like large diagrams or large text documents.
I considered just paging it, but it seems like it would be awkward when you're using the Find feature and it matches text crossing a page boundary.
The (non-Java) hex viewer I normally use (Hex Fiend) doesn't use paging either. It just scrolls the whole height of the document as if it's not a problem.
Does anyone know a good way to get around this sort of thing?
You don't need to draw your hex viewer in long coordinates because you only need to draw the part of the file that you want to be visible at the moment. JScrollPane is a very useful tool for scrolling around large components, but you don't need it. If you want to scroll through so much stuff that it's troublesome to have a component big enough to hold it all, then you can simply do the scrolling by making a JScrollBar and painting your component according to the position of the scroll bar.
I have a graphics application in JAVA, which is made up of many different shapes (lines, circles, arcs, etc, which are drawn via the Graphics.drawLine(), drawArc()... methods). I would like to create mouse-over events on many, if not all of the drawn objects.
What I was thinking was to store some sort of bitmap with metadata in it, and use that to figure out which object the mouse is over. Is there a way to do this in Java? (looping through all the objects per mouse move doesn't seem viable).
Thanks,
John
Key-color solution
(moved from comment)
Create an off-screen graphics buffer (like BufferedImage), same size as subject image.
Draw all objects into this buffer. Each object with one own color. Depending on object count you can optimize image buffer: For example use 8-bit graphics.
Read resulting image buffer by pixel (example Java - get pixel array from image). Determine pixel color at current mouse position, and map color index (or RGB value) to the source object.
Pros:
The solution is "pixel-accurate": Object boundaries are exact - pixel to pixel.
Easy to solve overlapping objects problem. Just draw them at the desired order.
Object complexity is not limited. Theoretically bitmaps are also possible.
Cons:
To move one object, the complete off-screen buffer must be repainted
Number of objects can be limited when using low-bit image buffer
It depends on your specifications. You do not mention if those shapes are allowed to overlap, to move, how many of them can exist etc.
Solution a) The easiest approach that comes to mind is to implement each shape as a JComponent descedant (e.g. JPanel). So you would have a CirclePanel, an ArcPanel etc that extend JPanel and each one of them paints itself in the same way it is being done now.
Having the shapes as a JComponent allows you to add a MouseListener to each panel that would then handle the mouseEntered(), mouseExited() events.
Solution b) If on the other hand you need to draw all the shapes on a single component's area (as I understand is the case now) then you still do not need to iterate over all the shapes. You just need to introduce an algorithm to categorize the shapes based on their position, to be able to exclude them fast inside your "isMouseOver(Shape s)" test procedure.
For example lets say you divide the area to 2 equal sub-areas left and right (let's call them tiles). When you create each shape you test which tile they intersect to, and you store this information both in the shape and in the corresponding tile.
Now when you need to test if the mouse is over a shape, you decide which tile the mouse is over. This way you only have to check shapes that intersect either the left or the right tile. Assuming that your shapes are distributed uniformly on the screen, you have just rejected 50% of the shapes with one test.
Depending on how many shapes you have, you could use 4 or 8 tiles, or you could even create/delete tiles dynamically (e.g. based on how many objects tend to gather in one area of the screen or not).
I would suggest to try the first solution because it is easier and a cleaner approach. If you decide that it does not fit your needs, you could then go for an approach similar to the second one.
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