JFrame scaling for high resolution screens - java

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.

Related

Expandable component to hide or unhide another component

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;

Pixels to dips, desktop and android

I am using Libgdx to code an android game and as you may know, many screen resolutions cause some problems if done incorrectly. So I am trying to use this DP unit rather than pixels.
However, I have this method here:
public static float pixelToDP(float dp){
return dp * Gdx.graphics.getDensity();
}
the Gdx.graphics.getDensity() method actually gets the SCALE, so it's already done for me.
Now the problem, libgdx is cross platform which is good for testing. When I launch this on my S4 which has a resolution of 1920x1080 with a dpi of a whopping 480, opposed to my terrible and overpriced laptop which has 1366x768 # 92dpi it is placed exactly where I want it. On desktop it is way off, a good few hundred pixels on the X and Y axis.
Is this due to the fact my screen dpi is measured #92dpi, the resolution is a lot lower and the actual game is not fullscreen on the desktop?
Here is the code for drawing the object:
table.setPosition(MathHelper.pixelToDP(150), MathHelper.pixelToDP(200));
In order to get it perfect on desktop I have to do:
table.setPosition(MathHelper.pixelToDP(480), MathHelper.pixelToDP(700));
Which is not even visible on my phone, since the scale is actually 3x, which puts it a good 200 pixels off the screen on the Y axis.
Is there a way around this? Or am I basically going to have to deal with doing platform checks and different blocks of code?
Possible solution:
So I changed my dp conversion method, if I was to do 100 * 0.5 it would return a new value of 50 but in reality I want the orignal value of 100 + 100 * 0.5.
Not sure if this is a proper fix or not but regardless by table is drew in the exact same place on both laptop and phone:
public static float pixelToDP(float dp){
if(Gdx.graphics.getDensity() < 1)
return dp + dp * Gdx.graphics.getDensity();
return dp * Gdx.graphics.getDensity();
Is this just a cheap fix or is this pretty much how it should be done?
Usage of density independent pixels implies that the physical size of the table on all screens should be same. Since your laptop screen is (physically) much bigger, you would see the table to be lot smaller than expected.
I would suggest an alternative approach of placing objects in fractions of size. e.g. 30% of width or 45% of height.
To implement this, just assume a stage resolution and place objects as you like then change viewport in resize method such that you get full view.
Hope it helps.
For more,
https://code.google.com/p/libgdx-users/wiki/AspectRatio
The best approach for this is to manipulate the density based on the execution target.
So what I usually do is to store the density in a field in a singleton, and set it based on the scenario:
public class Game {
public static float density;
public static initDensity(){
if (GDX.app.getTarget() == 0){
density = 2.0f;
}else {
density = GDX.graphics.getDensity();
}
}
public float toPixel(float dip){
return dip * density;
}
}
with this approach you can "simulate" a more dense screen then you actually have, and by using properties in your run config like -Ddensity=2 and System.getPropery("density") you can vary the screens you like to simulate.
One approach is having a fixed viewport size. Create your camera for example 1366x768 and place all your objects using that coordinate. Then the camera will fill the whole screen of every other resolution.
cam = new OrthographicCamera(1366, 768);
try seeing few tutorials....I personally think it is best to deal with pixels and using the camera will help you a lot, check this link once
getting different screen resolutions

Display JFrame Centred on main monitor when using dual screens

I am trying to write some code to center my main application JFrame in the center of the computer screen using Java. To do it I am using the code below, which divides the process into two part, this is just because I use the ScreenHeight and ScreenWidth for scaling purposes elsewhere in the class and they are properties of the class.
This code works, on my laptop and other single screen machines perfectly, but on my main machine, which is dual monitor, it places the screen in the centre of the workspace which puts half the dialogue box (which can be small) on each screen. It's in a method, so that I can call it each time the dialogue boxes size, is changed by the program.
I use the boolean Width value to keep the screen in the same location on the vertical axis, but to center it on the horizontal.
// Finds the size of the screen
private void find_ScreenSize() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension dim = toolkit.getScreenSize();
ScreenHeight = dim.height;
ScreenWidth = dim.width;
}
// Centres the dialogue box within the screen
private void centre_Frame(JFrame Frame, boolean Width) {
find_ScreenSize();
if (!Width) { // if you are not justifying on the X axis
Frame.setLocation(Frame.getLocationOnScreen().x,
((ScreenWidth / 2) - (Frame.getWidth() / 2)));
} else {
Frame.setLocation(((ScreenWidth / 2) - (Frame.getWidth() / 2)),
((ScreenHeight / 2) - (Frame.getHeight() / 2)));
}
}
I would like to be able to center the dialogue box in the center of the main/first screen on any multi screen computers. The dialogue boxes in my application, that I don't control the location of, manage to do what I am trying to do for example my JOptionPane and file open and save dialogues all work perfectly.
I am developing on Linux, but the application is for use on Linux and MS platforms.
Searching for this problem gives me lots of examples of the above but nothing that shows me how to do what I want, any help would be appreciated.
Thanks in advance for any help.
frame.setLocationRelativeTo(null);
should work (doc). At least it does on my multi monitor setup. Note that the window is always displayed on the center of the main monitor, even if the app is launched from the secondary monitor.
You can use GraphicsEnvironment.getCenterPoint to find the center point rather than calculating youselves.
If you want to display in a specific monitor, see Show JFrame in a specific screen in dual monitor configuration

Create image file with java

I was trying to create a rectangular image where will be 2 things.
A label (100% width and 20% height)
A Text Area (100% width and 80% height)
So lablel will be at top and text area will be at bottom
so I tried to create a JFrame and place both components there. Then I am creating its image with JFrame.createImage(width, height) and in last I used ImageIO.write(). but problem was, There was some extra blank space around the components in Image. When I tried to set its bound then it create an exact image but this image works perfectly on Windows but it doesn't work on Mac. Any idea why?
Is there also another easy way where I can achieve this. I've spent 2 days but couldn't found any solution.
Please advice
Thanks in adnvace
Rendering using Swing components is very versatile, but the user interface delegate for each component varies by platform. Similarly, font metrics also vary by platform and vendor. If you need very fine control over the placement of text, you can access the graphics context's font metrics as seen in this example, and you can mitigate aliasing as shown here.

SWT Image concatenation or tiling / mosaic

I have an Eclipse RCP application that displays a lot (10k+) of small images next to each other, like a film strip. For each image, I am using a SWT Image object. This uses an excessive amount of memory and resources. I am looking for a more efficient way. I thought of taking all of these images and concatenating them by creating an ImageData object of the proper total, concatenated width (with a constant height) and using setPixel() for the rest of the pixels. However, the Palette used in the ImageData constructor I can't figure out.
I also searched for SWT tiling or mosaic functionality to create one image from a group of images, but found nothing.
Any ideas how I can display thousands of small images next to each other efficiently? Please note that once the images are displayed, they are not manipulated, so this is a one-time cost.
You can draw directly on the GC (graphics context) of a new (big) image. Having one big Image should result in much less resource usage than thousands of smaller images (each image in SWT keeps some OS graphics object handle)
What you can try is something like this:
final List<Image> images;
final Image bigImage = new Image(Display.getCurrent(), combinedWidth, height);
final GC gc = new GC(bigImage);
//loop thru all the images while increasing x as necessary:
int x = 0;
int y = 0;
for (Image curImage : images) {
gc.drawImage(curImage, x, y);
x += curImage.getBounds().width;
}
//very important to dispose GC!!!
gc.dispose();
//now you can use bigImage
Presumably not every image is visible on screen at any one time? Perhaps a better solution would be to only load the images when they become (or are about to become) visible, disposing of them when they have been scrolled off the screen. Obviously you'd want to keep a few in memory on either side of the current viewport in order to make a smooth transition for the user.
I previously worked with a Java application to create photomosaics, and found it very difficult to achieve adequate performance and memory usage using the java imaging (JAI) libraries and SWT. Although we weren't using nearly as many images as you mention, one route was to rely on a utilities outside of java. In particular, you could use ImageMagick command-line utilities to stitch together your mosaic, and the load the completed memory from disk. If you want to get fancy, there is also a C++ API for ImageMagick, which is very efficient in memory.

Categories

Resources