How to correctly update an Image in a JLabel? - java

I'm French so my English is quite bad but I have a real problem with java:
I'm trying to show an Image built manually with some fillRect & co.
It works. Next, I want to update this image as a function of the text I enter in the text field. And there is the problem: it doesn't change anything, and if I manually rescale the window of the JFrame, the image shows totally deformed or scaled badly.
I'm a beginner and I have difficulties with GUI, moreso when I want to couple it with Images.
Can you help me? Why doesn't it work as I want? This is my code below, a bit long but actually quite simple ! Thanks :)
I've changed it a bit, this is the 2e VERSION.
Now the problem s that I can't change a condition in order to modify the color of a simple rectangle, try "lol" in the entry field !
CODE VERSION 2
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.ImageIcon;
public class Fenetre extends JFrame {
private JFrame frame;
private JPanel container = new JPanel();
private JTextField jtf;
private JLabel label = new JLabel("Commandes ");
private JButton b = new JButton ("OK");
private Graphics graph;
private Image img;
private JLabel screen;
private boolean color;
/**
* Constructeur de l'objet
*/
public Fenetre(){
color = true;
frame = new JFrame();
frame.setTitle("Animation");
frame.setSize(1000, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
JPanel top = new JPanel();
jtf = new JTextField();
jtf.setPreferredSize(new Dimension(800, 30));
b.addActionListener(new BoutonListener());
frame.setContentPane(top);
frame.setVisible(true);
paintComponent(graph);
screen = new JLabel( new ImageIcon(img));
top.add(screen);
top.add(label);
top.add(jtf);
top.add(b);
frame.setContentPane(top);
}
class BoutonListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
if(jtf.getText().equals("lol")) lol();
System.out.println("Entry : " + jtf.getText());
}
}
public void paintComponent(Graphics g)
{
if(img == null) {
img = frame.createImage(1000,300);
g = img.getGraphics();
}
g.setColor(Color.white);
g.fillRect(0,0,1000,300);
if(color) g.setColor(Color.orange); else g.setColor(Color.blue);
g.fillRect(8,25,200,100);
g.setColor(Color.green);
g.drawString("Text",10,10);
}
public void lol()
{
if(color) color = false; else color = true;
}
}
PREVIOUS CODE
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.ImageIcon;
public class Fenetre extends JFrame {
private JPanel container = new JPanel();
private JTextField jtf;
private JLabel label = new JLabel("Commandes ");
private JButton b = new JButton ("OK");
private Graphics g;
private Image img;
private JLabel screen;
/**
* Constructeur de l'objet
*/
public Fenetre(){
this.setTitle("Animation");
this.setSize(1000, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
JPanel top = new JPanel();
jtf = new JTextField();
jtf.setPreferredSize(new Dimension(800, 30));
b.addActionListener(new BoutonListener());
this.setContentPane(top);
this.setVisible(true);
paint(g);
screen = new JLabel( new ImageIcon(img));
top.add(screen);
top.add(label);
top.add(jtf);
top.add(b);
this.setContentPane(top);
}
class BoutonListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
System.out.println("Entry : " + jtf.getText());
if(jtf.getText().equals("lol")) lol();
}
}
#Override
public void paint(Graphics g)
{
if(img == null) {
img = createImage(1000,300);
g = img.getGraphics();
}
g.setColor(Color.white);
g.fillRect(0,0,1000,300);
g.setColor(Color.orange);
g.fillRect(8,25,200,100);
g.setColor(Color.green);
g.drawString("Text",10,10);
}
#Override
public void update(Graphics g)
{
g.setColor(Color.blue);
g.fillRect(8,25,300,100);
}
public void lol()
{
g.setColor(Color.blue);
g.fillRect(8,25,200,100);
}
}

I see several problems in your code:
You are confusing your g member variable with the g parameter of the paint method. When lol is called, g is null and you get a NullPointerException
You should never grab a hold on Graphics (only in really rare cases). Instead you override properly paintComponent() and you use the Graphics parameter to draw what you want. When you want to update the component, you call repaint()
Don't override paint, but override paintComponent()
Don't override paint of JFrame. Use a dedicate component for that. No need to use a JLabel for that, a simple JComponent is enough.
Don't extend JFrame if you are not extending its functionality.
After adding components to the component hierarchy, call revalidate()
Fix those issues and come back with another question if you still have problems.
You should probably consider reading this tutorial and the few next steps. It will show you basic examples of things similar to what you are trying to do.
EDIT:
I took your V2 code and patched it as I could. This is very far from perfect but you should get the gist of how you can do this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Fenetre extends JComponent {
private boolean color;
/**
* Constructeur de l'objet
*/
public Fenetre() {
color = true;
setPreferredSize(new Dimension(1000, 300));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, 1000, 300);
if (color) {
g.setColor(Color.orange);
} else {
g.setColor(Color.blue);
}
g.fillRect(8, 25, 200, 100);
g.setColor(Color.green);
g.drawString("Text", 10, 10);
}
public void lol() {
if (color) {
color = false;
} else {
color = true;
}
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
protected static void initUI() {
JFrame frame = new JFrame();
frame.setTitle("Animation");
frame.setSize(1000, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JPanel container = new JPanel();
final JTextField jtf = new JTextField();
final Fenetre fenetre = new Fenetre();
JLabel label = new JLabel("Commandes ");
JButton b = new JButton("OK");
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
JPanel top = new JPanel();
jtf.setPreferredSize(new Dimension(800, 30));
class BoutonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (jtf.getText().equals("lol")) {
fenetre.lol();
}
System.out.println("Entry : " + jtf.getText());
}
}
b.addActionListener(new BoutonListener());
top.add(fenetre);
top.add(label);
top.add(jtf);
top.add(b);
top.revalidate();
frame.setContentPane(top);
frame.setVisible(true);
}
}

Your Swing graphics programming has several significant problems, and I urge you to go through the tutorials to learn how to do this better. For example, you are
calling the paint method directly -- something you should almost never do except in very special situations (this is not one of them)
Drawing directly in the JFrame's paint(...) method. Instead you will want to draw in the paintComponent(...) method override of a class derived from JComponent such as JPanel.
Calling update unnecessarily as if this were an AWT program. You don't do this in Swing unless you're changing the Look & Feel.
Again, take a look at the tutorials on this -- you will not regret doing this, trust me.
edit -- too slow! 1+ to Guillaume

Related

Java JButton set text background color

I have to create a rounded button with a precise color.
I did a lot of research in order to make it and I'm almost there!
I choose to use a rounded border because doing otherwise seem impossible to me :/ (I'm new to Java).
So I just need to find a way to set the background of the content of the button (the text) the right color and I'm done. (I currently have just the border and disabled the background in order to see the rounded part so the background of the text is empty...)
Result :
Expected result :
I've already tried theses :
Complex solution I didn't understand and that doesn't seem to work
I also tried solutions with Java Theme
package components;
import java.awt.Font;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import utils.BrandColors;
public class Button extends JButton {
private int xPadding = 10;
public Button(String text) {
super(text);
this.init();
}
private void init() {
this.setFont(new Font("Arial", Font.PLAIN, 16));
this.setForeground(BrandColors.TEXT_ON_SECOUNDARY);
this.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(BrandColors.SECOUNDARY, 15, true),
BorderFactory.createMatteBorder(0, this.xPadding, 0, this.xPadding, BrandColors.SECOUNDARY)
));
// this.setBackground(BrandColors.SECOUNDARY);
this.setOpaque(false);
}
}
Thanks in advance for your responses :)
Border don't fill. So once you make your component transparent (setOpaque(false)) you'll lose the background color, but you'd have weird issue with the border drawing inside the painted background area of the component anyway.
There's no simple way to do this and in fact (for Swing) a "generally" better solution would be to do this at the look and feel level (where you'd gain ultimate control and could change ALL the buttons in the UI without ever changing the code they use 😈, for example, example, example)
But I don't have the time to muck about with all that, so, instead, I'll go straight for the "custom painted, custom component" route instead.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
add(new Button("This is a test"));
}
}
public class BrandColors {
public static final Color TEXT_ON_SECOUNDARY = Color.WHITE;
public static final Color SECOUNDARY = Color.RED;
}
public class Button extends JButton {
private int xPadding = 10;
public Button(String text) {
super(text);
this.init();
}
private void init() {
this.setFont(new Font("Arial", Font.PLAIN, 16));
this.setForeground(BrandColors.TEXT_ON_SECOUNDARY);
this.setContentAreaFilled(false);
this.setBorderPainted(false);
this.setBackground(BrandColors.SECOUNDARY);
this.setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHints(hints);
g2d.setColor(getBackground());
g2d.fill(new RoundRectangle2D.Double(0, 0, getWidth() - 1, getHeight() - 1, 15, 15));
g2d.setColor(getForeground());
super.paintComponent(g2d);
g2d.dispose();
}
}
}
Now, the trick here is in knowing that paintComponent will also render the text, so we need to paint the background BEFORE we call super.paintComponent
UI delegate example...
Now, one of the features of Swing is it's "pluggable look and feel". This allows you to modify the "look and feel" of components without having to modify the rest of the code.
The following example shows a way to set a UI delegate for a specific instance of JButton
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicButtonUI;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 4);
JButton button = new JButton("This is a normal button");
add(button, gbc);
JButton superButton = new JButton("This is a super button");
superButton.setUI(new RoundedButtonUI());
add(superButton, gbc);
}
}
public class BrandColors {
public static final Color TEXT_ON_SECOUNDARY = Color.WHITE;
public static final Color SECOUNDARY = Color.RED;
}
public class RoundedButtonUI extends BasicButtonUI {
#Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setOpaque(false);
b.setBackground(BrandColors.SECOUNDARY);
b.setForeground(BrandColors.TEXT_ON_SECOUNDARY);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHints(hints);
g2d.setColor(c.getBackground());
g2d.fill(new RoundRectangle2D.Double(0, 0, c.getWidth() - 1, c.getHeight() - 1, 15, 15));
g2d.setColor(c.getForeground());
super.paint(g, c);
g2d.dispose();
}
}
}
Effect ALL buttons in the UI
If you want to change ALL the buttons in the UI, without having to change any of the related code, you can set the UI delegate as the default UI delegate to be used by all buttons
To do this, I had to make a couple of additional changes. First, the delegate class needs to be in it's own file (please take note of the package name) and I had to implement the static method createUI
package stackoverflow;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;
public class RoundedButtonUI extends BasicButtonUI {
private static RoundedButtonUI shared;
public static ComponentUI createUI(JComponent c) {
if (shared != null) {
return shared;
}
shared = new RoundedButtonUI();
return shared;
}
#Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setOpaque(false);
b.setBackground(BrandColors.SECOUNDARY);
b.setForeground(BrandColors.TEXT_ON_SECOUNDARY);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(hints);
g2d.setColor(c.getBackground());
g2d.fill(new RoundRectangle2D.Double(0, 0, c.getWidth() - 1, c.getHeight() - 1, 15, 15));
g2d.setColor(c.getForeground());
super.paint(g, c);
g2d.dispose();
}
}
Now, before you do anything else, I need to install it, UIManager.getDefaults().put(new JButton().getUIClassID(), "stackoverflow.RoundedButtonUI");. This should be done before you call any other UI related code (and after you've set the look and feel, if you're doing that)
And then I can just run the code as normal
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
UIManager.getDefaults().put(new JButton().getUIClassID(), "stackoverflow.RoundedButtonUI");
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 4);
JButton button = new JButton("This is a normal button");
add(button, gbc);
JButton superButton = new JButton("This is a super button");
add(superButton, gbc);
}
}
}
PLEASE NOTE
In order to install a new UI delegate this way, you MUST supply the fully qualified class name, that is, the full package path AND the class name.
In my examples above, I'm using stackoverflow as my package name (I'm lazy), so the installation looks like UIManager.getDefaults().put(new JButton().getUIClassID(), "stackoverflow.RoundedButtonUI");

Java graphics, making the window flash in different colors

this is my first post here. I am currently learning about basic GUI and Graphics in java. I'm still pretty new to the language, and it's my first language as well. As I learn java I like to experiment and play with the new tools I acquire from reading. As a result I wanted to make a window where the colors it is filled with will flash, currently, i wanted to stay simple and have it flash from orange to cyan and back. However, right now, all my program does is start white, and fill in with cyan and the text, and then stop changing whatsoever, and I'm not sure why this is.
Please point me in the right direction, thanks!
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ColorFlash extends JFrame{
private static class Display extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int h = 200; h > 25; h--){
g.setColor(Color.ORANGE);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.CYAN);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.ORANGE);
g.drawString("Hello world!", 30, 35);
g.drawOval(100, 100, 60, 60);
}
}
}
private static class ButtonHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
public static void main (String [] args){
Display displayPanel = new Display();
JButton okButton = new JButton("OK");
ButtonHandler listener = new ButtonHandler();
okButton.addActionListener(listener);
JPanel content = new JPanel();
content.setLayout(new BorderLayout());
content.add(displayPanel, BorderLayout.CENTER);
//content.add(okButton, BorderLayout.SOUTH);
//subContent.add(displayPanel, BorderLayout.SOUTH);
//content.add(okButton, BorderLayout.SOUTH);
content.add(okButton, BorderLayout.SOUTH);
JFrame window = new JFrame("GUI Test");
window.setContentPane(content);
window.setSize(500, 500);
window.setLocation(100,100);
window.setVisible(true);
}
}
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing
Basically, what's happening is whatever is painted last in your loop is what is actually been painted to the screen
What you need is some kind of timer/trigger that can change the color you want to paint with and repaint the component.
Take a look at How to use Swing Timers for more details
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestPaint {
private static class Display extends JPanel {
private Color[] colors = new Color[]{Color.ORANGE, Color.CYAN};
private int colorIndex;
public Display() {
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setBackground(colors[colorIndex % 2]);
colorIndex++;
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.drawString("Hello world!", 30, 35);
g.drawOval(100, 100, 60, 60);
}
}
public static void main(String[] args) {
new TestPaint();
}
public TestPaint() {
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.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Display());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You might also like to take a look at Initial Threads

On using Nimbus look and feel, JButton vanishes totally in a JFrame if there is a background image

I have a JFrame. In that i have used:
JTabbed panes.
JButton.
background images in a Jlabel which is added in JPanel.
Nimbus look and feel.
My problem is that whenever i use Nimbus look and feel the JButton vanishes only if there is a background image added. But this doesn't happen with other look and feel. Can anyone help me in getting the button visible?
Here is my code:
import javax.swing.ImageIcon;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;
import java.awt.*;
import java.awt.event.*;
class ImageTest
{
JTabbedPane tp;
JLabel lab1;
JPanel welcome;
JFrame frame;
ImageIcon image2;
JButton b1;
public void createUI()
{
frame=new JFrame("JTabbedPane Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b1=new JButton();
welcome= new JPanel(null);
welcome.setPreferredSize(new Dimension(1366,786));
ImageIcon icon = new ImageIcon(ImageTest.class.getResource("icloud.jpg"));
tp=new JTabbedPane();
Container pane = frame.getContentPane();
pane.add(tp);
tp.addTab("Welcome", welcome);
lab1=new JLabel();
lab1.setIcon(icon);
b1.setBounds(100,100,100,100);
lab1.setBounds(0,0,1500,700);
welcome.add(lab1);
welcome.add(b1);
b1.setVisible(true);
frame.setSize(500,500);
frame.setVisible(true);
frame.setTitle("I-Cloud");
}
public static void main(String[] args)
{
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
}
ImageTest w = new ImageTest();
w.createUI();
}
}
EDIT:
import javax.swing.ImageIcon;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;
import java.awt.*;
import java.awt.event.*;
class ImageTest
{
JTabbedPane tp;
JLabel lab1;
JPanel welcome,w;
JFrame frame;
ImageIcon image2;
JButton b1;
public void createUI()
{
frame=new JFrame("JTabbedPane Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b1=new JButton();
welcome= new JPanel(new GridLayout(1,1,15,15));
w=new JPanel (new GridLayout(1, 1, 15, 15));
welcome.setPreferredSize(new Dimension(1366,786));
ImageIcon icon = new ImageIcon(ImageTest.class.getResource("icloud.jpg"));
tp=new JTabbedPane();
Container pane = frame.getContentPane();
pane.add(tp);
lab1=new JLabel();
lab1.setIcon(icon);
w.setOpaque(false);
w.add(b1);
b1.setVisible(true);
welcome.add(lab1);
welcome.add(w);
tp.addTab("Welcome", welcome);
frame.setSize(500,500);
frame.pack();
frame.setVisible(true);
frame.setTitle("I-Cloud");
}
public static void main(String[] args)
{
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
}
ImageTest w = new ImageTest();
w.createUI();
}
}
Thanks.
Your use of Swing GUI is out of kilter by use of null layouts and then adding one component on top of another, essentially covering up one of the components (the JButton) with another (the JLabel with the image).
Don't use null layout like you're doing. While to a newbie using null layout and setBounds seems the best way to create complex GUI's, the more you deal with Swing GUI creation, the more you will find that doing this will put your GUI in a straight-jacket, painting it in a very tight corner and making it very hard to extend or enhance. Just don't do this.
Don't add one component on top of another in the same container.
Instead give your JLabel with the image a layout manager.
Then add the JButton to the JLabel.
Then add the JLabel to the JTabbedPane.
Edit
Your latest edit did not use the JLabel as the container as suggested above. So if you use a separate container, then the button and the label will be shown side by side. To solve this, you either need to give the JLabel a layout manager, and then add the button to it as suggested above, or draw directly in a JPanel's paintComponent(...) method, and add the button to the JPanel.
For an example of the latter:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class MyImageTest extends JPanel {
// public static final String SPEC = "https://duke.kenai.com/SunRIP/.Midsize/SunRIP.jpg.png";
public static final String SPEC = "http://upload.wikimedia.org/wikipedia/commons/3/37/"
+ "Mandel_zoom_14_satellite_julia_island.jpg";
private static final int PREF_H = 786;
private static final int GAP = 100;
private BufferedImage img;
public MyImageTest() {
try {
URL imgUrl = new URL(SPEC);
img = ImageIO.read(imgUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
setLayout(new FlowLayout(FlowLayout.LEADING));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
JButton b = new JButton();
b.setPreferredSize(new Dimension(GAP, GAP));
add(b);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
#Override
public Dimension getPreferredSize() {
if (img == null) {
return super.getPreferredSize();
} else {
int width = (img.getWidth() * PREF_H) / img.getHeight();
return new Dimension(width, PREF_H);
// return new Dimension(img.getWidth(), img.getHeight());
}
}
private static void createAndShowGui() {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
MyImageTest mainPanel = new MyImageTest();
JFrame frame = new JFrame("MyImageTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I think setting a background image in JLabel and then adding buttons even after adding containers is a very complex issue. Believe me tried it and it was a very complex task. you can do it by directly drawing as Hovercraft suggested, but remember you would get not so much good image quality with that method. :-|

JLabel unusable from other class

I got a problem with two problematics classes. One for drawing things, and other for implementing pan and zoom onto the previously drawn objects.
Imagine my interface as only two spitted panels, one empty(top) and one with a slider(bot):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import javax.swing.JSplitPane;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JSlider;
import java.awt.FlowLayout;
public class Interface {
private JFrame mainFrame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {Interface window = new Interface();window.mainFrame.setVisible(true);
} catch (Exception e) { e.printStackTrace();}
}
});
}
public Interface() {initialize();}
private void initialize() {
mainFrame = new JFrame();
mainFrame.setTitle("LXView");
mainFrame.setMinimumSize(new Dimension(800, 600));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setExtendedState(mainFrame.getExtendedState()| JFrame.MAXIMIZED_BOTH);
mainFrame.getContentPane().setBackground(Color.WHITE);
mainFrame.getContentPane().setLayout(new BorderLayout(0, 0));
JSplitPane splitPane = new JSplitPane();
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setOneTouchExpandable(true);
splitPane.setBackground(Color.WHITE);
mainFrame.getContentPane().add(splitPane, BorderLayout.CENTER);
splitPane.setResizeWeight(0.99);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setEnabled(false);
splitPane.setLeftComponent(scrollPane);
Render topPane = new Render();
scrollPane.setViewportView(topPane);
topPane.setLayout(new BoxLayout(topPane, BoxLayout.X_AXIS));
JPanel botPane = new JPanel();
splitPane.setRightComponent(botPane);
botPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
JLabel zoomLevel = new JLabel("Zoom level:");
botPane.add(zoomLevel);
JSlider slider = new JSlider(JSlider.HORIZONTAL, 25, 100, 100);
slider.setMajorTickSpacing(15);
slider.setMinorTickSpacing(5);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setPreferredSize(new Dimension(600,40));
botPane.add(slider);
PanAndZoom zoomer=new PanAndZoom(topPane.getLabel());
slider.addChangeListener(zoomer);
}
The top panel uses the render class which was made to draw graphics. Simplifying:
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Render extends JPanel {
JLabel envContainer;
Render() {
super();
ImageIcon imageIcon = new ImageIcon("/path/to/img1");
JLabel envContainer = new JLabel(imageIcon);
super.add(envContainer);
}
#Override
public void paint(Graphics g) {
super.paint(g);
/*Render stuff*/
}
public JLabel getLabel() {
return envContainer;
}
}
And the third class which is giving me the trouble, listens on the slider and sets the JLabel icon according to it:
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class PanAndZoom implements ChangeListener {
private JLabel label;
private BufferedImage image;
public PanAndZoom(JLabel lab){
this.label=lab;
try {
image = ImageIO.read(new File("/path/to/img1"));
} catch (IOException e) {
e.printStackTrace();
}
label.setIcon(new ImageIcon("/path/to/img2"));//To test another img. It gives runtime errors.
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
double scale = value / 100.0;
BufferedImage scaled = getScaledImage(scale); // It also gives runtime errors.
System.out.println("Scale:"+scale+" Value:"+value);
label.setIcon(new ImageIcon(scaled));
label.revalidate();
}
private BufferedImage getScaledImage(double scale) {
int w = (int) (scale * image.getWidth());
int h = (int) (scale * image.getHeight());
BufferedImage bi = new BufferedImage(w, h, image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
g2.drawRenderedImage(image, at);
g2.dispose();
return bi;
}
}
Why cant i use the JLabel if it was successfully returned by the getLabel method?
You're local version of envContainer in class Render's constructor is overriding the class instance envContainer.
public class Render extends JPanel {
JLabel envContainer; //<---- class instance
Render() {
super();
ImageIcon imageIcon = new ImageIcon("/path/to/img1");
JLabel envContainer = new JLabel(imageIcon); //<---- overriden by local instance, hence class instance remains null
super.add(envContainer);
}
My guess is that you didn't mean to make it a local version since you're not using it within the constructor for anything. Make the following change to your Render constructor.
Render() {
..
this.envContainer = new JLabel(imageIcon);
...
}

Java JScrollPane- Multiple components

I'm trying to add 2 images inside the JScrollPane. the first image is a background and the second one overlap the first one. The problem shows only the second image when i run my program!
please help
ImageIcon ii = new ImageIcon("mini_map.png");
JLabel label1=new JLabel(ii);
Icon icon = new ImageIcon("Mg.gif");
JLabel label2 = new JLabel(icon);
JScrollPane jsp=new JScrollPane();
jsp.getViewport().add(label1);
jsp.getViewport().add(label2 );
JViewport is a single-child container, you can't add two components.
To achieve an overlap (that is stack components in z-direction) in any container, you'r mostly on your own, the built-in support is poor. Either have to manage them in LayeredPane (as mentioned already) or try OverlapLayout
Put both labels in the same panel and add it to the JScrollPane:
ImageIcon ii = new ImageIcon("mini_map.png");
JLabel label1=new JLabel(ii);
Icon icon = new ImageIcon("Mg.gif");
JLabel label2 = new JLabel(icon);
JPanel pContainer = new JPanel();
pContainer.add(label1);
pContainer.add(label2);
JScrollPane jsp=new JScrollPane(pContainer);
If you want to have components on top of each other use a layered pane.
This is how I would do it for your particular problem.
Since you say you have one image which serves the role of a background, thus I would override paintComponent() like in BackgroundPanel below.
This way you have a panel which serves as a background only. To it you can add any type of component, in your case a JLabel with an ImageIcon.
This way you have an effect of one being over another and you are still able to use layout manager to control where your components are.
If your problem is more complex or you want to generally set Components one over another then do as all are saying here ---> use JLayeredPane. Note that if you use JLayeredPane sadly layout managers will not help you since it doesn't respects them. You will have to proceed similarly to a situation when you use a null manager, i.e. setBounds() for components.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class PaintInScroll
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
Image backgroundImage = new ImageIcon(new URL(
"http://www.jvsearch.com/adidocs7_images/JAVAORANGE.JPG")).getImage();
BackgroundPanel bP = new BackgroundPanel(backgroundImage);
bP.setLayout(new BorderLayout());
bP.setPreferredSize(new Dimension(500, 500));
JLabel label = new JLabel(new ImageIcon(new URL(
"https://blogs.oracle.com/theplanetarium/resource/thumb-java-duke-guitar.png")));
bP.add(label, BorderLayout.CENTER);
JScrollPane scrollPane = new JScrollPane(bP);
scrollPane.setPreferredSize(new Dimension(300, 400));
JPanel contentPane = new JPanel();
contentPane.add(scrollPane);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}catch(MalformedURLException ex)
{
Logger.getLogger(PaintInScroll.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
class BackgroundPanel extends JPanel
{
private Image image;
public BackgroundPanel(Image image)
{
this.image = image;
}
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
}
}
NOTE: Images are URLs thus i-net connection is required to run the example.
EDIT1: Example showing how to use JLayeredPane with use of layout managers for each layer.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class PaintInScrollRespectingLayoutManagers extends JPanel
{
private static final long serialVersionUID = 1L;
private JLayeredPane layeredPane;
private JLabel imageContainer = new JLabel();
private JButton infoB = new JButton("i");
private JScrollPane scrollPane;
public PaintInScrollRespectingLayoutManagers(ImageIcon image)
{
super();
this.imageContainer.setIcon(image);
scrollPane = new JScrollPane(imageContainer);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setPreferredSize(new Dimension(125, 90));
JPanel iSPP = new JPanel();//image scroll pane panel
iSPP.setOpaque(false);
iSPP.add(scrollPane);
JPanel iBP = new JPanel();//info button panel
iBP.setOpaque(false);
iBP.add(infoB);
this.layeredPane = new JLayeredPane();
layeredPane.add(iSPP, new Integer(50));
layeredPane.add(iBP, new Integer(100));
this.setLayout(new BorderLayout());
this.add(layeredPane, BorderLayout.CENTER);
this.add(new JButton("A button"), BorderLayout.SOUTH);
layeredPane.addComponentListener(layeredPaneCL);
setPreferredSize(new Dimension(300, 300));
}
private ComponentListener layeredPaneCL = new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
super.componentResized(e);
System.out.println("componentResized");
for(Component c : layeredPane.getComponents())
c.setSize(layeredPane.getSize());
}
};
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PaintInScrollRespectingLayoutManagers(new ImageIcon(new URL(
"http://www.prodeveloper.org/wp-content/uploads/2008/10/stackoverflow-logo-250.png"))));
frame.pack();
frame.setVisible(true);
}catch(MalformedURLException ex)
{
Logger.getLogger(PaintInScrollRespectingLayoutManagers.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
NOTE 2: The only reason that the scroll panes have setPrefferedSize is so you can see the scrollbars. Otherwise do not use it let the layout take care of controlling scroll pane.

Categories

Resources