How can I add "proper" images (not Icons) to my JFrame/JPanel/JComponents (Swing) (Kotlin) - image

Language: Kotlin,
GUI Library: Swing,
IDE: IntelliJ IDEA
I know that there are similarly phrased questions, but note that I want to add multiple images, not just one, to any type of JComponent that holds other components. For example, I am not concerned with adding an image to a JLabel, I already know how to do that. I want to know how to add an image to a JFrame, JPanel, Container, etc.; all things that hold other Components (and have an add(Component) function). Finally, I don't want that workaround where you add the image to a JLabel with no text and then add that to the container. I would like to just use the Image class or a subset like BufferedImage or URL.
I want to be able to call the add() method from the Container class, jFrame.add(component) for example, where component is some sort of image. I want this to result in an image being displayed on the screen.
The ImageIcon class is not a Component so this can't be input on its own. I think I would have to create some sort of custom Image class that extends from Component or JComponent, but I don't know what I would have to override to get that to display an image on screen when added to another JComponent. There are multiple solutions to this, but to clarify, I don't want some kind of "middle man" where I add a JLabel or JButton or something that only contains an Icon. I don't want to display icons anyway, I want to display full-sized images anywhere on the screen. I will provide a possible example of what I want the final result to look like.
class MyApp() {
fun init() {
var jFrame = JFrame()
jFrame.add(Image("filepath/image.png"))
//Some other JFrame boiler plate
jFrame.isVisible = true
}
}
fun main() {
MyApp().init()
}
The unclear part is the Image class, and whether that's a custom class that inherits JImage, or some already defined class or method I don't know about. I know about ImageIO and BufferedImage and ImageIcon, but none of them directly go into this method, as they don't inherit Component or JComponent.
EDIT:
I tried using Camickr's second solution, but it didn't work. I will post the code to see if a made a simple mistake.
import java.awt.Image as AWTImage
import java.awt.Image.*
//Including these imports as I used name alias so I had to say what it was from.
open class JImage(var point: Point = Point(0, 0), image: AWTImage): JComponent() {
var image: ImageIcon = ImageIcon(image)
override fun paintComponent(g: Graphics?) {
super.paint(g)
g?.drawImage(image.image, point.x.toInt(), point.y.toInt(), null)
}
}
class SplashScreen(image: JImage): Frame() {
init {
//jFrame.isUndecorated = true
jFrame.add(image)
}
}
class MyApp {
fun init() {
var jFrame = SplashScreen(JImage(image = ImageIO.read(Loader().getClassLoader().getResourceAsStream("resources/images/splashscreen/SplashScreen.png"))).getScaledInstance(Size(1000, 1000*3/5)))
jFrame.isVisible = true
}
}
fun main() {
MyApp().init()
}
FINAL EDIT:
Okay, so I did make a simple mistake when trying this solution. I overrode paintComponent() but then inside it, I called super.paint(). Additionally, I realized I didn't have to use the ImageIcon class, which I didn't want to do anyway. This is the Image class I have come up with.
open class JImage(var point: Point = Point(0, 0), var image: AWTImage): JComponent() {
fun getScaledInstance(size: Size, scalingMethods: ScalingMethods = ScalingMethods.DEFAULT): JImage {
val scale: Int = when(scalingMethods) {
ScalingMethods.DEFAULT -> SCALE_DEFAULT
ScalingMethods.FAST -> SCALE_FAST
ScalingMethods.AREA_AVERAGING -> SCALE_AREA_AVERAGING
ScalingMethods.REPLICATE -> SCALE_REPLICATE
ScalingMethods.SMOOTH -> SCALE_SMOOTH
}
return JImage(point, image.getScaledInstance(size.width.toInt(), size.height.toInt(), scale))
}
override fun paintComponent(g: Graphics?) {
super.paintComponent(g)
g?.drawImage(image, point.x.toInt(), point.y.toInt(), null)
}
}

I want to know how to add an image to a JFrame, JPanel, Container, etc.
You don't add an image to a JFrame, JPanel etc. As you said an image is not a component. You add the image to a JLabel and add the label to the panel. This is the easiest and more direct way to display an image at its actual size.
Don't know if Kotlin is any different, but the other option is to do custom painting and paint the image on a JPanel by overriding the paintComponent(…) method and using the Graphics.drawImage(…) method and then add the panel to the frame. Read the Swing tutorial on Custom Painting for painting basics.
You can also check out Background Panel for an example that paints an image as a background of the panel. The image can be:
painted at its real size
scaled to fill the panel
tiled to fill the panel
Just note that the image should NOT be read in the paintComponent() method as painting code should be efficient.

Related

I want to addChild the Entity created by the RealityComposer

I'm adding addChild to a custom class that inherits the Entity that I created with RealityComposer, but the Entity is not placed at the tapped position and is displayed in the center of the screen.
I'm using the official sample by Apple of collaborative session creation and implemented so far I've done it. (It doesn't use RealityComposer.)
For example, tapping on an Entity will place it in that location.
However, when I add an Entity to the scene, such as a container that is an addChild of an Entity created by RealityComposer, it always appears in the middle.
My guess is that this is because Entities created with the RealityComposer are not HasModel compliant.
In this code, the Entity is always in the center of the screen
(I've already created a QRScene.rcproject.)
final class QRCardEntity: Entity, HasModel {
let twitterCard = try! QRScene.loadTwitterCard ()
var cardContainer: HasModel {
twitterCard.allChildren().first { $0.name == " CardContainer" }! .children[0] as! HasModel
}
required init() {
super.init()
addChild(twitterCard) // preservingWorldTransform: true does not change this.
}
}
However, this code puts it in the right place.
final class QRCardEntity: Entity, HasModel {
let twitterCard = try! QRScene.loadTwitterCard ()
var cardContainer: HasModel {
twitterCard.allChildren().first { $0.name == "CardContainer" }! .children[0] as! HasModel
}
required init() {
super.init()
model = cardContainer.model
}
}
Extensions used
private extension Entity {
func allChildren() -> [Entity] {
children.reduce([]) { $0 + [$1] + $1.allChildren () }
}
}
I don't think this is the best way.
AddChild is a better way to add a whole Entity while preserving the hierarchical relationship.
This model assignment can only add models from the Top hierarchy, so it doesn't add the other Models needed for display.
How do I get the Entity created by the RealityComposer to appear in the correct position with addChild?
ps 2020/07/03
To be precise, when you tap on Device1, Entity appears in the center and
Device2 shows Entity asynchronously centered no matter where the camera is pointed.
Instead of Entity of created by RealityComposer, using code like this, it works.
addChild(
ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [
SimpleMaterial(color: color ?? .white, isMetallic: false)
]
)
)
If the position is already zero, you could try something like this that may get it looking right, but the positions of your Entities may be a bit back and forth:
twitterCard.position = -twitterCard.visualBounds(relativeTo: nil).center
That may need a little tweaking, but hopefully the intention is clear.
I've had issues understanding the hierarchy that Reality Composer gives to Entities, which is why I have avoided using it.
I solved by myself.
The reason is because I added the scene as child.
This code is to load the scene created by RealityComposer.
TwitterCard was scene name.
let twitterCard = try! QRScene.loadTwitterCard()
Scene name is presented in here.
So, correctly ModelEntity's name is here.
I needed to use this.
This load correctly.
addChild(twitterCard.cardObject!)
Only write this, it could add child Entity created by RealityComposer.
I have problem yet.
I can’t post notification for moving motion created by RealityComposer.
Because of twitterCard is not added to ARView’s scene. If can’t do this, we must write a lot of animation codes.
When needed, I create another post, thanks.

item dropping system - how can i use a prefab correctly here?

my code is pretty simple, but im quite new to unity... im trying to make it so i can drop my items on the ground when i drag the out of my inventory, but cant quite manage to do so, with a few consistent errors. I have a prefab (just learned of those today), which im trying to change its sprite renderer and spawn it. Heres my code:
public class ItemWorld : MonoBehaviour
{
private Transform prefab;
private Item item;
private SpriteRenderer spriteRenderer;
void Start()
{
prefab = Resources.Load("Prefabs/pfItemWorld") as GameObject;
//myPrefab = Resources.Load("Prefabs/pfItemWorld");
}
public static ItemWorld spawnItemWorld(Vector3 position, Item item)
{
Transform transform = Instantiate(prefab, position, Quaternion.identity);
ItemWorld itemWorld = transform.GetComponent<ItemWorld>();
itemWorld.SetItem(item);
return itemWorld;
}
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
}
public void SetItem(Item item)
{
this.item = item;
Rect spriteRect = new Rect(0, 0, item.itemIcon.width, item.itemIcon.height);
Sprite mySprite = Sprite.Create(item.itemIcon, spriteRect, new Vector2(0.5f, 0.5f));
spriteRenderer.sprite = mySprite;
}
}
My problem is i cant manage to load my prefab and use it in Instantiate without many errors...
What is wrong with my code?
Here are the errors:
(1) Assets\Scripts\ItemWorld.cs(12,18): error CS0029: Cannot implicitly convert type 'UnityEngine.GameObject' to 'UnityEngine.Transform' (yes, i know what this means, but how can i use a prefab without transform)
(2)Assets\Scripts\ItemWorld.cs(17,43): error CS0120: An object reference is required for the non-static field, method, or property 'ItemWorld.prefab'
I have tried to research but this is my last hope xd
Ill be happy for ANY help,
thanks ahead,
Gambizon
Prefabs are GameObjects and need to be instantiated and declared as such. private transform prefab should be private GameObject prefab.
After you've instantiated the object with
GameObject prefabObject = Instantiate(prefab, position, Quaternion.identity);
You can then use Transform transform = prefabObject.transform; to get the transform component of your newly instantiated prefab.
Also, if you make the prefab reference in the script public, and have this script attached to a GameObject, you can drag the prefab into the inspector so that you don't need Resources.Load("Prefabs/pfItemWorld") as GameObject, as the reference will already be there before run time.

Creating user UI using Flixel

I am new to game development but familiar with programming languages. I have started using Flixel and have a working Breakout game with score and lives.
What I am trying to do is add a Start Screen before actually loading the game.
I have a create function that adds all the game elements to the stage:
override public function create():void
// all game elements
{
How can I add this pre-load Start Screen? I'm not sure if I have to add in the code to this create function or somewhere else and what code to actually add.
Eventually I would also like to add saving, loading, options and upgrades too. So any advice with that would be great.
Here is my main game.as:
package
{
import org.flixel.*;
public class Game extends FlxGame
{
private const resolution:FlxPoint = new FlxPoint(640, 480);
private const zoom:uint = 2;
private const fps:uint = 60;
public function Game()
{
super(resolution.x / zoom, resolution.y / zoom, PlayState, zoom);
FlxG.flashFramerate = fps;
}
}
}
Thanks.
The way that I usually do it is with a different FlxState - I use one for "Menu", the game itself, and the Game Over screen.
So make a new class that extends FlxState, call it maybe "MenuState" and then say:
super(resolution.x / zoom, resolution.y / zoom, MenuState, zoom);
Inside MenuState, on a button press or something, say:
FlxG.switchState(PlayState);

Tools/Guide to Creating an Image Looper in GWT

I'm setting out to create a weather model display tool (web application), and from what I've seen, I'm really liking the idea of using Google Web Tools, and especially the SmartGWT toolkit. My one biggest sticking point at this point is finding some way to create a sort of image "looper" (displaying all images in a particular "set" one after another, not unlike a slide show). For reference, I need functionality (at least on a basic level) similar to this: http://rapidrefresh.noaa.gov/hrrrconus/jsloop.cgi?dsKeys=hrrr:&runTime=2012053007&plotName=cref_sfc&fcstInc=60&numFcsts=16&model=hrrr&ptitle=HRRR%20Model%20Fields%20-%20Experimental&maxFcstLen=15&fcstStrLen=-1&resizePlot=1&domain=full&wjet=1 (though it certainly need not be exactly like that).
Does anyone know of (ideally) some sort of GWT module that can do image looping? Or if not, does it sound like something an intermediate programmer could figure out without too much trouble (I'm willing to accept a challenge), even if I've never explicitly used GWT before? I'm sure I could whip together something that pulls each image in as it goes through a loop, but prefetching them would be even more ideal.
Please comment if you need clarification on anything!
As far as I'm aware there's not a pre-fab solution to do this, although maybe SmartGWT has something I don't know about. In any case, it won't be too hard to roll your own. Here's some code to get you started:
public class ImageLooper extends Composite {
// List of images that we will loop through
private final String[] imageUrls;
// Index of the image currently being displayed
private int currentImage = 0;
// The image element that will be displayed to the user
private final Image image = new Image();
// The Timer provides a means to execute arbitrary
// code after a delay or at regular intervals
private final Timer imageUpdateTimer = new Timer() {
public void run() {
currentImage = (currentImage + 1) % images.length;
image.setUrl(imageUrls[currentImage]);
}
}
// Constructor. I'll leave it to you how you're going to
// build your list of image urls.
public ImageLooper(String[] imageUrls) {
this.imageUrls = imageUrls;
// Prefetching the list of images.
for (String url : imageUrls)
Image.prefetch(url);
// Start by displaying the first image.
image.setUrl(imageUrls[0]);
// Initialize this Composite on the image. That means
// you can attach this ImageLooper to the page like you
// would any other Widget and it will show up as the
// image.
initWidget(image);
}
// Call this method to start the animation
public void playAnimation() {
// Update the image every two seconds
imageUpdateTimer.scheduleRepeating(2000);
}
// Call this method to stop the animation
public void stopAnimation() {
imageUpdateTimer.cancel();
}
}
One annoying thing with this implementation is that you have no way of knowing when your list of images has finished loading; Image.prefetch doesn't have a callback to help you here.

How to construct simple wxWidgets image display

I wrote a wxPython program that I am translating to wxWidgets. The program has a scrolled window that displays an image. Following Rappin, wxPython In Action (Listing 12.1), I used a StaticBitmap within a panel. While surfing the latest wxWidgets documentation, I found a dire warning that wxStaticBitmap should only be used for very small images. It says, "... you should use your own control if you want to display larger images portably." Okay. Show me. I don't have my "own control."
Was Rappin wrong, or is the documentation out of date?
The question - a newbie one, no doubt - is what is the right way to do a simple image-view window in wxWidgets? A drop-in replacement for wxStaticBitmap would be nice. I looked into the "image" program in the wxWidgets "samples" directory. It's as long a War and Peace. Surely there must be a canned class or a simple recipe.
Don't let the size of the "image" sample fool you, only a few lines of code are necessary to do what you want.
Search for the MyImageFrame class in the image.cpp file, it is nothing more than a class with a private bitmap field, a custom constructor to set the bitmap and the window client size, and an event handler for EVT_PAINT:
void OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc( this );
dc.DrawBitmap( m_bitmap, 0, 0, true /* use mask */ );
}
Since you don't want a frame class here's your recipe: You create a simple descendant of wxWindow that has a similar constructor, paint handler and duplicates the methods of wxStaticBitmap that you use in your code. Maybe simply one method to set a new bitmap and resize the control to the new bitmap dimensions.
// A scrolled window for showing an image.
class PictureFrame: public wxScrolledWindow
{
public:
PictureFrame()
: wxScrolledWindow()
, bitmap(0,0)
{;}
void Create(wxWindow *parent, wxWindowID id = -1)
{
wxScrolledWindow::Create(parent, id);
}
void LoadImage(wxImage &image) {
bitmap = wxBitmap(image);
SetVirtualSize(bitmap.GetWidth(), bitmap.GetHeight());
wxClientDC dc(this);
PrepareDC(dc);
dc.DrawBitmap(bitmap, 0, 0);
}
protected:
wxBitmap bitmap;
void OnMouse(wxMouseEvent &event) {
int xx,yy;
CalcUnscrolledPosition(event.GetX(), event.GetY(), &xx, &yy);
event.m_x = xx; event.m_y = yy;
event.ResumePropagation(1); // Pass along mouse events (e.g. to parent)
event.Skip();
}
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
PrepareDC(dc);
dc.DrawBitmap(bitmap, 0,0, true);
}
private:
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(PictureFrame,wxScrolledWindow)
EVT_PAINT(PictureFrame::OnPaint)
EVT_MOUSE_EVENTS(PictureFrame::OnMouse)
END_EVENT_TABLE()

Resources