How to add picture out of JFrame, attached to border - java

Hi I Would like add to my JFrame border some image.
Is this Possible to attach picture to borders for JFrame and create it as 1 object ?
Something like this:

I'm not sure if it's possible to add the image directly to the border of a JFrame (suggestions welcome). I decided to solve this issue by using a transparent content pane, and using an inner frame to "appear" like the outer frame.
The code is pretty simple, however, let me know if you'd like an explanation of how the code works.
Here's the minimum code you'll need to get up and running.
You'll need to provide your own transparent-phone.png image, in the root of the classpath (i.e. next to your PhoneWindow.java file, in the root package).
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
public class PhoneWindow {
public static void main(String[] args) {
new PhoneWindow();
}
public PhoneWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create the inner frame
final JInternalFrame frame2 = new JInternalFrame("My Telephone");
frame2.setClosable(true);
frame2.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
// add elements to the outer frame
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
JPanel pane = new TranslucentPane();
frame.setContentPane(pane);
frame.setLayout(new BorderLayout());
// add inner frame and phone picture
frame.add(frame2, BorderLayout.CENTER);
frame.add(new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/transparent-phone.png")))), BorderLayout.EAST);
frame.setLocationRelativeTo(null);
frame.setMinimumSize(new Dimension(400, 300));
frame.pack();
// show
frame2.setVisible(true);
frame.setVisible(true);
} catch (Throwable ex) {
ex.printStackTrace();
}
}
});
}
public class TranslucentPane extends JPanel {
public TranslucentPane() {
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0f));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
}
Here's the full Java class (including close and draggable behaviour)
https://gist.github.com/nickgrealy/16901a6428cb79d4f179
And here's a screenshot of the final product
N.B. the transparent sections inside/outside the phone.
References:
How to make a transparent JFrame but keep everything else the same?
Trying to disable dragging of a JInternalFrame

Related

How do I create a transparent window with red border?

I'm trying to make a software that records the screen when a key is pressed. In order to indicate that the program is now recording, I want to put a red border around the outside of the screen. I'm having trouble getting it to work, here is my attempt so far:
public Main() {
JFrame frame = new JFrame("");
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setSize((int)ss.getWidth(), (int)ss.getHeight());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.createBufferStrategy(3);
BufferStrategy bs = frame.getBufferStrategy();
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
g.setColor(Color.RED);
g.drawRect(0, 0, frame.getWidth()-1, frame.getHeight()-1);
g.dispose();
bs.show();
}
It seems like setting the background transparent makes the graphics object not able to draw onto the jframe, and setting the background of the graphics object to transparent only leaves a white background with a red border, rather than transparent. I'm completely stuck on this one at the moment so any help would be appreciated!
You can't really draw on a component that way, you would need to override paintComponent(g) to do that.
You can simply add a border object:
((JComponent) frame.getContentPane()).setBorder(new LineBorder(Color.RED, 10));
I believe the following code achieves what you want. Notes after the code.
import static java.awt.Frame.MAXIMIZED_BOTH;
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
import java.awt.EventQueue;
import java.awt.Color;
import java.awt.Container;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Recorder implements Runnable {
private JFrame frame;
#Override // java.lang.Runnable
public void run() {
showGui();
}
private void showGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
if (contentPane instanceof JComponent) {
JComponent jCmpt = (JComponent) contentPane;
jCmpt.setBorder(BorderFactory.createLineBorder(Color.RED, 5, true));
}
frame.setExtendedState(MAXIMIZED_BOTH);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
/**
* Start here
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Recorder());
}
}
setExtendedState() maximizes the JFrame so that it takes up the entire screen.
setUndecorated() removes the title bar and the border of the JFrame.
setBackground() makes the JFrame transparent.
setLocationRelativeTo() is optional since the JFrame is maximized.
Finally I set a thick, red, rounded border around the content pane of the JFrame.
Note that you can close the JFrame by pressing Alt+F4 keys on the computer keyboard.
Optionally, you can also add the following:
frame.setAlwaysOnTop(true);

how to do auto-resizing drawings in JPanel?

what's the easiest way to have a drawing in a JPanel that resizes whenever the user resizes the JFrame?
I know that I can auto resize the panel with a BorderLayout but the drawings are not resized in this case. I am new to java and GUI programming and there are probably numerous solutions.
please give me a hint into the right direction to make e.g. the rectangle in
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawRect(20, 20, 100, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
auto-resizing whenever the frame is resized.
Provide positions and sizes as a proportion of the width and height of the panel. Whenever the panel is resized, the rendering engine will schedule a call to the paintComponent() method and the rectangle will be drawn proportionally. E.G.
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
g.drawRect(w/10, h/10, w/2, h/2);
}
/* A custom component should give the layout manager hints as to
its preferred size. */
#Override
public Dimension getPreferredSize() {
return new Dimension(200,200);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
frame.getContentPane().setLayout(new BorderLayout());
Insert the line before you add the component to the GUI.
You should study layoutmanagers, since it is a unique concept in Java.

Image not showing on the window

I have reduced my codes to such a simple function: to show a picture on a window. But why does the picture not show up however I tried? I create a JFrame, and then created a JPanel which is expected to show the picture. Then add the panel to the frame. By the way, I imported the picture and double clicked it to get the url.
import java.awt.*;
import javax.swing.*;
import com.sun.prism.Graphics;
public class GUI {
JFrame frame=new JFrame("My game");
JPanel gamePanel=new JPanel();
public static void main(String[] args){
GUI gui=new GUI();
gui.go();
}
public void go(){
frame.setSize(300, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Background backPic=new Background();
backPic.setVisible(true);
frame.getContentPane().add(backPic);
JPanel contentPane=(JPanel) frame.getContentPane();
contentPane.setOpaque(false);
frame.setVisible(true);
}
class Background extends JPanel{
public void paintComponent(Graphics g){
ImageIcon backgroundIcon=new ImageIcon("file:///E:/eclipse/EL/backgroundPicture.jpg");
Image backgroundPic=backgroundIcon.getImage();
Graphics2D g2D=(Graphics2D) g;
g2D.drawImage(backgroundPic,0,0,this);
}
}
}
It's because you've imported com.sun.prism.Graphics. It should be java.awt.Graphics.
I would also get rid of the "file:///" bit from your path. And you also probably don't want to be loading the image on each paint event. Here's a better version of the Background class;-
class Background extends JPanel {
Image backgroundPic;
public Background() {
ImageIcon backgroundIcon=new ImageIcon("E:/eclipse/EL/backgroundPicture.jpg");
backgroundPic=backgroundIcon.getImage();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D=(Graphics2D) g;
g2D.drawImage(backgroundPic,10,10,this);
}
}

How to pass events through a JFrame?

I have an undecorated JFrame with some contents on it (Labels, Images, etc.). I need the JFrame to pass all the events through it. For example: when a click is made on that JFrame, I want it to pass that click through, to the window/anything that is underneath the frame.
Problem Example:
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame("Test");
f.setAlwaysOnTop(true);
Component c = new JPanel() {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setColor(Color.gray);
int w = getWidth();
int h = getHeight();
g2.fillRect(0, 0, w,h);
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(w/4, h/4, w-2*(w/4), h-2*(h/4));
}
};
c.setPreferredSize(new Dimension(300, 300));
f.getContentPane().add(c);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
com.sun.awt.AWTUtilities.setWindowOpaque(f,false);
}
In this case, the JFrame has a border with close/minimize/fullscreen controls, and graphics on the JFrame still catch the events while just the transparent parts pass them through. I need both (transparent parts, and with graphics) to pass through the events.
Video Example of my goal: https://www.youtube.com/watch?v=irUQGDDSk_g
Similar question:
Pass mouse events to applications behind from a Java UI
This question tries to achieve a similar goal, but the JFrame is decorated (has close/minimize controls with an outer frame), and graphics still catch the user control events.
Question: How can I make a JFrame with graphics, that will not catch the events from the user controlling, but to pass in through?
This is not an answer, but a correction to the code example
The example you provide is actually doing some very dangerous things, first it's painting a translucent color onto an opaque component, this means that Swing doesn't know that it should actually be painting anything under the component and could also result in a number of very nasty paint artifacts, as Swing only knows about opaque and transparent component, it doesn't know about semi-transparent components, so you need to trick the API.
When performing custom painting, you should always call super.paintComponent to ensure that the Graphics context is setup correctly before painting. In your case, you should also make the component transparent using setOpaque and passing it false, for example...
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestFrame {
public static void main(String[] args) {
new TestFrame();
}
public TestFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLUE);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2d.dispose();
}
}
}

Platform independent Image in java

I am trying to paint an image onto a panel, that is contained by a frame.
Let us say I have a 320 x 480 image.
When i try to create a frame with size 320x480 and add the panel into it, I encounter a problem.
In different operating systems, the JFrame of 320x480 is of different sizes due to title bar.
Thus my correct fit image in windows XP will not be properly painted in Windows8 or Ubuntu.
A grey patch is visible because the image was not properly placed.
I tried overriding paint method and using ImageIcon.
Please do offer a solution.
TIA
Code Snippet
CLASS PA CONTENTS
setPreferredSize(new Dimension(500,500));
.
.
JLabel image= new JLabel();
ImageIcon background = new ImageIcon(getClass().getClassLoader().getResource("Flower.jpg"));
image.setBounds(0, 0, 500, 500);
image.setIcon(background);
this.add(image); //where "this" is extending from JPanel
CLASS PB CONTENTS
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
inserting(frame.getContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setResizable(false);
private void inserting(Container pane)
{
cardPanel=new JPanel();
CardLayout cards=new CardLayout();
cardPanel.setLayout(cards);
PA home= new PA();
cardPanel.add(home,"homeScreen");
pane.add(cardPanel);
}
Don't call setSize at all, call pack (as VGR stated in his comment). pack will size your JFrame based on size's of component's within it, and gaps between those component's.
Now.. issue you will encounter is that your JFrame will be small at startup. So override getPreferredSize method for your JPanel to return dimensions of your image:
public void getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
Now your image will fit perfectly and your application will be fully OS independent.
And also, do not override paint method. Instead, override paintComponent.
Here is a small demo I made in cases like yours:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Drawing {
JFrame frame = new JFrame();
public Drawing() {
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new Panel());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Drawing();
}
});
}
class Panel extends JPanel {
BufferedImage image = null;
Panel() {
try {
image = ImageIO.read(new File("path-to-your-image"));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
#Override
public Dimension getPreferredSize() {
// Panel will be sizes based on dimensions of image
return new Dimension(image.getWidth(), image.getHeight());
}
}
}
It seems to be the layout problem. The most obvious solution is to wrap you image panel into another container with proper layout, so your panel will always have the same size.

Categories

Resources