My Java Swing application uses updateUiChanged() to resize fonts after its jFrame has been resized by the user. But updateUiChanged() is getting triggered when the jFrame is minimized and then maximized which is causing problem
I tried to trap the minimize and maximize events with the following, but they do not execute at all or they execute after the updateUiChanged() which is too late.
How can I trap the minimize and maximize before the updateUiChanged()
See below for the updateUiChanged implementation.
Thanks
private WindowListener wndMinMax;
wndMinMax = new WindowAdapter(){
public void windowIconified(WindowEvent e){
if(debug)debug("Window Iconfied!!");
return;
}
public void windowDeiconified(WindowEvent e){
if(debug)debug("Window DeIconfied!!");
return;
}
};
this.addWindowListener(wndMinMax);
addComponentListener(new ComponentAdapter()
{
public void componentResized(ComponentEvent e) //V.43
{
if (e.getSource() instanceof JFrame) //V.43
{
updateUiChanged((int) e.getComponent().getWidth(),
(int) e.getComponent().getHeight());
}
}
});
You can use EventQueue.invokeLater to make sure your updateUiChanged call takes place after the WindowEvent. You can track the occurrence of a WindowEvent in a private instance field, so your delayed ComponentListener code can know if the resize was paired with a WindowEvent:
private boolean iconifyStateChanged;
// ...
wndMinMax = new WindowAdapter(){
public void windowIconified(WindowEvent e){
if(debug)debug("Window Iconfied!!");
iconifyStateChanged = true;
}
public void windowDeiconified(WindowEvent e){
if(debug)debug("Window DeIconfied!!");
iconifyStateChanged = true;
}
};
this.addWindowListener(wndMinMax);
addComponentListener(new ComponentAdapter()
{
public void componentResized(ComponentEvent e) //V.43
{
if (e.getSource() instanceof JFrame) //V.43
{
// This will run after any pending WindowEvents.
EventQueue.invokeLater(() -> {
if (!iconifyStateChanged)
{
updateUiChanged(e.getComponent().getWidth(),
e.getComponent().getHeight()));
}
iconifyStateChanged = false;
});
}
}
});
(getWidth() and getHeight() already return int values, so a cast to int is not necessary.)
Related
I want to update my look and feel by JRadioButtonMenuItem. And I searching in Stackoverflow but what I find was a big bunch of code in 1 class. For me as a beginner its easier to seperate function in a special class.
That is my Frame-Class.
public class CalenderFrame extends JFrame {
public CalenderFrame() throws HeadlessException {
createFrame();
}
public void createFrame() {
setJMenuBar(CalenderMenuBar.getInstance().createMenu());
setTitle("Calender");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(400, 300));
pack();
setLocationRelativeTo(null);
setVisible(true);
}
}
And that is my MenueBar Class. I just give a short one of Code that is specific for this question. This class is an Singleton.
public JMenuBar createMenu() {
JMenu lookAndFeelMenu = new JMenu("Look & Feel");
JRadioButtonMenuItem lAndFWindowsItem = new JRadioButtonMenuItem("Windows",true);
lAndFWindowsItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFWindowsItem) {
lAndFAction(1);
}
}
});
JRadioButtonMenuItem lAndFMetalItem = new JRadioButtonMenuItem("Metal",false);
lAndFMetalItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFMetalItem) {
lAndFAction(2);
}
}
});
JRadioButtonMenuItem lAndFMotifItem = new JRadioButtonMenuItem("Motif", false);
lAndFMotifItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFMotifItem) {
lAndFAction(3);
}
}
});
ButtonGroup group = new ButtonGroup();
group.add(lAndFWindowsItem);
group.add(lAndFMetalItem);
group.add(lAndFMotifItem);
lookAndFeelMenu.add(lAndFWindowsItem);
lookAndFeelMenu.add(lAndFMetalItem);
lookAndFeelMenu.add(lAndFMotifItem);
}
public void lAndFAction(int counter) {
try {
String plaf = "";
if (counter == 1) {
plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
} else if (counter == 2) {
plaf = "javax.swing.plaf.metal.MetalLookAndFeel";
} else if (counter == 3) {
plaf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
}
UIManager.setLookAndFeel(plaf);
//SwingUtilities.updateComponentTreeUI(this);
} catch (UnsupportedLookAndFeelException ue) {
System.err.println(ue.toString());
} catch (ClassNotFoundException ce) {
System.err.println(ce.toString());
} catch (InstantiationException ie) {
System.err.println(ie.toString());
} catch (IllegalAccessException iae) {
System.err.println(iae.toString());
}
}
}
I hope you guys can help me.
I'm not sure what your problem actually is. But, you must update your components after changing the LaF. According to the Look and Feel Documentation:
Changing the Look and Feel After Startup
You can change the L&F with setLookAndFeel even after the program's
GUI is visible. To make existing components reflect the new L&F,
invoke the SwingUtilities updateComponentTreeUI method once per
top-level container. Then you might wish to resize each top-level
container to reflect the new sizes of its contained components. For
example:
UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
Therefore, you would need a reference to the frame holding the components in your UI. An idea would be doing something like:
public class CalendarMenuBar {
// Add this field to tour factory
private static JFrame frameThatWillBeUpdated;
// ... (Your code goes here)
// update this method to receive the reference of the frame which will
// need to be refreshed (update the GUI)
public JMenuBar createMenu(JFrame frame) {
// sets the reference for the frame
frameThatWillBeUpdated = frame;
// ... (the rest of your code for this method)
}
// ...
// Update this method to refresh the frame
public void lAndFAction(int counter) {
try{
// ... (your code)
// Set the LaF
UIManager.setLookAndFeel(plaf);
// Update the component tree (frame and its children)
SwingUtilities.updateComponentTreeUI(frameThatWillBeUpdated);
// repack to resize
frame.pack();
} catch(Exception ex){
// Your catches
}
}
}
And here is how you use it when creating your frame (inside your CalenderFrame class):
public void createFrame() {
// use this frame as reference
setJMenuBar(CalenderMenuBar.getInstance().createMenu(this));
// ... (your code goes here)
}
I want to show a popupmenu, while using Metal L&F it will do these behavior.
single click: it printed "pressed" and show menu
double pressed: it printed "pressed" and show menu too.
Yes it is I needed. But when using WindowsLookAndFeel, it not same as those.
when twice pressed it just hide menu and not printed "pressed". why it have difference behavior between two L&F?
import javax.swing.*;
import java.awt.event.*;
public class Popup {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(300, 300);
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
ex.printStackTrace();
}
JPopupMenu menu = new JPopupMenu();
menu.add("item");
f.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
System.out.println("pressed");
}
});
f.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
menu.show(f, e.getX(), e.getY());
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
boolean consumeEvent = UIManager.getBoolean("PopupMenu.consumeEventOnClose");
// Consume the event so that normal processing stops.
if(consumeEvent && !(src instanceof MenuElement)) {
me.consume();
}
I have found the problems, because of this property is different
so end it
There is a class AgentHome which extends JFrame.
AgentHome has a JPanel rem_panel. Checkboxes are added dynamically into rem_panel…number of checkboxes depending on the number of entries in the database table from where the text to be displayed by the textboxes are read.
AgentHome has an integer variable x and a checkbox arraylist rem_cbarr.
rem_cbarr stores the checkboxes as they are created and added to rem_panel.
I am trying to set the background color of these checkboxes to red when the variable x is set to 1 as the program executes.
I have implemented the TickerBehaviour of JADE framework to check if the variable x is set to 1.
I am unable to set the background color of the checkboxes to red. This is the code I have implemented. Please help. Thanks.
public void setup()
{
Behaviour loop = new TickerBehaviour( this, 2000 )
{
protected void onTick() {
timer();
}
};
addBehaviour( loop );
}
public void timer()
{
AgentHome hm=new AgentHome();
if(hm.x==1)
{
for (int i = hm.rem_cbarr.size()-1; i>=0; i--)
{
JCheckBox cb=hm.rem_cbarr.get(i);
cb.setBackground(Color.red);
hm.rem_panel.revalidate();
hm.rem_panel.repaint();
}
}
}
GUI operations need to be done on the EDT (Event Dispatcher Thread). In java this happens by calling SwingUtilities.invokeLater(Runnable run).
A number of things...
UI components should only ever be updated within the context of the Event Dispatching Thread
You should never perform any action which might block the Event Dispatching Thread (like using loops or Thread#Sleep to try and update the screen)
The Event Dispatching Thread is responsible for dispatching paint updates...
JCheckBox is transparent by default.
public class FlashCheckBox {
public static void main(String[] args) {
new FlashCheckBox();
}
public FlashCheckBox() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new FlashyCheckBox());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class FlashyCheckBox extends JCheckBox {
private final Color defaultBackground;
private int flash;
private Timer flashTimer;
public FlashyCheckBox() {
defaultBackground = getBackground();
flashTimer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
flash++;
if (flash % 5 == 0) {
setOpaque(false);
setBackground(defaultBackground);
flashTimer.stop();
} else if (flash % 2 == 0) {
setBackground(Color.YELLOW);
setOpaque(true);
} else {
setBackground(defaultBackground);
setOpaque(false);
}
repaint();
}
});
flashTimer.setRepeats(true);
flashTimer.setCoalesce(true);
flashTimer.setInitialDelay(0);
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
flashTimer.restart();
}
});
}
}
}
Edited at the request of commenters. I hope this is compliant.
First post! Trying to understand why my Swing application will not advance from one panel to the next. Here is the general flow of the code :
public class MainWindow {
JFrame mainFrame;
ChangeablePanel currentScreen; // abstract and extends JPanel, has getters &
setters for a Timer (swing timer), a String (nextScreen), and an Image
(background image). also has a close(AWTEvent e) method that simply calls
"this.setVisible(false);"
public MainWindow() {
mainFrame = new JFrame("New Arcana");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitleFrame();
} // MainFrame constructor
public void changeFrame(String frameType, String frameName) {
switch (frameType) {
case "Title":
setTitleFrame();
break;
case "Town":
setTownFrame(frameName);
break;
case "Movie":
setMovieFrame(frameName);
break;
default:
break;
} // switch
} // changeFrame
private void setTitleFrame() {
currentScreen = new TitlePanel();
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
} // setTitleFrame
private void setTownFrame(String townName) {
currentScreen = new TownPanel(townName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(townScreenLength, townScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setTownFrame
private void setMovieFrame(String movieName) {
currentScreen = new MoviePanel(movieName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setMovieFrame
private class ScreenChangeListener implements ComponentListener {
#Override
public void componentHidden(ComponentEvent e) {
gotoNextScreen(e);
}
public void componentMoved(ComponentEvent e) {}
public void componentResized(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
} // ScreenChangeListener
public void gotoNextScreen(ComponentEvent e) {
changeFrame(currentScreen.getNextScreen(), null);
}
} // MainWindow
public class Start {
...
public static void main(String[] args) {
initialize();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainWindow();
}
});
} // main
...
} // Start
public class TitlePanel extends ChangeablePanel implements ActionListener {
JButton newGame, continueGame;
public TitlePanel() {
setFocusable(true);
...
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setNextScreen("Movie");
close(e);
}
});
add(newGame);
add(continueGame);
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawTitleScreen(g2d);
} // paintComponent
private void drawTitleScreen(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
newGame.setLocation(170, 550);
continueGame.setLocation(605, 550);
} // drawTitleScreen
} // TitlePanel
public class MoviePanel extends ChangeablePanel implements ActionListener {
public MoviePanel(String movieName) {
setFocusable(true);
addKeyListener(new AnyKeyActionListener());
...
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
drawMovie(g2d);
} // paintComponent
private void drawMovie(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
} // drawTitleScreen
private class AnyKeyActionListener extends KeyAdapter {
public void keyTyped(KeyEvent e) {
setNextScreen("Town");
close(e);
} // keyPressed
} // listener to check for keystrokes
} // MoviePanel
The MainFrame is to be populated with more frames as the application advances based on user-input (currently, only MoviePanel and TownPanel are coded), and their code is fairly analogous to this one -- I pasted MoviePanel as well.
Execution breaks down after the KeyAdapter-based listener above. However, when I run my application in Debug mode in Eclipse with breakpoints, this indeed does what it's supposed to do and advances from the MoviePanel to the TownPanel. It is because of this that I suspect threading is the culprit here. Note that I did try many different combinations of the SwingUtilities.invokeLater() technique on the code-blocks above, but it didn't change anything. Any help would be appreciated; thanks!
Do the following:
invokeLater for creation ont the GUI Event Dispatch Thread
No repaint() during construction
setVisible last
Especially on event listeners again use invokeLater, to let buttons and such be responsive, and have then actions being taken with response too.
public static void main(String[] args) {
...
SwingUtilities.invokeLater() {
#Override()
new Runnable() {
new MainFrame().setVisible(true);
}
};
}
Code review
In TitlePanel.TitlePanel better use an absolute layout (that means null), instead of using setLocation in the painting code.
setLayout(null);
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.setBounds(170, 550, 120, 24);
continueGame.setBounds(605, 550, 120, 24);
In ChangeablePanel.close ensure also timer.stop().
In MainWindow use invokeLater:
public void gotoNextScreen(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
changeFrame(currentScreen.getNextScreen(), null);
}
});
}
In MoviePanel I cannot see that addKeyListener could function; maybe the left-out code? Or is this maybe the error you saw?
Furthermore I find a simple repaint() dubious; would have expected something like:
public void actionPerformed(ActionEvent e) {
invalidate();
repaint(10L);
}
I have been trying with no luck to get a JFormattedTextField to highlight on mouse click. I have been able to get it to work fine while tabbing through fields, however I would like to highlight everything on clicking.
I am only able to highlight on mouse click if I click and hold for about 1.5-2 seconds on the text field; I have no idea why.
I've searched and tried a few fixes including extending the class;
class HFTextField extends JFormattedTextField
{
HFTextField(MaskFormatter formatter)
{
super(formatter);
}
#Override
protected void processFocusEvent(FocusEvent e)
{
super.processFocusEvent(e);
if (e.getID() == FocusEvent.FOCUS_GAINED)
{
this.selectAll();
}
}
}
I am also defining a (rather verbose!) FocusListener which uses SwingUtilities.invokelater;
public static FocusListener CreateHighlightTextFieldFocusListener(final JTextField text_field)
{
FocusListener fl =
new FocusAdapter()
{
public void focusGained(FocusEvent evt)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
text_field.selectAll();
}
});
}
};
return fl;
}
and this is the function that creates formatted text fields;
public static JTextField CreateFormattedTextField(int x, int y, int width, int height,
Method action_method, Method changed_method, Method remove_method,
Method update_method, String mask_formatter, String banned_chars)
{
MaskFormatter formatter = null;
try {
formatter = new MaskFormatter(mask_formatter);
} catch (ParseException e) {
assert(false);
}
if(banned_chars != null)
formatter.setInvalidCharacters(banned_chars);
JTextField text_field = new HFTextField(formatter);
text_field.setBounds(x, y, width, height);
if(action_method != null)
{
text_field.addActionListener(CreateTextFieldActionListener(action_method, text_field));
}
text_field.getDocument().addDocumentListener(
CreateTextFieldDocumentListener(changed_method, remove_method,
update_method, text_field));
text_field.addFocusListener(CreateHighlightTextFieldFocusListener(text_field));
return text_field;
Any help would be greatly appreciated!
maybe you have got problems with EDT,
how method you use for/how you added value to JTextField
works with JTextField, JFormateddTextField, with JComboBox too, and with AutoCompleted funcionalies http://www.java2s.com/Code/Java/Swing-JFC/AutocompleteTextField.htm
private FocusListener focsListener = new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
dumpInfo(e);
}
#Override
public void focusLost(FocusEvent e) {
//dumpInfo(e);
}
private void dumpInfo(FocusEvent e) {
//System.out.println("Source : " + name(e.getComponent()));
//System.out.println("Opposite : " + name(e.getOppositeComponent()));
//System.out.println("Temporary: " + e.isTemporary());
Component c = e.getComponent();
if (c instanceof JFormattedTextField) {
((JFormattedTextField) c).requestFocus();
((JFormattedTextField) c).setText(((JFormattedTextField) c).getText());
((JFormattedTextField) c).selectAll();
} else if (c instanceof JTextField) {
((JTextField) c).requestFocus();
((JTextField) c).setText(((JTextField) c).getText());
((JTextField) c).selectAll();
}
}
private String name(Component c) {
return (c == null) ? null : c.getName();
}
};
Try the following code
yourTextField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
yourTextField.selectAll();
}
});
}
});
I hate to give a simple answer, but have you tried using the MouseListener interface (or MouseAdapter class)?
Have you tried something like this:
fieldName.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
JTextComponent text = (JTextComponent) e.getSource();
text.selectAll();
}
});
Also, I would not recommend doing this asynchronously.
If you want specialized behavior for a mouse click, then add a MouseAdapter to your JTextFiled, and in the mouseClicked event handler, explicitly alter the background.
basically you can use this code (not sure that for each formatter and input masks), but for Number, Date and String you can use following, with ensure that this JFormattedTextField doesn't implements AutoCompleted
myTextField.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
myTextField.requestFocus();
myTextField.setText(myTextField.getText());
myTextField.selectAll();
}
#Override
public void focusLost(FocusEvent e) {
}
});
sure you can pack that into InvokeLate...