I'm using the StyledEditorKit in a project I'm working on. I've used the StyledEditorKit.BoldAction(), and the StyledEditorKit.ItalicAction(). Now I want to use the StyledEditorKit.UnderlineAction() as well.
I make the JButtons that they'll be used in:
JButton bold = new JButton(new StyledEditorKit.BoldAction());
tool.add(bold);
JButton italic = new JButton(new StyledEditorKit.ItalicAction());
tool.add(italic);
JButton underline = new JButton(new StyledEditorKit.UnderlineAction());
tool.add(underline);
They each have their own use where I setText(null) and assign an Icon to the button. Then when I try to use these buttons in an AbstractAction:
Action Bold = new AbstractAction("Bold", new ImageIcon("bold.png"))
{
public void actionPerformed(ActionEvent e)
{
if(bolded == false)
{
area.setFont(area.getFont().deriveFont(Font.BOLD));
bolded = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
bolded = false;
}
}
};
Action Italic = new AbstractAction("Italic", new ImageIcon("italic.png"))
{
public void actionPerformed(ActionEvent e)
{
if(italiced == false)
{
area.setFont(area.getFont().deriveFont(Font.ITALIC));
italiced = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
italiced = false;
}
}
};
Action underline = new AbstractAction("underline", new ImageIcon("underline.png"))
{
public void actionPerformed(ActionEvent e)
{
if(underlined == false)
{
area.setFont(area.getFont().deriveFont(Font.UNDERLINE));
underline = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
underline = false;
}
}
};
The first two AbstractActions work fine. The final one where I use
area.setFont(area.getFont().deriveFont(Font.UNDERLINE);
is not correct however. I have yet to find the actual implementation on oracle (am I looking in the wrong place maybe?), but I figure it is just how I am using 'UNDERLINE' that is incorrect. Simple answer I know. Any help is appreciated.
I figured it out. Yeah that second half of code is completely unnecessary.
The StyledEditorKit that was called in the creation of the button was all I needed to get it working. When I was trying to implement that second AbstractAction, something was going on that wasn't happening in the other 2 AbstractActions (for what ever reason).
I was under the impression I still needed to create another bold action in order to bold the text, but Java handles all of that automatically with the StyledEditorKit.
Related
I've got an application that is using Swing for it's UI. I want a button that switch the type of communication that the app is using. I want to use a Toggle Button to identify the type of communication that's selected.
My problem is that I don't want the color of the button to change after it's been clicked. Currently the button looks like this...
Non-Selected
And then when clicked it looks like this...
Selected
The text changing is what I want, but I would prefer them to have the same color / style.
Here's my code for this...
JToggleButton tglbtnCommunicationType = new JToggleButton("AlwaysOn");
tglbtnCommunicationType.setFocusPainted(false);
tglbtnCommunicationType.addChangeListener(new ChangeListener( ) {
public void stateChanged(ChangeEvent tgl) {
System.out.println("ChangeEvent!");
if(tglbtnCommunicationType.isSelected()){
tglbtnCommunicationType.setText("REST");
tglbtnCommunicationType.setBackground(UIManager.getColor("Button.background"));
}
else
{
tglbtnCommunicationType.setText("AlwaysOn");
};
}
});
My thought is that setting the background when it is selected to the standard background color would fix that, but it doesn't look like it. Any ideas?
Thanks!
Answer:
I switched to a JButton instead, thanks for the help everyone!
JButton btnCommunicationType = new JButton("AlwaysOn");
btnCommunicationType.setFocusPainted(false);
btnCommunicationType.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(btnCommunicationType.getText().equals("AlwaysOn"))
{
btnCommunicationType.setText("REST");
//TODO: Insert Code for Switching Communication to REST here
}
else if(btnCommunicationType.getText().equals("REST")){
btnCommunicationType.setText("AlwaysOn");
//TODO: Insert Code for Switching Communication to AlwaysOne here
}
}
});
btnCommunicationType.setBounds(275, 199, 97, 25);
thingWorxConnectionPanel.add(btnCommunicationType);
you can do it by using JButton only instead of JToggleButton ,
JButton showButton = new JButton("AlwaysOn");
showButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String currentText = showButton.getText();
if("AlwaysOn".equals(currentText)){
showButton.setText("REST");
}else{
showButton.setText("AlwaysOn");
}
}
});
Thanks to the very helpful post by Bart Kiers in someone else's post, I have managed to get my input hints working. Hurray! Unfortunately I can't seem to get a small glitch to stop occurring.
During the normal course of operation, the HintTextFields are disabled and enabled to allow or disallow edits. The input hint should only show when the field is empty and not selected, but when I left click the boxes, even when disabled and containing text, the text disappears in favor of the hint. Then, when I click on something else, I lose the contents entirely.
I have added an extra bit to the if then statements regarding gaining and losing focus to prevent it from running that code if the component is disabled, but the problem still occurs. It must be some small interaction with the JTextField class (or maybe FocusListener?). I have also tried getParent() in favor of this in that clause, in case I was misunderstanding the 'this' keyword, but that didn't help. The class below:
class HintTextField extends JTextField implements FocusListener {
private final String hint;
private boolean showingHint;
public HintTextField(final String hint) {
super(hint);
this.hint = hint;
this.showingHint = true;
super.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if(this.getText().isEmpty() && this.isEnabled()) {
super.setText("");
showingHint = false;
}
}
#Override
public void focusLost(FocusEvent e) {
if(this.getText().isEmpty() && this.isEnabled()) {
super.setText(hint);
showingHint = true;
}
}
#Override
public String getText() {
return showingHint ? "" : super.getText();
}
}
Original post if anyone wants to go upvote the wonderful Bart Kiers.
Java JTextField with input hint
Also, here is the initialization. This started as a JDeveloper gui.
startDateField.setHorizontalAlignment(javax.swing.JTextField.CENTER);
startDateField.setToolTipText(notes);
startDateField.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
startDateField.setMaximumSize(new java.awt.Dimension(2, 16));
startDateField.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
startDateFieldMouseClicked(evt);
}
});
private void startDateFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_startDateFieldMouseClicked
if (SwingUtilities.isRightMouseButton(evt)) {
editNote();
}
}
public void editNote() {
int selected = -1;
for (int a = 0; a < spinner.bitem.bldg.stallArray[1].length; a ++) {
if (spinner.bitem.bldg.stallArray[1][a].equals(stallName)) {
selected = a;
}
}
String oldNote = notes;
JTextField xField = new JTextField(oldNote);
xField.setPreferredSize(new Dimension(200,30));
JPanel myPanel = new JPanel();
myPanel.add(new JLabel("Note:"));
myPanel.add(xField);
int result =
JOptionPane.showConfirmDialog(this, myPanel, "Please enter note.",
JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
String note = xField.getText();
if (!note.equals(oldNote)) {
notes = note;
spinner.bitem.bldg.stallArray[9][selected] = notes;
spinner.bitem.master.sendNoteDataToSQL(spinner.bitem.bldg.buildingName, spinner.bitem.bldg.stallArray[1][selected], notes);
spinner.updateScreen();
}
}
}
I am trying to get a group of JRadioButtons to be navigable using the arrow keys. I was going to implement this manually with KeyListeners, but apparently this behavior is already supposed to work for at least the last 8 years (http://bugs.sun.com/view_bug.do?bug_id=4104452). However, it's not working for me: pressing the arrow keys does nothing. Java version is 7u45 on Windows.
A standalone test case to see what I'm talking about:
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
if (!EventQueue.isDispatchThread()) {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
main(args);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return;
}
try {
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable t) {
throw new RuntimeException(t);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
JRadioButton rb;
rb = new JRadioButton("Option A");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option B");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option C");
panel.add(rb);
group.add(rb);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
I have tried using different look & feels, different containers, and different layout managers, but it still does not work.
You need to add the right/left (up/down?) keys to the focus traversal policy of each radio button. For example to add the right/left arrow keys:
Set set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "RIGHT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "LEFT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
Read the section from the Swing tutorial on How to Use the Focus Subsystem for more information.
I believe you can achieve your goal using KeyBindings instead of KeyListeners. In many cases bindings are actually recommended over KeyListeners, as the second ones can generate many problems (frame catching the key activity must be active one etc.)
Thank you everyone for the answers.
I discovered the reason for my confusion. Apparently, when the Sun bug report system says that a bug's status is "Closed" and its "Resolved Date" is "2005-07-19", that doesn't mean the bug is fixed at all. Apparently, it's just logged as a duplicate of some other (newer?) bug. Nearly 16 years since it was first reported it still isn't fixed. Whatever.
The needed behavior is much more subtle than I realized. I experimented in native Windows dialogs in various programs:
Most button-like components: buttons, checkboxes, and radio buttons, implement the arrow keys for focus navigation. In Java this corresponds to the AbstractButton class. (JMenuItem is also a subclass of that, but that has its own distinct arrow key behavior.)
Only radio buttons get selected/checked during this navigation.
Unfocusable (including disabled or invisible) components must be skipped.
Attempting to navigate before the first button in a group or after the last one is inconsistent: on some dialogs it loops from end to end; on others it moves irreversibly onto non-button components; and on yet others it does nothing. I experimented with all these different behaviors and none of them was particularly better than the others.
I implemented a looping behavior below as it felt slightly more fluent. The navigation silently skips past non-AbstractButton components, forming a sort-of separate focus cycle private to buttons. This is dubious but sometimes needed when a set of related checkboxes or radio buttons are mixed with other components. Testing for a common parent component to identify groups would also be a reasonable behavior, but that didn't work in one dialog where I'd used separate components purely for layout reasons (to implement a line break in a FlowLayout).
As suggested I studied up on InputMaps and ActionMaps instead of using a KeyListener. I've always avoided the maps as they seem overcomplicated but I guess I see the advantage of being able to easily override the binding.
This code uses an auxialiary look and feel to install the desired behavior for all AbstractButton components application-wide (which is a nice technique I found out about here). I've tested it with several different dialog boxes and windows and it seems to be okay. If it causes issues I'll update this post.
Call:
ButtonArrowKeyNavigation.install();
once at application startup to install it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonArrowKeyNavigation {
private ButtonArrowKeyNavigation() {}
public static void install() {
UIManager.addAuxiliaryLookAndFeel(lookAndFeel);
}
private static final LookAndFeel lookAndFeel = new LookAndFeel() {
private final UIDefaults defaults = new UIDefaults() {
#Override
public javax.swing.plaf.ComponentUI getUI(JComponent c) {
if (c instanceof AbstractButton && !(c instanceof JMenuItem)) {
if (c.getClientProperty(this) == null) {
c.putClientProperty(this, Boolean.TRUE);
configure(c);
}
}
return null;
}
};
#Override public UIDefaults getDefaults() { return defaults; };
#Override public String getID() { return "ButtonArrowKeyNavigation"; }
#Override public String getName() { return getID(); }
#Override public String getDescription() { return getID(); }
#Override public boolean isNativeLookAndFeel() { return false; }
#Override public boolean isSupportedLookAndFeel() { return true; }
};
private static void configure(JComponent c) {
InputMap im = c.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap am = c.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "focusNextButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "focusNextButton");
am.put("focusPreviousButton", focusPreviousButton);
am.put("focusNextButton", focusNextButton);
}
private static final Action focusPreviousButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), -1);
}
};
private static final Action focusNextButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), +1);
}
};
private static void move(AbstractButton ab, int direction) {
Container focusRoot = ab.getFocusCycleRootAncestor();
FocusTraversalPolicy focusPolicy = focusRoot.getFocusTraversalPolicy();
Component toFocus = ab, loop = null;
for (;;) {
toFocus = direction > 0
? focusPolicy.getComponentAfter(focusRoot, toFocus)
: focusPolicy.getComponentBefore(focusRoot, toFocus);
if (toFocus instanceof AbstractButton) break;
if (toFocus == null) return;
// infinite loop protection; should not be necessary, but just in
// case all buttons are somehow unfocusable at the moment this
// method is called:
if (loop == null) loop = toFocus; else if (loop == toFocus) return;
}
if (toFocus.requestFocusInWindow()) {
if (toFocus instanceof JRadioButton) {
((JRadioButton)toFocus).setSelected(true);
}
}
}
}
Here is my example of JRadioButtons can be navigable using the arrow keys(UP and Down) and modified few codes for you.
public class JRadioButton extends JPanel {
private JRadioButton[] buttons;
public JRadioButtonTest(int row) {
ButtonGroup group = new ButtonGroup();
buttons = new JRadioButton[row];
for (int i = 0; i < buttons.length; i++) {
final int curRow = i;
buttons[i] = new JRadioButton("Option " + i);
buttons[i].addKeyListener(enter);
buttons[i].addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (curRow > 0)
buttons[curRow - 1].requestFocus();
break;
case KeyEvent.VK_DOWN:
if (curRow < buttons.length - 1)
buttons[curRow + 1].requestFocus();
break;
default:
break;
}
}
});
group.add(buttons[i]);
add(buttons[i]);
}
}
private KeyListener enter = new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
((JButton) e.getComponent()).doClick();
}
}
};
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JRadioButton(3));
frame.pack();
frame.setVisible(true);
}
}
The core implement method is calling requestFocus() on the correct JRadioButton when an arrow key is called. Extra KeyListener for when the Enter key is pressed.
You can use this KeyListener to your program and add more key.
Good luck!
I'm developing a small photo editing application and would like the JButtons disabled until the user loads an image, at which point I want the buttons to become enabled(clickable). My thinking was to add a boolean imageFound, and an image checker method. If boolean is false, the buttons are disabled and if it is true they are enabled (the boolean is set to true in the load image actionPerformed method). The problem im having is that when running the app, the buttons are disabled as they should be, but when i load the image they would still be disabled. I dont know if maybe i am missing any piece of code to recheck whether the image is available, thus enabling the buttons (at runtime ofc). Thanks for any help.
...BufferedImage effects = null;
boolean bmpFound = false;
public GUI()
{
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.initComponents();
this.bmpChecker();
this.addListeners();
this.setTitle("PicTweak");
this.setSize(900, 600);
this.setVisible(true);
}
...else if(e.getSource() == loadItem)
{
try
{
imagePath = DialogIO.displayOpenDialog();
effects = ImageInOut.loadImage(imagePath);
imageHolder.setIcon(new ImageIcon(effects));
bmpFound = true;
}
....public void bmpChecker()
{
if(bmpFound)
{
grayScale.setEnabled(true);
blur.setEnabled(true);
reset.setEnabled(true);
brightDark.setEnabled(true);
horFlip.setEnabled(true);
verFlip.setEnabled(true);
verHorFlip.setEnabled(true);
}
else
{
grayScale.setEnabled(false);
blur.setEnabled(false);
reset.setEnabled(false);
brightDark.setEnabled(false);
horFlip.setEnabled(false);
verFlip.setEnabled(false);
verHorFlip.setEnabled(false);
}
}
When you load/unload the image, call bmpChecker() afterwards, i.e.
...
try
{
imagePath = DialogIO.displayOpenDialog();
effects = ImageInOut.loadImage(imagePath);
imageHolder.setIcon(new ImageIcon(effects));
bmpFound = true;
bmpChecker();
}
...
A better alternative would be t add listeners for the image loading, i.e. for each control or group of controls that needs to update its state accordingly, you'd register a listener that is notified whenever an image is loaded or unloaded. The listener could then trigger the updates of the corresponding controls.
Something like:
class ImageEvent {
private boolean imageLoaded; //plus getter/setter and maybe initialized in constructor
}
interface ImageListener {
void imageChanged(ImageEvent e);
}
...
List<ImageListener> listeners;
...
try
{
imagePath = DialogIO.displayOpenDialog();
effects = ImageInOut.loadImage(imagePath);
imageHolder.setIcon(new ImageIcon(effects));
bmpFound = true;
ImageEvent imgageEvent = new ImageEvent();
imageEvent.setImageLoaded(true);
for( ImageListener l : listeners ) {
l.imageChanged(imageEvent);
}
}
...
And an example listener:
class JButtonImageListener implements ImageListener {
private JButton button; //plus getter/setter
public void imageChanged(ImageEvent e) {
button.setEnabled(e.isImageLoaded());
}
}
So I am trying to get my GUI to work. When I run the code below, it does nothing, and I'm sure I'm probably just doing something dumb, but I am completely stuck...
public void actionPerformed(ActionEvent e){
UI.getInstance().sS++;
if((UI.getInstance().sS %2) != 0){
UI.getInstance().startStop.setName("STOP");
UI.getInstance().change.setEnabled(false);
}else if(UI.getInstance().sS%2 == 0){
UI.getInstance().startStop.setName("START");
UI.getInstance().change.setEnabled(true);
}
}
public void setStartListener(StartHandler e){
this.startStop.addActionListener(e);
}
sS is an int that increments every time the button startStop is clicked. change is also a button.
not really an answer, but I think your code would be simpler if you used a boolean instead of an int, something like:
public void actionPerformed(ActionEvent e){
final boolean isEnabled = UI.getInstance().change.isEnabled();
if(isEnabled){
UI.getInstance().startStop.setName("STOP");
}else{
UI.getInstance().startStop.setName("START");
}
UI.getInstance().change.setEnabled(!isEnabled);
}
Here's an example that shows a different approach to managing a Start/Stop button. It uses an instance of javax.swing.Timer to pace updates. Encapsulating the control button and display label may simplify maintenance. This variation illustrates adding a third command to pause updates.
private static final String Start = "Start";
private static final String Stop = "Stop";
…
private static void create() {
…
final JButton button = new JButton(Stop);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (Stop.equals(cmd)) {
jtl.stop();
button.setText(Start);
} else {
jtl.start();
button.setText(Stop);
}
}
});
…
}
More generally, use Action to encapsulate functionality for use elsewhere in your program. This example "exports several actions that make it easy to use them in a control panel."