Expandable component to hide or unhide another component - java

I am wondering if there is a Swing-component which is able to be expanded, so that I am able to hide or unhide something like a menu.
As an example something similar can be found in MS Outlook:
This is the default look, where all mail folders are unhidden. But clicking on the little arrow (circled red) hides that view:
I would like to have something similar in my Java-GUI to do the same, while the included component should be hidden by default. I am not sure what component should be under that expandable "tab", but right now I am thinking about a JTree.
This is what I am generally trying. But if you want a bonus cooky, you could consider the requirement that this expandable menu has to expand in a flowing, smooth animation, instead of being hidden or unhidden instantly. The latter can be found in TeamViewer for example. There you have a menu bar on top, which can be hidden or unhidden, while it's going up and down in a smooth animation.
Example, TeamViewer:
EDIT
First I tried the JSplitPane, but moving all existing components to fit the split pane schema was not a solution I would prefer. Instead I was looking for something more independent.
The next thing I tried was using Swing Timer to expand the width of the JFrame using its setBounds-method. It works exactly the way I want when it comes to toggling additional space for a menu. The JFrame gets bigger or smaller while the resizing process is animated. But I can see two disadvantages of this approach:
The animation is kind of slow and not perfectly smooth. I removed the delay. It is quite OK so far, but a more smoother solution is preferred here. But I can totally live with it how it is currently.
A big disadvantage is that the increasing of the size leaves black spaces between the old and the new width for half of a second. If anyone knows how to avoid that, I would have my perfect solution to this problem.
To make it clearer what I mean with "black spaces", see:
Now you can see that black area. Like I said, it only remains for half of a second or even less. With Swing Timer I added 100 pixels to the width of the JFrame. The higher the value I add to the width, the higher the black area. If the JFrame's width is completely resized, everything is in the correct color again.
So does anyone know why this happens? Is this hardware related or is it just simply a standard behavior of Java or Swing? Does anyone know solutions or workarounds for this?

See splitpane.
For example
JSplitPane mainSplitPanel = new JSplitPane();
mainSplitPanel.setDividerLocation(650);
mainSplitPanel.setOneTouchExpandable(true);
For samples click here

The solution which fit the best for me can be found in the edited part of my question. I found a good combination of delay time and frame resizing which appeared smooth enough (1 millesecond delay and increasing the width with 45 pixels). The issue with the black frame is not problematical anymore. Now the black screen is even shorter in its duration, and if the user waits around 2 seconds, the black area won't be displayed (visibly) at all. In that case it's OK for me, because the user should spend some seconds after expanding anyways.
For everyone who wants to know more about this black area while resizing JFrames, see here.
The code of the solution I described in my edited question:
final Timer timer = new Timer(1, null);
timer.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt)
{
double width = myFrame.getBounds().getWidth();
if(isExpanded == false)
width += FRAME_PIXEL_CHANGE;
else
width -= FRAME_PIXEL_CHANGE;
if(myFrame.getBounds().getWidth() >= FRAME_SIZE_EXPANDED && isExpanded == false)
{
myFrame.setBounds(FRAME_X, FRAME_Y, FRAME_SIZE_EXPANDED, FRAME_HEIGTH);
btnExpand.setIcon(new ImageIcon(GUI.class.getResource("/img/close.png")));
timer.stop();
isExpanded = true;
}
else if(myFrame.getBounds().getWidth() <= FRAME_SIZE_REGULAR && isExpanded == true)
{
myFrame.setBounds(FRAME_X, FRAME_Y, FRAME_SIZE_REGULAR, FRAME_HEIGTH);
btnExpand.setIcon(new ImageIcon(GUIMain.class.getResource("/img/expand.png")));
timer.stop();
isExpanded = false;
}
else
{
myFrame.setBounds(FRAME_X, FRAME_Y, (int) width, (int) FRAME_HEIGTH);
btnExpand.setBounds((int) (width-36), 246, 36, 36);
}
}
});
return timer;

Related

JFrame scaling for high resolution screens

I have a non resizable Jframe of size 1280x800. Of course this size appears bigger and smaller according to the resolution of the screen. (It has a background image). Now, if i try this on lets say a 4k monitor, it would be absolutely impractical because to small. Isn't there a way to scale the JFrame? Or a solution to this problem? What i thought i would do is write bigger jFrames and tell the main class which one to open according to the resolution. I am sure there is a much more elegant way to do that, since i guess it is a problem that many would have come across!
What a nightmare! Please help me!
Thank you
One way you could achieve that is by getting the screen size of the device, and then setting the size of your JFrame accordingly:
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
double jFrameWidth = screenDimension.width * 0.7;
double jFrameHeight = screenDimension.height * 0.5;
Or if you just want to maximise the JFrame you can use:
jFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
Detect the resolution of the window you're launching on and scale the frame to a percentage of that window. Have a baseline dimension (1280 * 800) so it isn't too-squashed on smaller screens.
As an example I pull the local GraphicsEnvironment, I pull the data from each relevant GraphicsDevice into a data class that I wrote myself, and I use that throughout my project as it gives me all sorts of stuff like buffer strategies, window dimensions, and so on. I do this when the application is loading (using a SplashScreen) which affords me control over the whole process.
That's about as elegant as you can get, I think.
EDIT
Editing in some example pseudocode to give an idea of what I'm getting at. I write primarily in Java, but I'm not doing this in an IDE so it won't necessarily be compile-ready:
public void scaleWindowDimensions(JFrame frame, GraphicsDevice gd) {
Rectangle bounds = gd.getDefaultConfiguration().getBounds();
int screenX = (int) bounds.getWidth();
int screenY = (int) bounds.getHeight();
// substitute this for however you're setting the size of the JFrame; this is simply how I sometimes do it
frame.getContentPane().setPreferredSize(new Dimension(screenX, screenY));
}
This is a very quick example that will set the size of your JFrame to that of the monitor it's running on. You'll need to modify the background image you're using as well. There's a lot more you could do with this but I'm keeping it simple on purpose.

Use components as JProgressBar on java game

Been building up a little game in java, already asked a few questions about the usage of JPanel in it, and used them to paint the graphics and the main part of the screens.
Now i have a little doubt about other components. My intention is to add on the corner a pair of bars to show health and mana of an entity (like in a rpg game), and wondered which was the best approach for it.
Thought about making a new JPnale with a pair of JProgressBar to set the ammount of it, but then i wondered if it would be better to paint it completely and fill a pair of rectangles.
I mean, doing a pair of new JProgressBar() for it, or a pair of g.fillRect() and then paint the ammounts.
I guess that easiest is to set the JProgress, as i can set values and text if i want, maybe, but not sure about it and if it would run smoother without overwhelming it with JComponents.
Also, if want to add buttons would be better the JButton, or paint a rectangle and check for containment of the mouse pointer with an event (I have this approach at some points where there is not KeyBinding). Should i change that?
Thank you beforehand :)
I'm writing an answer because i haven't got enough reputation to comment :(
I think is better if you paint it in your graphics engine. Use Rectangles is of course a better idea than use a new JPanel with JProgressBar.
But i think that it's even better if you use Images to build your own Progress Bar.
You can create them or find them on internet.
For example you can take an Image for the Progress Bar Background, and another Image for the Foreground (the part that will fill the Bar). Then you can set their X and Y position and then just change the Foreground Width in relation with the entity health to fill or empty the Progress Bar.

Java: Painting multiple objects to one frame

I've been working on a java game recently, and I have a lot of it figured out. One thing still plagues me, however. The way it's set up, a player moves across a background (the game board). Currently, every time the player moves, it repaints the whole frame, including the background. This causes a brief, yet annoying screen flicker whenever the player moves.
I've separated out my code to draw the background separately from the things that need to be repainted:
public void drawMap(Graphics pane) {...}
public void drawPlayer(Graphics pane) {...}
The problem is that I can't find a way to make the board stay on the screen when I use repaint(); , a necessity for the player to move. Any suggestions?
You should look into double buffering, basically you paint an image to the buffer, then paint the buffer. It should remove the flickering effect you are talking about. Below are a few helpful links:
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering
http://www.ecst.csuchico.edu/~amk/classes/csciOOP/double-buffering.html
Just comment if your having trouble understanding it.
UPDATE: I would also suggest you look in 'Killer game programming in java'. You can get a free ebook of one of the older versions. Some of it is a bit out dated, but the first few chapters about setting up a game loop and drawing to the screen etc are still very much relevant.
UPDATE 2: From the second link, try something like this:
private void drawStuff() {
BufferStrategy bf = this.getBufferStrategy();
Graphics g = null;
try {
g = bf.getDrawGraphics();
drawMap(g);
drawPlayer(g);
} finally {
// It is best to dispose() a Graphics object when done with it.
g.dispose();
}
// Shows the contents of the backbuffer on the screen.
bf.show();
//Tell the System to do the Drawing now, otherwise it can take a few extra ms until
//Drawing is done which looks very jerky
Toolkit.getDefaultToolkit().sync();
}
UPDATE 3: This post here gives a nice code sample that you can play with and adapt, that should give you the best idea on how to do double buffering
I suggest to avoid redrawing everything with every change. Instead draw the whole frame at a fixed interval, e.g. every 50ms. Just keep the status of every element in a class and if something changes just change the data value. Due to the fixed redrawing interval the display will pick up any changes at the next redraw.

Mouse movement optimizations

I want to have a game where the view will move around as the mouse reaches the outer edge of the window (similar to many RTS games). I have read that there is significant overhead when using the MouseMotionListener.
Is there perhaps a way of having a second transparent component within the game window (JPanel) that does not affect game-play, but will register when the mouse leaves the inner component via MouseAdapter.mouseEntered()/mouseExited()?
boolean mouseOnScreen;
boolean mouseWithinInnerComponent; //is (10 <= mouse.x <= screenWidth - 10) && (10 <= mouse.y <= screenHeight)
if(mouseOnScreen && !mouseWithinInnerComponent)
{
//do something...
}
I am at a loss for how to determine which screen boundary was crossed without having to have four of the above mentioned components overlapping at the corners to form a border around the screen which can detect if the mouse is at any edge or corner. This I imagine to be fairly expensive (having to check each component while running the game)...
boolean mouseOnScreen;
boolean mouseWithinTopComponent; //is (0 <= mouse.y <= 10)
boolean mouseWithinBottomComponent; //is (screenHeight - 10 <= mouse.y <= screenHeight)
boolean mouseWithinLeftComponent; //is (0 <= mouse.x <= 10)
boolean mouseWithinRightComponent; //is (screenWidth - 10 <= mouse.x <= screenWidth)
if(mouseOnScreen)
{
if(!mouseWithinBottomComponent)
{
//move view up
}
if(!mouseWithinTopComponent)
{
//move view down
}
if(!mouseWithinLeftComponent)
{
//move view right
}
if(!mouseWithinRightComponent)
{
//move view left
}
}
Exactly how much overhead exists with MouseMotionListener? Would this or a similar method perhaps be more efficient if the detections only need to be made along the borders of a game window?
NOTE: This will be used in windowed mode as well as possible full-screen application.
I have implemented the same thing you need using a MouseMotionListener. I'm not really sure why you think it will add overhead... If you add one and simply ask each of its methods to print to the console (which is slow) and move your mouse around, you will see it is pretty snappy from the user's point of view.
My implementation consists of 4 main pieces: a scroll pane, rectangular regions, a timer, and a MouseMotionListener.
First, I created a panel, called AutoScrollPane, that extends JScollPane. Even though it is a JScrollPane, you can hide the scrollbars. This allows me to leverage functionality for moving a viewport around on a map or similar like in an RTS game as you say.
Second, for the scroll regions, I actually have 8: n, ne, e, se, s, sw, w and nw (i.e. "north", north-east", etc.), with the diagonals allowing diagonal scrolling. I implement them simply as Rectangles. They aren't drawn on the screen or anything - I just instantiate 8 rectangles in my class sized appropriately and with coordinates that match the regions of the window. I actually allow my window to be resized, so I resize the rectangles if necessary.
Third, I have a timer that can be turned on and off. When it is turned on, every "tick" generates a Runnable. This Runnable's job is to scroll the panel's viewport in the appropriate direction a certain distance. Each Runnable is handed to the Swing event queue.
Finally, I have a MouseMotionListener. It's job is to intercept mouse enter, exit, and move events. Each time it receives an event, it checks the current mouse location and whether it intersects one of the rectangles. Based on which rectangle, it chooses a direction to scroll. It keeps track of whether the mouse was in a scroll region on the previous event or not. Based on this information it knows whether it should start scrolling, stop scrolling, or just let whatever is happening continue. I wanted my scrolling to stop if the mouse goes outside the pane, thus the use of the exit/enter events. Anyway, to start scrolling, the listener saves off the direction and distance to scroll and tells the timer to start. When it is time to stop scrolling (such as when the mouse exits a scroll region), it tells the timer to stop.
It took a while to pick the right timer granularity and scroll distance for smooth scrolling, but it does work pretty well. I hope this outline provides some help.
I think it was Martin Fowler that espoused that premature optimisation is the root of all evil in software development. Why not try the MouseMotionListener and only think about optimising if you find that it affects the performance of the game.
There is nothing wrong with a MouseMotionListener When you read about the overhead it was probably one specific exmaple
Anything you can do in any programming language can be done bad or wrong.
If you pay attention to what you do in your listener all should be fine

Raw Java 2D implementation of a scrollbar

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

Categories

Resources