How to scale images in an SWT TableItem? - java

I have been struggling to get the images displayed in an SWT TableItem to scale. I have a listener which scales the fonts correctly, and I have confirmed that the images being set into the TableItem are correctly scaled. I know that the scaled images are being successfully set into the TableItem, because I can even change what image gets displayed. But the new image is always displayed at the original scale.
I have read in SWT: The Standard Widget Toolkit, Volume 1 where the authors state:
The First Image Defines the Size of
All Images in the Control
Due to a Windows limitation, just like
ToolBar, TabFolder, and Tree, Table
scales the images it displays to be
the size of the first image inserted
into the control.
The behaviour I'm seeing is the most extreme case suggested by this quote -- images in the table seem to be being scaled, not the the size of the first image in the table, but to the size of the first image ever to have been in the table. Can anyone confirm or refute this? Does anyone have any more detailed information about the behaviour of images in TableItems? Is this restriction really the show-stopper it seems to be?
And in particular, if I go down the path of custom drawing table items (Custom Drawing Table and Tree Items), am I likely to bump into any further showstoppers?
(You'll note what a good job I'm doing of gritting my teeth and not giving way to rage at having to deal with Windows stupidity even when using a supposedly cross-platform development environment!)

I can confirm this in my experience on Windows.
I propose one of two solutions:
Use custom table drawing as per the link you mentioned. It's a little annoying but not more than 2 hours of work I'd say to learn and implement it.
Use an alternative SWT table control e.g. Nebula Grid or KTable which do not share the same platform limitations of Table on Windows
Edit: in response to "And in particular, if I go down the path of custom drawing table items (Custom Drawing Table and Tree Items), am I likely to bump into any further showstoppers?"
The only issue I found with custom drawing is that it's best to know ahead of time what the maximum row height will be, otherwise there will be jumping when Table has to increase the row height and therefore scroll items a bit while it readjusts

Related

Libgdx Pixellated GUI Effect

In LibGDX, I am currently trying to achieve the effect of a pixellated GUI, meaning the buttons are pixellated, like an 8-bit theme.
When I make my GUI elements, such as a TextButton, I am using images that are small, say 34x16 pixels, but I am rendering them on a large resolution like 1920x1080. What is the best way to render such a small image at a high resolution?
My thoughts were to use stage.setViewport(WIDTH,HEIGHT), and set the width and height to a scaled down resolution, so the gui elements wouldn't be so big. This works, however when adding elements things go wrong.
This my stage/table currently, using a scaled down resolution. I am adding widgets using to the table like this:
table.add(playButton);
table.row();
table.add(title);
but as you can see, the table.row() makes a row that is much too large, perhaps a row fit for a larger resolution. Is there any way to change the gap that is made by the row? I would have thought that the gap would be zero, and by using table.add().pad() you could change the gap, but I am not doing any of that.
Any help would be greatly appreciated.
Ninepatch
This is a common issue in all apps. To overcome this, images which can be safely resized in parts are used. they are called ninepatches.
Here is a nice Tutorial about using them in libgdx.
Distance Field Fonts
Although you haven't mentioned it here, you'd also find font sizing (pixellated fonts) as an issue. For that Distance Field Fonts are used.
Hope this helps.
I would say don't worry about scaling them up and making the virtual resolution bigger. If you want to see picture still pixelated when you scale it use Texture filter. For your case you want to use Nearest filter. use it like this:
yourTexture.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
where yourTexture is the texture that you have all your bitmaps and skin elements on. If you are using texturePacker than you can specify the filter before packing too. Or just open the .pack file and on the top you will see filtering options, and edit those to Nearest.

CPU/Memory Efficiency in Multi-tabbed Map/Tile Level Editor (many HashMaps/ArrayLists)

I'm developing on a machine from 2008, and unfortunately cannot upgrade at the moment. I really need to optimize performance in this tool I am building.
My entire project is fairly large, and I'm currently creating my own Map Editor for use to create Maps for my main project later on down the road. It's fairly simple, and is being designed to load, save, and edit Arrays of 'Tiles' possessed by a Map. It's basically a 2D-Map Editor, customized for my needs.
When a Map is loaded into the Editor, its Tileset (one large BufferedImage), is broken down into each individual Tile (with a smaller BufferedImage), loaded into the right side of the GUI into a large bunch of JLabels with icons. I've used various Swing LayoutManagers to achieve my desired positioning.
Inside the MapCanvas area, essentially the same thing is done. Each Tile, whether empty or not, has a JLabel with an Icon, loaded onto the Grid. I've asked around before about whether using Swing components would be more efficient than using Java2D to design and draw, and the consensus was that it didn't really matter (and to be honest, Swing probably does it better than what I would write myself).
I believe my problem is stemming from the way that I interconnect each JLabel and their icons.
My goal was to reduce the number of duplicate Icons I have to create, which in theory should reduce memory usage and CPU usage. Tiles in the Editor are interacted with as follows:
If no tile is selected to be 'stamped,' there will just be an alpha composite of a color painted over the JLabel's icon to denote that it is being hovered, and will revert upon a MouseExit
If there is a tile on the active Stamp tool, that tile's image will replace the JLabel's icon -temporarily- to denote that it is being hovered, and will revert upon a MouseExit
If there is a tile on the active Stamp tool, and a JLabel is clicked, that JLabel's icon will be set to the active Stamp tile "permanently" unless reverted
If the option to have Grid Lines is toggled on, each JLabel's icon will be processed through the ImageFactory to have dashed lines running along the top and left edges (forms a grid, as seen in the picture)
If the Zoom level is changed, each JLabel's preferredSize is set to accomodate, and the icon has to be resized in the ImageFactory (grid lines applied depending)
Upon loading a Map into the Editor, each JLabel is created, given its corresponding BufferedImage (be that empty or not), and thrown into the Map's field ArrayList. The preferredSize is set so the Layout looks right, and it is added to the MapCanvas (which is just a JPanel).
I created various ArrayList and HashMap objects, so that I could pass a JLabel as a Key, and get back a BufferedImage. That way, when hovering iver a JLabel, the MouseEvent can send the event's source back to the listener, and it can grab the correct BufferedImage based on the JLabel it receives. The image can then be processed by my ImageFactory class in one of the ways listed above.
So basically when a JLabel recieves a MouseEvent, this happens:
MouseEvent sends source JLabel to ActionListener
Listener uses source JLabel as Key to grab desired BufferedImage chunk
BufferedImage chunk is then processed accordingly (which could be a color Alpha composite, a Zoom factor applied to it, or grid lines added to it, or a combination of these)
Is there any better way to do this? This doesn't take any noticeable toll on my 2 year old Laptop, but there is very noticeable lag when the Mouse interacts with the JLabels on my older Desktop machine.
Seeing as I will be actively developing on both, I want the environment to run smoothly, and if that means I have to be stricter on memory and CPU usage, then so be it.
But I can't really seem to come up with a system that is more memory efficient.
Are the ArrayLists and HashMaps the problems? Are the many image operations the problems?
I've taken advantage of JLabel's "setName(String)" method in various ways already (for example, each JLabel has a name containing its location in the single-dimension Array of JLabels, and its x-and-y coordintes on the graph, i.e. "maptile#24:1,9"), but that requires iterating through Arrays, and my hope was that specifically grabbing the BufferedImages with Keys would be more efficient.
Java collections are dynamic, meaning they resize as you add data. The actual model for their sizing function (used by ArrayList and presumably HashMap) is something similar to when they reach capacity they double their capacity, which consists of declaring a new block in memory and copying across all the stored data.
If you know the maximum possible size for each of your HashMaps and ArrayLists you may benefit from using the constructors that take an initial capacity. Here & Here This will prevent them using more memory than necessary. And will prevent any possible delays from increasing capacity.
You may also benefit from reading the top few paragraphs of the documentation for each type as they can provide good explanations of efficient usage (e.g. HashMaps loadfactor).
It may also be useful for you to consider other types of List and Map (if you are not aware of the difference in their implementations), e.g LinkedList has far more efficient delete and insert operations than ArrayList, however it is much slower for random access to an index than an ArrayList as it must traverse each prior index to reach the desired index, whereas an ArrayList can directly access the desired index.
However it's hard to guess how noticeable any changes you make based on these recommendations would be.

How can I implement custom maps with provinces in Android?

Ok, so I have this map and I have various sliders on the right. After changing slider values and pressing 'Execute' button, some provinces in the map below should change colour.
However, I don't know how to implement the map below. I have used 33 png drawable for each province. I have set them all to have a same big rectangle dimension so that they'd align themselves.
I am getting an 'Out of memory on byte allocation' error.
I assume this is because of all the large drawables I have.
I'm new to android and I want to ask, is there a way to implement this without the error?
Also the map should always be displayed on the left side of the screen so the images always have to be visible.
I would recommend making a SVG and changing the colors programmatically.
Graphics are hard to scale and are heavy space users, scalable graphics are slim, look great everywhere (device size and dpi) and easy to manage (single file instead of 33).

Java / Swing how to deal with different screen DPI and density settings?

Hi everyone I've recently come across the problem that now days some monitors have different DPI settings, some monitors are much more dense such as, for example, Apple's Retina displays.
How would one compensate for the different DPI settings and densities on various monitors with Java? Is it possible to scale the controls to be the same size on any monitor. I know when programming for Android all measurements are in "DP" and you can specify different images for three different display densities.
Is there a way I could choose different images using Java / Swing for different display densities so my application doesn't look blurry on higher density monitors? Or is this not that important or possible? I know Chrome currently doesn't take into account DPI but Internet Explorer and other apps do.
Thank you for your help, I'm a long time Java developer I've just never thought about DPI before and was wondering how I might go about it :)
First, trust the platform's Look & Feel designers to choose sensible default sizes for text and controls. Then, avoid the temptation to frustrate those defaults. Here are some heuristics:
Use layouts; when contemplating absolute positioning, consider a custom layout.
Respect the preferred size of components.
Avoid non-resizable components.
In animation, scale graphics to the size of the enclosing Window.
Test across a range of platforms, using emulation as required.
First thanks trashgod for the useful links you provided for they were very helpful.
Below I have listed some specifics on how to deal with issues concerning DPI changes that I have run into.
Font Issues:
If the font is not fitting in the component then look at Component Sizing Issues below for often the component is not sizing to what is inside. Otherwise in a JLabel you can apply HTML tags to automatically line wrap the text (there are other solutions but this works for me).
If the component's text is naturally the default font, size, and style (Tahoma 11 plain) then everything is automatically done for you. Know that user574171 gave pictures showing different font and layout managers issues and strengths in his link to http://kynosarges.org/GuiDpiScaling.html in his answer to How to set the DPI of Java Swing apps on Windows/Linux?. This question here is asking about the "Swing" issues but his link is useful in also comparing WPF, JavaFX, and Swing layouts with a basic components and different fonts. You can see there the "Swing a" font is the best, that is Tahoma 11 Plain. However it only works if the component is naturally the default font, size, and style (Tahoma 11 Plain). This means bolding, underlining, sizing, and a different font for the text will throw off the auto sizing for different DPI.
If the text is the default font (Tahoma) but bolded, underlined, or a different size then the text does not scale for different DPI's. To fix the scaling for different DPI's then check the box labeled "Derive the font from the default font." The "Relative" option will take the default DPI scaling font and apply your relative changes such as bigger or smaller, bold, and underlined. Also know that if the component is a JLabel then DPI scaling is automatic using HTML tags despite how you format the text (line wraps too).
If the component is not naturally the default font, style, and size (Tahoma 11 plain) or you want a different font (ie not Tahoma) then you need to associate the changes in another component that is naturally the default like a JLabel. Therefore if 125 DPI increases the font by 3 then you increase your desired font by the same.
Component Sizing Issues:
All components have a preferred, minimum, and maximum size properties but I have found that they do not play well with DPI changes. The "Respect the preferred size of components" bullet in trashgod's answer tells you all about it. To summarize let the default size of the component take care of itself for it will try to size to whatever is inside.
If the component can use the default sizes then DPI handling can be done for you. Just as trashgod's said "First, trust the platform's Look & Feel designers to choose sensible default sizes for text and controls. Then, avoid the temptation to frustrate those defaults." Again, the component of the default size usually sizes to what is inside (or acts re-sizable). From my own experience when I set re-sizable components I do it via "Horizontal Resizable" or "Vertical Resizable" for I have found it works very well with DPI changes as well as window resizing.
If the default size does of the component does not work then first try looking below at some specific issues I found. Alternatively try scaling the component according to changes in a component that does get scaled right. IE, apply ratio of what you expected the scaling component to be at 100% DPI and the change to the new DPI. Examples of components that need to be scaled to other component changes would be one that it's text is filled by code or it is an image.
As a last resort use a JScrollPane to allow the user to scroll to see the whole thing. If the window/dialog is fairly large then a JScrollPane is a great idea because if the DPI is higher for the user's eyesight then the window often is bigger than the screen.
Note:
I have found that encapsulating groups of components in a JPanel helps swing handle DPI changes a lot better.
JTextField Size Issues:
Set the columns property and nothing else but the text if you wish. The columns property is the number of letters or numbers you want to show. Typically used when allowing the user to enter a number. Know that the columns property works great for multiple platforms.
JSpinner Size Issues:
Set the model to be accurate, valid, and default values. Therefore the auto-sizing of the component is done for the max value and works great for DPI changes and other platforms.
Table Row Height Issue:
Table row height does not change with higher DPI. I encountered this issue and it seems to be due to me trying to be compatible with older versions of Java. To fix multiply the change in font size ratio or change in JLabel height ratio due to the DPI change.
Use JRE 9 (or greater).
This is because the Java runtime (older versions) declared themselves to be "DPI-aware" but didn't really supported it for AWT and Swing. Java applications were sized and rendered based on pixels rather than being properly scaled, this included HiDPI displays.
Anyways, this has been recently solved.
See the issue JEP 263: HiDPI Graphics on Windows and Linux
and the upgrade.
So, increasing the font size does not work (because it does not increase the rest of the things); the jvm argument -Dsun.java2d.dpiaware=false does not work (because it is not really supported); and the manifest file + registry edit (for Windows) just does not work.
Then, You need to run it on JRE 9 because it really supports this feature.
By using
System.setProperty( "sun.java2d.uiScale", "1.0" );
in your java code, ui scaling should be deactivated.

Stop OSX from Automatically re-Sizing JComboBox?

I created a program that deals with combo boxes, and I ran across a problem a Mac user showed me. Mac apparrently resizes JComboBox's and JButton's even if I set the width. The width of all the combo boxes on Windows are different since they are supposed to, but on OSX it's all the same width and size making it impossible to read half the entries of in the combo-box because it's all cut off when you try to select a selection. How can I fix or prevent this?
So my question is, how do you stop an operating system from auto-resizing the swing tools, or how do I make the selections in the JCombBox's readable and not cut off to like "Boxes" instead of "Bo...?"
As shown here, don't set the width; that is the purview of the UI delegate, com.apple.laf.AquaComboBoxUI. Instead, let the JComboBox calculate it's own preferred size based on the font metrics that inevitably vary from one platform to another.
If you still have problems, this example may form the basis for your sscce.

Categories

Resources