JRadioButton selection doesn't show on GUI until visible in Windows LaF - java

I'm currently working on a project that requires the state of a JRadioButton to change when the record being viewed is updated.
We've had a few clients complain to us that when the record changes, if the JRadioButton is off-screen, it won't be updated until the screen is shown. This behavior seems to be a result of using the Windows Look and Feel, as it doesn't seem to happen when it is not set.
The code example below demonstrates this.
The default selected JRadioButton is 'Cat', so by selecting the 'Dog' JButton and then changing tab to 'Question', you can see the JRadioButton transition occur.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* Example of JRadioButton not updating until it's parent panel becomes visible.
*/
public class RadioButtonExample extends JPanel implements ActionListener {
public static final String CAT = "Cat";
public static final String DOG = "Dog";
private final JRadioButton radCat;
private final JRadioButton radDog;
private final ButtonGroup grpAnimal;
public RadioButtonExample() {
super(new BorderLayout());
JLabel lblQuestion = new JLabel("Are you a cat or dog person?");
radCat = new JRadioButton(CAT);
radCat.setActionCommand(CAT);
radCat.setSelected(true);
radDog = new JRadioButton(DOG);
radDog.setActionCommand(DOG);
grpAnimal = new ButtonGroup();
grpAnimal.add(radCat);
grpAnimal.add(radDog);
JPanel pnlQuestion = new JPanel(new GridLayout(0, 1));
pnlQuestion.add(lblQuestion);
pnlQuestion.add(radCat);
pnlQuestion.add(radDog);
JButton btnSetCat = new JButton(CAT);
btnSetCat.setActionCommand(CAT);
btnSetCat.addActionListener(this);
JButton btnSetDog = new JButton(DOG);
btnSetDog.setActionCommand(DOG);
btnSetDog.addActionListener(this);
JPanel pnlButtons = new JPanel(new GridLayout(0, 1));
pnlButtons.add(new JLabel("Update your choice of animal"));
pnlButtons.add(btnSetCat);
pnlButtons.add(btnSetDog);
JTabbedPane tabPane = new JTabbedPane();
tabPane.addTab("Buttons", pnlButtons);
tabPane.addTab("Question", pnlQuestion);
add(tabPane, BorderLayout.LINE_START);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
}
public void actionPerformed(ActionEvent evt) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
grpAnimal.clearSelection();
if (CAT.equals(evt.getActionCommand())) {
grpAnimal.setSelected(radCat.getModel(), true);
}
else if (DOG.equals(evt.getActionCommand())) {
grpAnimal.setSelected(radDog.getModel(), true);
}
}
});
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("RadioButtonExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new RadioButtonExample();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Comment out the line below to run using standard L&F
setLookAndFeel();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void setLookAndFeel() {
try {
// Set Windows L&F
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
}
catch (Exception e) {
// handle exception
}
}
}
Is there a way to prevent this behavior or even speed it up to make it less noticeable for our users?

You might be able to disable the animation by specifying the swing.disablevistaanimation Java system property:
java -Dswing.disablevistaanimation="true" your-cool-application.jar
In the com.sun.java.swing.plaf.windows.AnimationController class, there is a VISTA_ANIMATION_DISABLED field that is initialized to the swing.disablevistaanimation property. This field determines whether the paintSkin method calls the skin.paintSkinRaw method if animations are disabled or else starts to get into the animations.
It works on my Windows 8.1 laptop with Java 8 (jdk1.8.0_65), so its effect does not seem to be limited to Windows Vista only.

Related

Toggle the visibility of Jlabel and JPanel

I am trying to toggle the visibility of JLable and JPanel. Both are in initial case in visible state. After pressing a Button, they should be invisible for two seconds. After this time they are going to be visible again. In adddition, there are two checkBoxes on the JPanel, which are grouped by ButtonGroup. The selection should be cleared after pressing the Button.
For solving I wrote the following code:
package Aufgaben;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;
public class Aufgabe1 extends JFrame {
private JPanel contentPane;
private JPanel checkPanel;
private JPanel pointPanel;
private JRadioButton rdbtnJa;
private JRadioButton rdbtnNein;
private ButtonGroup btnGroup;
private JButton btnStart;
private JLabel lblX;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Aufgabe1 frame = new Aufgabe1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Aufgabe1() {setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 700, 300);
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(null);
btnStart = new JButton("Start");
btnStart.setBounds(0, 0, 684, 23);
contentPane.add(btnStart);
checkPanel = new JPanel();
checkPanel.setBounds(0, 229, 684, 33);
contentPane.add(checkPanel);
btnGroup = new ButtonGroup();
rdbtnJa = new JRadioButton("Ja");
checkPanel.add(rdbtnJa);
btnGroup.add(rdbtnJa);
rdbtnNein = new JRadioButton("Nein");
checkPanel.add(rdbtnNein);
btnGroup.add(rdbtnNein);
pointPanel = new JPanel(new BorderLayout());
pointPanel.setBackground(Color.BLACK);
pointPanel.setBounds(0, 23, 684, 209);
contentPane.add(pointPanel);
lblX = new JLabel("X");
lblX.setForeground(Color.WHITE);
lblX.setVerticalAlignment(JLabel.CENTER);
lblX.setHorizontalAlignment(JLabel.CENTER);
pointPanel.add(lblX, BorderLayout.CENTER);
run();
}
public void run() {
System.out.println("----------");
System.out.println("Method run()");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("btn actionPerformed()");
createLightPoint();
}
});
}
private void createLightPoint() {
System.out.println("----------");
System.out.println("Method createLightPoint()");
btnGroup.clearSelection();
lblX.setVisible(false);
// lblX.repaint();
// pointPanel.repaint();
checkPanel.setVisible(false);
// checkPanel.repaint();
System.out.println("Bevor Sleep");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("After Sleep");
lblX.setVisible(true);
// lblX.repaint();
checkPanel.setVisible(true);
// checkPanel.repaint();
}
}
As you can see I tried to solve the problems (what I described above) over the function .setVisibility() as well .repaint(). I tried the functions .show() and .hide althought they are deprecatet as well.But in any case, it doesn't work.
I already read the following posts:
Show/Hide JLabel with button?
https://softwareengineering.stackexchange.com/questions/233068/is-better-show-hide-or-setvisiblebool-visible
But none of them could help the solve my problem.
I hope you can Help me.
Don't use sleep() on Event Dispatch Thread - it will prevent the thread from processing painting and other UI related events and the UI will become frozen. See The Event Dispatch Thread tutorial for more details.
You can use Swing timer instead, see How to Use Swing Timers tutorial for examples.

Java - a simple PlayerAction counter to practice object-oriented programming

I am learning the basics of Java and decided to practice working on objects, by making a simple program which I called a 'PlayerAction Counter'. It does nothing more that counting an 'action' which is fired by clicking '+1' button and additionally reset the counter, when the 'Reset' button is clicked. For this case I've made a Application.java which holds the main method and launches the program, Interface.java for GUI, EventHandling.java for events and Person.java which holds interface components and methods to change their state. It looks like this:
My idea was to create the window in Interface class and set it's layout, then create two Person objects called PlayerOne and Player Two. The Person class creates two labels and two buttons and set a label of one by a constructor parameter.
I've managed to add these two objects' elements to the GUI by getters and it looks just fine. I added ActionListener to both buttons in Person class and it also works just fine.
I am stuck on getting back to Person fields and methods from EventHandling class. I've created a setValueLabel() which increases by one a value of 'action' and sets it on the label, but I have to idea how to launch the method from another class. I can not make another object inside (throws StackOverFlow error), but should it not somehow refer to those two made in Interface class?
Here is the code:
Application.java
import java.awt.EventQueue;
public class Application {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Interface().setVisible(true);
}
});
}
}
Interface.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
public class Interface extends JFrame {
private JLabel titleLabel;
private JPanel mainPanel;
private JPanel leftPanel, rightPanel;
private JSeparator separator;
Person PlayerOne = new Person("PlayerOne");
Person PlayerTwo = new Person("PlayerTwo");
public Interface() {
//Basic init
setTitle("PlayerAction Counter");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//Layout
mainPanel = new JPanel();
add(mainPanel);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
leftPanel = new JPanel();
rightPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
leftPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(leftPanel, BorderLayout.WEST);
separator = new JSeparator(SwingConstants.VERTICAL);
mainPanel.add(separator, BorderLayout.CENTER);
titleLabel = new JLabel("PlayerAction Counter");
mainPanel.add(titleLabel, BorderLayout.PAGE_START);
//Components init
PlayerTwo.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getPersonLabel());
PlayerTwo.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueLabel());
PlayerTwo.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueUpButton());
PlayerTwo.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueResetButton());
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
rightPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(rightPanel, BorderLayout.EAST);
PlayerOne.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getPersonLabel());
PlayerOne.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueLabel());
PlayerOne.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueUpButton());
PlayerOne.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueResetButton());
pack();
}
}
Person.java
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Person {
private JLabel personLabel;
private JLabel valueLabel;
private JButton valueUpButton;
private JButton valueResetButton;
private int actionValue = 0;
public Person(String s) {
personLabel = new JLabel(s);
setComponents();
}
private void setComponents() {
valueUpButton = new JButton("+1");
valueResetButton = new JButton("Reset");
valueLabel = new JLabel(""+actionValue);
EventHandling eventHand = new EventHandling(valueUpButton, valueResetButton);
valueResetButton.addActionListener(eventHand);
valueUpButton.addActionListener(eventHand);
}
public void setValueLabel() {
actionValue++;
valueLabel.setText("" +actionValue);
}
public JLabel getPersonLabel() {
return personLabel;
}
public JLabel getValueLabel() {
return valueLabel;
}
public JButton getValueUpButton() {
return valueUpButton;
}
public JButton getValueResetButton() {
return valueResetButton;
}
}
EventHandling.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
public class EventHandling implements ActionListener {
private JButton valueUpButton;
private JButton valueResetButton;
public EventHandling(JButton valueUpButton, JButton valueResetButton) {
this.valueUpButton = valueUpButton;
this.valueResetButton = valueResetButton;
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == valueUpButton) {
//no idea how to launch Person.setValueLabel();
//creating new Person object throws StackOverFlow error and I doubt that's the way
}
else if (event.getSource() == valueResetButton) {
}
}
}
I do hope my issue is understandable. The question is: how should it be done?
Please keep in mind that I am a complete rookie and try to learn OOP, but am very confused by it. Please point my mistakes in thinking and the code.
Any feedback will be greatly appraciated.
Thank you.

Java memory consumption for Swing GUI

I have the following piece of code,It just opens a JTextPane in a Jframe..
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultCaret;
public class TextPane extends JFrame{
public static TextPane instance;
private static JTextPane pane = new JTextPane();
private static JScrollPane scroll = new JScrollPane();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TextPane.getInstance().init();
}
});
}
private static TextPane getInstance() {
if(null == instance){
instance = new TextPane();
}
return instance;
}
private void init() {
pane.setFont(new Font("Courier new", Font.PLAIN, 12));
pane.setLayout(new BorderLayout());
pane.setBackground(Color.black);
pane.setForeground(Color.white);
pane.setCaretColor(Color.green);
pane.setDragEnabled(false);
DefaultCaret caret = (DefaultCaret) pane.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
scroll.setViewportView(pane);
add(scroll);
setTitle("Dummy");
setSize(500 , 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(true);
setVisible(true);
}
}
To analyze memory used by application i ran this code and once the GUI comes i verified Memory(Private working set) in Task manager ,(By right click on this application in Task manager Application tab and Go to Process).
For simply opening the GUI it showed around 16000K . is it normal?? If not how can i check the actual memory usage, which we can say this is the memory used by this application(For opening GUI).
Please help.

Java GUI: Image will be overwritten, Path the same -> show it in the frame (image still the same)

I want to show a changing image on my frame. The imagepath is always the same, but the image will be getting overwritten every 10 seconds from another program.
The problem is that the image is not changing when I overwrite it with another image with the same name. So in my understanding: Compiler looks every look in the path and gets the image -> when the image changed it will be changed on the frame!
I hope you understand my problem and somebody could help me.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GUI extends JFrame{
public ImageIcon imageBar;
public JLabel labelimage1;
private JLabel labelimage2;
private JLabel bar1 = new JLabel();
private JLabel bar2 = new JLabel();
private JLabel bar3 = new JLabel();
private JLabel bar4 = new JLabel();
private JLabel bar5 = new JLabel();
private JButton buttonBar1 = new JButton("1");
private JButton buttonBar2 = new JButton("2");
private JButton buttonBar3 = new JButton("3");
private JButton buttonBar4 = new JButton("4");
private JButton buttonBar5 = new JButton("5");
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private JPanel panel3 = new JPanel();
private JFrame window = new JFrame("Interface");
public GUI(){
//set the layouts
panel1.setLayout(new GridLayout(1, 2));
panel2.setLayout(new GridLayout(2, 1));
panel3.setLayout(new GridLayout(2, 5));
//place Panel2 and Panel3 in the window
panel1.add(panel2);
panel1.add(panel3);
//----Panel2
//refreshImage();
//----Panel3
panel3.add(buttonBar1); //add the bars 1-5 on panel3
panel3.add(buttonBar2);
panel3.add(buttonBar3);
panel3.add(buttonBar4);
panel3.add(buttonBar5);
//configure the frame
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setSize(800, 400);
window.getContentPane().add(panel1);
}
public void refreshImage() {
panel2.removeAll(); //delete the old panel
//panel2.repaint();
//panel2.revalidate()
DrawImage pan = new DrawImage();
panel2.add(pan);
panel2.add(labelimage2);
}
}
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class DrawImage extends JPanel implements ActionListener{
private ImageIcon image;
public DrawImage(){
image = new ImageIcon("C:\\Users\\usuario\\Desktop\\image.png");
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
image.paintIcon(this, g, 50, 50);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
import java.io.File;
public class Main {
public static void main(String[] args) {
GUI Interface = new GUI();
while(true)
{
Interface.refreshImage();
try {
Thread.sleep(5000); //wait for 5000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Thank you very much!
The likely cause is Java is caching the image in memory, associated with the source name. So rather then trying to reload the image again, Java simply returns the cached version.
You could use ImageIcon#getImage#flush to force Java to reconstruct the image
Problems
You are calling refreshImage from a Thread other then the Event Dispatching Thread, this could cause issues with the updating of the components and cause rendering artifacts
You are forcefully removing the DrawImage pane and adding a new instance, rather the trying to reload the image
You're calling repaint within the paintComponent method, don't do this...
You should consider using a Swing Timer, which will allow you to schedule a regular update and be notified within the context of the Event Dispatching Thread.
You could provide a simple refresh method which flushes the current ImageIcon and schedule a repaint of the panel...or you could just use a JLabel and save your self the time
An example of Image#flush
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SlideShow {
public ImageIcon imageBar;
public static void main(String[] args) {
new SlideShow();
}
public SlideShow() {
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 DrawImage());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawImage extends JPanel {
private ImageIcon image;
public DrawImage() {
image = new ImageIcon("D:\\thumbs\\image.png");
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
refresh();
}
});
timer.start();
}
public void refresh() {
image.getImage().flush();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
}
The problem with this, is because the image data is loaded in a background thread, it won't may no be available when the component is first repainted, which could make the component appear to flicker.
A better approach would be to use ImageIO.read, which will ensure that the image is fully loaded before the method returns, the draw back here is that could cause the application to "pause" momentary as the image is loaded, personally, I'd use the refresh method to stop the the Timer (or set the Timer to non-repeating), start a background Thread to load the image (using ImageIO.read) call repaint (which is thread safe) and restart the Timer...
Your while (true) loop risks typing up the Swing event thread locking your program. If it doesn't do that, then you risk unpredictable threading issues by making Swing calls off of the event Thread. These problems can be solved easily by your using a Swing Timer not a while true loop to do your swapping.
Rather than removing and adding components, why not simply display images as ImageIcons within a single non-swapped JLabel.
To swap images here, simply call setIcon(...) on the JLabel.
For an example of using a Swing Timer to swap images, please check out my answer to a similar question here.
For example:
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TimerImageSwapper {
public static final String[] IMAGE_URLS = {
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_02.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_04.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_08.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_05.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_06.png" };
private ImageIcon[] icons = new ImageIcon[IMAGE_URLS.length];
private JLabel mainLabel = new JLabel();
private int iconIndex = 0;;
public TimerImageSwapper(int timerDelay) throws IOException {
for (int i = 0; i < icons.length; i++) {
URL imgUrl = new URL(IMAGE_URLS[i]);
BufferedImage image = ImageIO.read(imgUrl);
icons[i] = new ImageIcon(image);
}
mainLabel.setIcon(icons[iconIndex]);
new Timer(timerDelay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
iconIndex++;
iconIndex %= IMAGE_URLS.length;
mainLabel.setIcon(icons[iconIndex]);
}
}).start();
}
public Component getMainComponent() {
return mainLabel;
}
private static void createAndShowGui() {
TimerImageSwapper timerImageSwapper;
try {
timerImageSwapper = new TimerImageSwapper(5 * 1000);
JFrame frame = new JFrame("Timer Image Swapper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(timerImageSwapper.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Using custom ComboBoxUI

I am trying to change the look of JComboBox components by extending BasicComboBoxUI class. The problem is that when I use the extended MyComboBoxUI class, combo boxes stop functioning properly.
This SSCCE is demonstrating my problem. The first combo box displays the selected item of the second combo box, and the first combo box doesn't have arrow button painted and items cannot be selected.
Note: I had no problem changing JButton components in this manner.
Main class:
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Main {
public static void main(String[] args) {
UIManager.put("ComboBoxUI", "MyComboBoxUI");
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
ContentPane contentPane = new ContentPane();
frame.setContentPane(contentPane);
frame.setSize(600, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
ContenPane class:
import java.awt.FlowLayout;
import javax.swing.JComboBox;
import javax.swing.JPanel;
public class ContentPane extends JPanel {
public ContentPane() {
setLayout(new FlowLayout());
JComboBox<String> firstComboBox = new JComboBox<>();
firstComboBox.addItem("firstComboBox - 1. item");
firstComboBox.addItem("firstComboBox - 2. item");
firstComboBox.addItem("firstComboBox - 3. item");
add(firstComboBox);
JComboBox<String> secondComboBox = new JComboBox<>();
secondComboBox.addItem("secondComboBox - 1.item");
secondComboBox.addItem("secondComboBox - 2. item");
secondComboBox.addItem("secondComboBox - 3. item");
add(secondComboBox);
}
}
MyComboBoxUI class:
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboBoxUI;
public class MyComboBoxUI extends BasicComboBoxUI {
private static MyComboBoxUI myComboBoxUI = new MyComboBoxUI();
public static ComponentUI createUI(JComponent component) {
return myComboBoxUI;
}
}
I think you want:
return new MyComboBoxUI();
When you have a static variable it means every combobox will share the same instance of the UI.

Categories

Resources