Raw Java 2D implementation of a scrollbar - java

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

Related

Java AWT setLayout(null) doesn't seem to be working

I'm trying to re-purpose an existing Java AWT (stand alone) application to run on dedicated, single-purpose hardware (think a kiosk in a museum that also controls hardware behind the scenes) and my presumption that if I simply set the layout manager on my main panel to null I'd be able to lay out items using something like Rectangle(starting x, starting y, x-width, y-height) or perhaps another similar method to position things, has proven false! So, I'm more lost than I thought I would be!
Here are a few excerpts:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
[...]
public class myGUI extends JFrame
{
JPanel MainPanel = new JPanel();
JMenuBar Menu = new JMenuBar();
int MaxWidth = 1920;
int MaxHeight = 1080;
Dimension FullScreen = new Dimension(MaxHeight, MaxWidth);
Rectangle recHZbar = new Rectangle(0, 32, MaxWidth, 4);
[...]
MainPanel.setLayout(null);
MainPanel.setPreferredSize(FullScreen);
MainPanel.setEnabled(true);
MainPanel.setBackground(LightBlue);
There are all manner of components totaling around a hundred or so and it makes no sense to present them here. Suffice to say that I'm trying to eliminate what were stand-alone frames and instead present all the data around the edges of a very large screen and then manage the center space of the screen separately with key data, hopefully able to use visibility to switch what the user sees (instead of panes / panels), since in many cases there's a lot of commonality.
I thought that by setting the layout manager to null I would then be able to position components on MainPanel using something like this horizontal bar with a message embedded in it:
JLabel HorizontalBar = new JLabel();
HorizontalBar.setBackground(DarkBlue);
HorizontalBar.setFont(new java.awt.Font("Dialog", 0, 10));
HorizontalBar.setForeground(LightBlue);
HorizontalBar.setPreferredSize(dimMxW10pt);
HorizontalBar.setOpaque(true);
HorizontalBar.setHorizontalTextPosition(SwingConstants.CENTER);
HorizontalBar.setText(HZBarTxt);
HorizontalBar.setBounds(recHZbar);
MainPanel.add(HorizontalBar, null);
... And this, of course, works, BUT, when I tried to position this horizontal bar (via setBounds(rectangle)), it's apparent that the coordinates are based off of the bottom of the JMenuBar I added earlier, and NOT from the upper left corner of the screen! This has me rather concerned! (I presume the next bar will be based on the space below the first one, etc?!) Am I correct in thinking I've got a layout manager I didn't (explicitly) ask for? (If so, how do I avoid it?)
I'm hoping I'm overlooking something simple to be able to do positioning myself without having to go through too much work. If I can't just pick where I want things to be on the screen, I'm going to be in trouble on this project! I'm hoping to avoid lots of little panels and such. I need to create irregular columns and so forth. I know I can do the math to lay things out how I want, and I'm loathe to trust a layout manager to get it right, especially since the testing on the actual production hardware is very hard, and if the layout manager is different, it'll mean trouble. I may well be I'm overlooking the right layout manager - the "do it yourself layout manager", perhaps? - but I don't see how "GridLayout" is going to work for me, at least, not easily. So I'm hoping to learn how to do my own layout as simply and directly as possible (which is what I thought I was already doing).
TIA.
It turns out that my original assumption that the call to setLayout(null) hadn't worked was itself mistaken, and that's a good thing!
Given MY requirements, I made the exactly correct choice of NOT using a window manager at all. Yes, it can easily be seen from the comments to the question that many people think it's foolhearty or even stupid to NOT use a window manager, but in my case I made the EXACTLY right choice, and here's why:
THIS PROJECT'S circumstances are one of the rare cases for "doing it yourself", and, indeed, if I'd used a window manager it would NOT have worked out _AT_ALL!_ ...at least not in the time I had available.
A brief review of the use-case for this project
This was for dedicated hardware control and, indeed, it could not run in production in any place but a very singular installation of specialized hardware that the Java code is providing a user-interface for. Further, it won't have any internet connection, ever, and will never be upgraded. There's ZERO concern over either operating system or other software upgrade - it just cannot happen. As it has a singular fixed running environment, there's no concern over font-change handling or anything like that.
The Application Design; WHY A Layout Manager Would Screw It Up
I chose to use one frame, "undecorated" so that if fills the entire display, like this:
This fills a 1090 X 1920 display completely, so IDK how well it will go here.
I created a JFrame that serves as a backdrop for the whole thing. Within it, I first created a menu bar, followed by a heading / title bar, and for these things, a layout manager could have done a great job, of course, but that's the end of the easy part.
I created a right and left column of necessarily different widths and then a section at the bottom just by placing the items using item.setBounds(X, Y, W, H). I used variables for the values, and used them to create standard row & column positions, widths and heights. This provided for easy shifting from the standard in places that required it; I'd just use a different set of variables (using a naming convention I invented to keep it easy). I'd imagine that you COULD have used a layout manager for this part, but it would have been tedious and it's not at all clear it would have been any less work. In particular, how do you get the two vertical columns do be where you want them? You'd have to create separate inset panes / panels for each differently formatted region within each column - and even the bottom rows! You'd have to get them to stack or space just right, too. Then there are those vertical and horizontal bars - how'd you do that?
Vitally, I left room for an inset panel in the center, of which there are a VERY large number (!!) way more than are apparent from what you can see in the sample image. They're JPanels, only one of which is visible here, of course. And this is where a layout manager would completely fall on its face. Good UI design keeps things consistent and so users can know where to expect to find various things. And on the various panels, there are things that are common among some panels and different on others with DIFFERENT commonality, and there are yet more panels that cross with commonality between different sets of panes, yet few of the panels are really full enough that the common layout manager packing algorithms could handle; Various items are - and need to be - in what may appear to be non-standard positions for various reasons, so using a layout manager would have required filling up the panes with lots of sub-panels and such so that each of the various layout managers could do their jobs properly. By NOT using a layout manager, and thereby being free to just exactly specify the different positioning of the components when looking at different inset panes, I was able to VERY SIMPLY just use panel.add(item) syntax to move items between panes and keep the position exactly. Further, because of the same top position of the outer panel and the inner ones, getting rows exactly right was a cinch!
This was hands-down the easiest approach. I would have been fighting the damned layout manager all along the way. ...DO NOT BE AFRAID TO SKIP A LAYOUT MANAGER AND DO IT YOURSELF, just be prepared to do the whole job yourself. If you're up to that task, and if you have a fixed-use-case situation like I had, it's not so bad at all, and it might even be the only practical way for some tasks.

Java Swing Gridlayout: Accessing Specific Coordinate

I'm creating a Java swing GUI and I have formatted a JPanel to use a GridLayout. I need to access a specific "box" (i.e. specific coordinate) of the grid, but I cannot see a way to do so.
How can I do this?
You shouldn't depend on GUI code (the View) to give you information about program data (the model). The best solution would be to "know" which component is where from the start--maybe you should have a data structure (2D array?) that holds the components and is updated whenever something's added to the grid.
If you want a quick and very-dirty fix, though, you could start playing games with JPanel.getComponentAt(). This requires pixel coordinates, though, so you'd need to do some reverse-engineering to figure out how much space a given grid square takes up. The space between grid squares is given by your GridLayout object. This is not recommended whatsoever though. I'm just including it in the interest of completeness (and since it's a more literal response to your question).
In GridLayout, "The container is divided into equal-sized rectangles." You can add an empty, transparent component in places you want to appear empty, e.g. new JLabel(""). See also GridBagLayout and Using Layout Managers.

Suggestion for implementing a drawing program - UML designer

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).

Zoom in Java Swing application

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

Can I set a window in Java so it has uniform resizing (ie. a square)?

I've seen several applications window's only allow the user to resize it in the diagonal direction, so it must maintain its square shape.
Is it possible to specify this constrain using swing/java?
I haven't heard of anything built in to do that. You could add a componentListener and from the resize events in that trigger resizes of the window to keep it square.
Personally, I would attach a ComponentListener to the window and in the componentResized method check the new window size and set the width equal to the height or vice versa.
Probably not the most efficient way though...
You should be able to modify the resize event handlers to increase both dimensions rather than just the one.
Resizing of a JFrame is handled by the OS, so it will be difficult to control unless you use a ComponentListener as suggested by all the other answers.
However, if you are talking about a JWindow, then resizing is NOT supported automatically and you need to provide support for this. Resizing Components entry might help you get started. I think you would need to make two changes:
a) limit the dragging to the diagonals
b) change the "drag distance" to be the maximum of the width/height drag distance and use that value for both future calculations.
Since I don't know if this is your real requirement, I won't go into any more detail.

Categories

Resources