How to set size and image of JButton? - java

Sorry if this is a really stupid question but I can't figure out how to set the size of a JButton. I'm trying to create a custom JButton class which can be called from anywhere with custom text to make things easier. I am also trying to set a background image which doesn't appear to be working either.
I have tried using this.setSize(1000, 1000) (surely this should work) but this does nothing at all.
Here is my code:
package menu;
import javax.swing.*;
#SuppressWarnings("serial")
public class Button extends JButton
{
public Button(String name)
{
ImageIcon background = new ImageIcon("/assets/buttons/menu.png"); //Is this how you set a background image for a button?
this.setText(name);
this.setIcon(background);
this.setLayout(null); //This hasn't made a difference
this.setSize(300, 80); //This does nothing
}
}

try
import javax.swing.JButton;
public class replaceButton **extends JButton**
{
public replaceButton(String name)
{
this.setText(name);
ImageIcon background = new ImageIcon("/assets/buttons/menu.png");
this.setIcon(background);
this.setSize(1000,1000);
}
}
by extending JButton you give it the properties of a button.
make sure you dont have any layout by adding this to the JFrame
this.setLayout(null);
else the button will be adjusted to the layout
see http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html

Related

How to update components listening a button in java

I am a bit sorry to ask this question, since it seems to be a bit obvious, but I can't find my solution alone.
I am coding a little app in Java, and I encounter some issues "redrawing" my swing components. Basically, I want my JFrame to update when an event occurs. I managed to reproduced the issue in the code below. This code is supposed to display two buttons (which it does), and replace them with a third button when you click on the first button (which it doesn't).
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JFrame implements ActionListener {
private JButton button = new JButton("Button 1");
private JButton button2 = new JButton("Button 2");
private JButton button3 = new JButton("Button 3");
private JPanel buttons = new JPanel();
public void init() {
this.setVisible(true);
this.setSize(500,500);
buttons.add(button);
buttons.add(button2);
this.add(buttons);
this.button.addActionListener(this);
}
public void update() {
this.removeAll();
buttons.add(button3);
this.revalidate();
}
public static void main(String[] args) {
Example ex = new Example();
ex.init();
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button) {
update();
}
}
}
I am pretty sure that I am doing something wrong in the update() method. I actually have a lot of trouble to understand how works removeAll(), revalidate(), repaint() etc, and I guess that is the problem. I tried to call the same methods on the buttons panel, it almost worked but I still have a graphic bug, and I would like to do it for all the container. I also tried to call these methods on this.getContentPane(), but it doesn't work.
Can anyone try to help me with it?
You're removing all components from this (which in this case is the JFrame (as you're extending it, which isn't needed, and instead you should create an instance from it rather than inherit from it, as you're not changing the behavior of the JFrame so it's better to just create an instance of it). See: Extends JFrame vs. creating it inside the program
In this case you're adding your components in this way:
JFrame > buttons (JPanel) > JButtons
And you're trying to remove
JFrame > everything
That includes the contentPane, instead you should call.
buttons.removeAll()
Inside the update() method.
And also call this.repaint() so your update() method should become:
public void update() {
buttons.removeAll();
buttons.add(button3);
this.revalidate();
this.repaint();
}
Or the best approach is to use CardLayout as recommended by #AndrewThompson in the comment below. This way you don't have to handle removing / repainting for each component, as CardLayout will do it for you. For example
this works,
public void update() {
buttons.remove(button);
buttons.remove(button2);
buttons.add(button3);
this.revalidate();
this.repaint();
}

Java button hovering

I'm new to Java programming and I'd like to know how to mess around with buttons, I have created a "Home Screen" and some buttons as well as text, however it's not as advanced as I'd like it to be, I want to know how to create things like image effects, so let's say I hover over a button, I want it to display a glowing animation behind it, or since I don't have that animation, if there's no easy way to create it, just displaying an image behind it is alright, also I don't have anything happening when pressing the button bcs IDK how to do that yet so if you could help with that it'd be awesome!
Here's the code I currently have:
package Menu;
import java.awt.FlowLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class BackgroundPanel extends JFrame {
private BufferedImage image;
public BackgroundPanel() {
ImageIcon icon = new ImageIcon("image_path.png");
JButton btn = new JButton(icon);
btn.setOpaque(false);
btn.setContentAreaFilled(false);
btn.setBorderPainted(false);
btn.setFocusPainted(false);
try {
image = ImageIO.read(new File("image_path.jpg"));
// Set your Image Here.
this.setContentPane(new JLabel(new ImageIcon(image)));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JPanel panel = new JPanel();
panel.add(new JLabel("Username:"));
panel.add(new JTextField("",20));
panel.add(new JLabel("Password:"));
panel.add(new JTextField("",20));
panel.add(btn);
//Adding components to Panel and JFrame
this.add(panel);
// JFrame Properties
this.setSize(1280,720);
this.setLayout(new FlowLayout());
this.setResizable(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Panel");
this.setVisible(true);
}
public static void main(String[] args) {
new BackgroundPanel();
}
}
[...] also I don't have anything happening when pressing the button bcs IDK how to do that yet so if you could help with that it'd be awesome [...]
You need to add an ActionListener to your button. There are various other ways to detect if the button was pressed, but this one is the (in my opinion) easiest. This is how you do it:
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
// code you write in here will be executed if the button was pressed
}
});
[...] let's say I hover over a button, I want it to display a glowing animation behind it, or since I don't have that animation, if there's no easy way to create it, just displaying an image behind it is alright [...]
For this, you'll have to deal with JLayeredPanes and MouseListeners. Here is an example that I created "on the run"; the layouting is very dirty and has to be improved. Anyhow, you'll notice that once you hover over the button, a black-bordered box containing LA- -LL! will appear behind the button. That's a JLabel and you can use it to display images and such by using the JLabel.setIcon method.
let's say I hover over a button, I want it to display a glowing animation behind it, or since I don't have that animation, if there's no easy way to create it, just displaying an image behind it is alright
This is not that easy, it requires jumping through a whole bunch of hoops, especially when the button isn't rectangle.
A while I ago a did a prototype of a "validation highlighter" which highlighted invalid fields, it makes use of JXLayer library, but which should be convertible to use the included JLayer library on the core libraries
See How can I change the highlight color of a focused JComboBox for more details
The other possibility we'd be to create a custom JPanel and override its paintComponent method and paint your effect there. You would place your button it and with a combination of a a layout manager and borders you should be able to get the button positioned where you need it.
The problem with this, is it will effect the over layout of your form, as the effect will be considered while the primary form is laid out
I really don't have anything happening when pressing the button bcs IDK how to do that yet so if you could help with that it'd be awesome
I suggest you have a look at How to use buttons and How to write ActionListeners

Hide a swing component without revalidating the layout?

If I set up a JFrame with some components and a layout manager, which initially looks perfectly fine, and then later due to some condition (say, clicking a button) I hide one of those components - the layout manager shuffles all the components around again.
See example code - initially 3 buttons appear. When you click the Hide button, the Hide button is hidden - but the two outer buttons then squash together. When you click the show button, they move apart again to make space. How can I stop that from happening, so that after I call pack (), components stay where they are no matter if they later become hidden?
In my real code I'm doing this with GridBagLayout, but used FlowLayout in the example below because its simpler and less code, and shows exactly the same behaviour.
I can only think of nasty ways of doing this, like using .setEnabled (false) instead of .setVisible (false), and then overriding the component's paintComponent () method to not draw the component when it is disabled.
It seems the exact opposite problem to here - Hide a button from Layout in Java Swing - where is complaining that hidden buttons do still take up space :) But there's no sample code there to show it working in that way.
Many thanks for any suggestions :)
Example:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RevalidateWhenSetChildInvisibleExample
{
private JButton button1;
private JButton button2;
private JButton button3;
public void run ()
{
// Set up action
Action hideButtonAction = new AbstractAction ()
{
#Override
public void actionPerformed (ActionEvent e)
{
button2.setVisible (false);
}
};
hideButtonAction.putValue (Action.NAME, "Hide");
Action showButtonAction = new AbstractAction ()
{
#Override
public void actionPerformed (ActionEvent e)
{
button2.setVisible (true);
}
};
showButtonAction.putValue (Action.NAME, "Show");
// Set up buttons
button1 = new JButton ("Dummy");
button2 = new JButton (hideButtonAction);
button3 = new JButton (showButtonAction);
// Set up content pane
JPanel contentPane = new JPanel ();
contentPane.setLayout (new FlowLayout ());
contentPane.add (button1);
contentPane.add (button2);
contentPane.add (button3);
// Set up frame
JFrame frame = new JFrame ();
frame.setContentPane (contentPane);
frame.pack ();
frame.setVisible (true);
}
public static void main (String args [])
{
SwingUtilities.invokeLater (new Runnable ()
{
public void run ()
{
new RevalidateWhenSetChildInvisibleExample ().run ();
}
});
}
}
You could use a CardLayout and then swap the button with an empty JPanel.
Read the section from the Swing tutorial on How to Use CardLayout for more information and examples.
The problem is the layout manager, which is not really a problem here because it is just doing its job. You could set the layout to null and then set the bounds for every button; this way they will NEVER move unless you change their position.
panel.setLayout(null);
button1.setBounds(10,10,50,20);
button2.setBounds(70,10,50,20);
button3.setBounds(xPos,yPos,width,height);
Another way is to use the GridLayout:
contentPane.setLayout(new GridLayout());
I tested it, and it worked fine, since the component did not get removed it stays the same.
Also, you should add the following to your code:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This makes the program exits when the JFrame is closed; without it the program still runs at the background.

The Switch Statement and page content control

I've been trying to create a class that decides which JPanel gets printed on a JFrame. The JPanels are "addNew" and "searchPanel". addNew is created by a class called "AddNew" and it contains content items that enables a user add new content into a database.
The searchPanel panel is in a different class "SearchPanel" that enables a user search content in a database.
The JFrame on which the two JPanels are drawn is in its own class and has only two buttons "Add new item" and "Search". No JPanel is drawn until one of these buttons is clicked.
Theres a third class that determines which JPanel gets drawn on the JFrame via a switch statement depending on a value (1 or 2) passed on "buttonClick", which is where I think I'm having problems.
My code so far:
import Panels.AddNew;
import SearchWakili.SearchPanel;
import javax.swing.JPanel;
public class Redirect {
public static JPanel panelRedirect = new JPanel();
public static JPanel value;
public static JPanel pageAddNewFunction () {
AddNew addNew = new AddNew();
panelRedirect.add(addNew);
return panelRedirect;
}
public static JPanel SearchPanelFunction () {
SearchPanel searchPanel = new SearchPanel();
panelRedirect.add(searchPanel);
return panelRedirect;
}
public static JPanel pageRedirect (int pageID) {
switch (pageID) {
case 1:
value = pageAddNewFunction();
break;
case 2:
value = SearchPanelFunction();
break;
}
return value;
}
}
The code does nothing. I don't get any code error messages, though. The JPanels print fine when I call the directly without redirecting via the "Redirect" class.
What is it that I'm doing wrong, and is there any other way I can use an independent class to decide on a JPanel to be drawn depending on the button clicked?
Thank you very much in advance.
Oh! And I don't want to use CardLayout. I'd like to learn how to code this myself.
Part of the code that draws the JFrame:
import java.awt.Color;
import java.lang.ProcessBuilder.Redirect;
import javax.swing.JFrame;
public class FrameContainer {
public static JFrame Home;
public static void createAndShowGUI() {
// Create and set up the Frame
JFrame.setDefaultLookAndFeelDecorated(true);
Home = new JFrame();
Home.setUndecorated(true);
Home.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Home.setResizable(false);
Home.setBounds(0, 0, 400, 400);
Home.setBackground(Color.gray);
// Redirect redirect = new Redirect();
Home.add(Redirect.panelRedirect);
// Display the window
Home.pack();
Home.setVisible(true);
}
}
Part of the Code that declares the event:
public class Home {
// The method that calls the type of JPanel (1) to be drawn
private void mouseClickedAddNew(java.awt.event.MouseEvent evt) {
// FrameContainer.createAndShowGUI();
Redirect.pageRedirect(1);
}
}
First off, it is not a good practice to initialize modules on request.
In other words, you should have a method that gets called in the main class constructor that will allocate space for the variables and do calculations, so when you actually click the button, the only command that you are running is the one that makes each panel visible.
This is most likely why what you are doing does not work.
So just make the code initially load both panels, then when a button is clicked, do show() or hide() (I believe those are the methods, but I don't use Swing often enough to know, so the wording may be different).

How to draw a colored rectangle on a JButton?

I'm going to enhance an application with a Swing UI, to allow the user to pick colors so they're not stuck with the default color choices.
It is common for other applications to have shaded rectangles drawn on each button that activates a color selector, with the rectangle's color changing accordingly when a new color is selected. I am trying to achieve the same effect by placing a small JPanel with the selected color on the button, but that results in a tiny square in the middle of the button, instead of filling most of the surface of the button.
I figure another way would be to dynamically generate rectangular icons with the colors and then add the appropriate icon to each button, but surely there must be a simpler way?
put there JButton.setIcon with expected Rectangle, for example
EDIT
I am trying to achieve the same effect by placing a small JPanel with the selected color on the button, but that results in a tiny square in the middle of the button, instead of filling most of the surface of the button.
only JFrame (BorderLayout) and JPanel (FlowLayout) have got pre-implemented LayoutManager, for rest of JComponents (add one JComponent to the another JComponent) you have to define LayoutManager, please read this thread
Here is an example using setBackground that works for me:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String... args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
final JButton button = new JButton("Hello");
button.setOpaque(true);
panel.add(button);
button.setBackground(Color.RED);
button.setOpaque(true);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Color c = JColorChooser.showDialog(button, "Choose a color", button.getBackground());
if (c != null) {
button.setBackground(c);
}
}
});
frame.setContentPane(panel);
frame.setPreferredSize(new Dimension(800, 600));
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Every swing component is drawn using the JComponent.drawComponent(...) method, you can override the default behavior if you want. For example, to make a panel like you suggest. It is worth noting though, that you can change a jpanels background color to achieve the exact same thing.
JColorChooser chooser = new JColorChooser(Color.BLACK);
chooser.setVisible(true);
Color color = chooser.getColor();
if (color!=null) {
colorPanel.setBackground(color);
}
Where colorPanel would be your JPanel indicating your color.

Categories