In connections with these two post #iMohammad,
Increasing/Decreasing Font Size inside textArea using JButton and
Changing Font Style when Clicking on a JButton Java ..., I'm facing with really funny issue that came from JComboBoxby passing setPrototypeDisplayValue as an argument for JComboBox's size on the screen
please how can I resize JComboBox dynamically depends of Font, same as works correctly for another JComponents that I tried in my sscce
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ComboBoxFontChange extends JFrame {
private static final long serialVersionUID = 1L;
private JComboBox cbox = new JComboBox();
private JTextField tfield = new JTextField("Change");
private JLabel label = new JLabel("Cash");
private JButton button = new JButton("++ Font");
private JTextField text;
private JPanel panel = new JPanel();
public ComboBoxFontChange() {
super("Combo Box Font change");
text = (JTextField) cbox.getEditor().getEditorComponent();
cbox.addItem("Change");
cbox.addItem("Cash");
cbox.addItem("Font");
tfield.setColumns(5);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Font font = cbox.getFont();
font = font.deriveFont((float) (font.getSize2D() * 1.10));
cbox.setFont(font);
// EDIT
cbox.setPrototypeDisplayValue(cbox.getSelectedItem().toString());
tfield.setFont(font);
button.setFont(font);
label.setFont(font);
//panel.revalidate();
//panel.repaint();
pack();
}
});
//panel.setLayout(new GridLayout(2, 2, 10, 10));
panel.add(cbox);
panel.add(label);
panel.add(tfield);
panel.add(button);
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(panel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ComboBoxFontChange frame = new ComboBoxFontChange();
frame.pack();
frame.setVisible(true);
}
});
}
}
I debugged your SSCCE, and the value passed to setPrototypeDisplayValue is the empty string. Changing the line to
cbox.setPrototypeDisplayValue(cbox.getSelectedItem());
Makes everything work as expected. Removing the call to setPrototypDisplayValue also makes the program behave as expected.
EDIT:
The other problem is that no event is fired for the prototype display value because you set it to the previous value as before, and an event is only fired if the value actually changes. Adding cbox.setPrototypeDisplayValue(""); before cbox.setPrototypeDisplayValue(cbox.getSelectedItem().toString()) makes everything behave as expected, even on JDK 1.6. I agree that given that the font is changed, the preferred size should be recomputed, but at least this change is a workaround.
I tried what JB Nizet said. But for me the comboBox size didnt change. How about you?
So i tried the following and the combobox size increased as i increased the font size.
cbox.setFont(font);
cbox.updateUI();
I also removed the line
cbox.setPrototypeDisplayValue(text.getText());
For reference, a GridLayout and eight clicks gave this result on Mac OS X:
panel.setLayout(new GridLayout(0, 1, 10, 10));
Combo: Popup:
As an aside, cbox.updateUI() restored the defaults prescribed by the Aqua UI delegate, com.apple.laf.AquaComboBoxUI.
Here is the code from the BasicComboBoxUI:
else if ( propertyName == "font" ) {
listBox.setFont( comboBox.getFont() );
if ( editor != null ) {
editor.setFont( comboBox.getFont() );
}
isMinimumSizeDirty = true;
comboBox.validate();
}
else if ( propertyName == JComponent.TOOL_TIP_TEXT_KEY ) {
updateToolTipTextForChildren();
}
else if ( propertyName == BasicComboBoxUI.IS_TABLE_CELL_EDITOR ) {
Boolean inTable = (Boolean)e.getNewValue();
isTableCellEditor = inTable.equals(Boolean.TRUE) ? true : false;
}
else if (propertyName == "prototypeDisplayValue") {
isMinimumSizeDirty = true;
isDisplaySizeDirty = true;
comboBox.revalidate();
}
For some reason a Font change only resets the "minimum size" not the "display size".
Related
I have used Romain Hippeau's answer. In order to set the default font of the application when it is first built.
public static void setUIFont(javax.swing.plaf.FontUIResource f) {
java.util.Enumeration keys = UIManager.getDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
Object value = UIManager.get(key);
if (value instanceof javax.swing.plaf.FontUIResource)
UIManager.put(key, f);
}
And then calling it:
setUIFont(new javax.swing.plaf.FontUIResource("Sans", Font.PLAIN, 24));
However when new text is written to the swing application: I.e
JTextArea textArea = new JTextArea();
onSomeEventHappening(){
textArea.setText("Hello world");
}
Hello world appears in the standard swing font whereas all my other elements remain at the font I want everything to stay in. Is there any way to make sure that all new text added to the application, doesn't have its font changed.
Above shows an example of this, the word "FOOTBALL" has be written into its combo box and therefore appears with Swing's normal font, whereas my button "Generate one link"appears in the font I've set.
Below shows a copy and paste example, if you click on the button, despite setting the font above, the label is still in Swings original style:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class test extends JFrame {
private static final int WIDTH = 1000;
private static final int HEIGHT = 700;
private JTextArea textArea = new JTextArea();
public static void setUIFont(javax.swing.plaf.FontUIResource f) {
java.util.Enumeration keys = UIManager.getDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
Object value = UIManager.get(key);
if (value instanceof javax.swing.plaf.FontUIResource)
UIManager.put(key, f);
}
}
public test(){
initialize();
}
final ActionListener buttonClick = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setText("new Text");
}
};
public void initialize(){
new JFrame();
setBounds(100, 100, 450, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1,2));
setUIFont(new javax.swing.plaf.FontUIResource("Sans", Font.PLAIN, 24));
JButton button = new JButton("test");
button.addActionListener(buttonClick);
this.add(button);
this.add(textArea);
setVisible(true);
}
public static void main(String[] args){
test test1 = new test();
}
}
private JTextArea textArea = new JTextArea();
...
setUIFont(new javax.swing.plaf.FontUIResource("Sans", Font.PLAIN, 24));
...
JButton button = new JButton("test");
You have already created the JTextArea before you change the font.
The Swing component gets its UI properties at the time it is created.
So you need to create the JTextArea AFTER you set the font, the same as you do with the JButton.
Note: if you change the properties after the components have been created then you need to reset the properties.
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
Read the section from the Swing tutorial on How to Set the Look and Feel After Startup for more information.
I'm creating a text field in java using swing components. I want to make a search text field like one appears in Mozilla or other browsers.
I have added a button in text field. I have set border layout of JTextField. everything is working fine but whenever large text is written in text field (as it reaches the given size of text field) it goes behind the button. As everyone of you must have seen, this does not occur in search bars. Text must not go behind the button rather there must be some gap between button and text.
Does anyone know how to do that?
Maybe start with something like this:
The blinking cursor is positioned at the far right of the text field.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ButtonsInTextField {
JPanel gui = new JPanel(new GridBagLayout());
JTextField textField;
ButtonsInTextField(int cols) {
JPanel textFieldWithButtonsPanel = new JPanel(new FlowLayout(
SwingConstants.LEADING, 5, 1));
textField = new JTextField(cols);
textFieldWithButtonsPanel.add(textField);
addButtonToPanel(textFieldWithButtonsPanel, 8);
addButtonToPanel(textFieldWithButtonsPanel, 16);
addButtonToPanel(textFieldWithButtonsPanel, 24);
// WARNING: Not sensitive to PLAF change!
textFieldWithButtonsPanel.setBackground(textField.getBackground());
textFieldWithButtonsPanel.setBorder(textField.getBorder());
textField.setBorder(null);
// END WARNING:
gui.add(textFieldWithButtonsPanel);
}
private final void addButtonToPanel(JPanel panel, int height) {
BufferedImage bi = new BufferedImage(
// find the size of an icon from the system,
// this is just a guess
24, height, BufferedImage.TYPE_INT_RGB);
JButton b = new JButton(new ImageIcon(bi));
b.setContentAreaFilled(false);
//b.setBorderPainted(false);
b.setMargin(new Insets(0,0,0,0));
panel.add(b);
}
public final JComponent getGui() {
return gui;
}
public final JTextField getField() {
return textField;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ButtonsInTextField bitf = new ButtonsInTextField(20);
JOptionPane.showMessageDialog(null, bitf.getGui());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
As people have noted above, it might have helped to see the code, especially the Layout manager.
However, you might try the following (if you haven't yet):
Call setColumns
http://docs.oracle.com/javase/7/docs/api/javax/swing/JTextField.html#setColumns(int)
Call setPreferredSize /setMaximumSize/setMinimumSize depending on your layout manager.
But I'd try to avoid this solution because it's pixel-level maintenance.
Regards
As an alternative solution you can use a Component Border, which allows you to use the button as a Border so it appears within the text field.
I have a delicate problem!
I have a form that set input verifier to text fields, and when user type a incorrect value, other text fields and radio buttons should be disable.
In second text filed (last name), When user type a incorrect value, other components disable perfectly, But when user edit that value to correct it, (for e.x by removing digit), user should user keyboard tab button to enable other components (radio buttons) and I want to enable with clicking to radio buttons too.
Here is my code:
public class UserDialog3 extends JDialog implements ActionListener {
JButton cancelBtn, okBtn;
JTextField fNameTf, lNameTf;
JRadioButton maleRb, femaleRb;
ButtonGroup group;
JLabel fNameLbl, lNameLbl, genderLbl, tempBtn, temp3, temp2, temp1;
public UserDialog3() {
add(createForm(), BorderLayout.CENTER);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocation(400, 100);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new UserDialog3();
}
});
}
public JPanel createForm() {
JPanel panel = new JPanel();
okBtn = new JButton("Ok");
cancelBtn = new JButton("Cancel");
tempBtn = new JLabel();
fNameLbl = new JLabel("First Name");
lNameLbl = new JLabel("Last Name");
genderLbl = new JLabel("Gender");
temp2 = new JLabel();
temp1 = new JLabel();
maleRb = new JRadioButton("Male");
femaleRb = new JRadioButton("Female");
temp3 = new JLabel();
group = new ButtonGroup();
group.add(maleRb);
group.add(femaleRb);
fNameTf = new JTextField(10);
fNameTf.setName("FnTF");
fNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));
lNameTf = new JTextField(10);
lNameTf.setName("LnTF");
lNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));
panel.add(fNameLbl);
panel.add(fNameTf);
panel.add(temp1);
panel.add(lNameLbl);
panel.add(lNameTf);
panel.add(temp2);
panel.add(genderLbl);
JPanel radioPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
radioPanel.add(maleRb);
radioPanel.add(femaleRb);
panel.add(radioPanel);
panel.add(temp3);
panel.add(okBtn);
panel.add(cancelBtn);
panel.add(tempBtn);
panel.setLayout(new SpringLayout());
SpringUtilities.makeCompactGrid(panel, 4, 3, 50, 10, 80, 60);
return panel;
}
#Override
public void actionPerformed(ActionEvent e) {
}
public class MyVerifier extends InputVerifier {
private JComponent[] component;
public MyVerifier(JComponent[] components) {
component = components;
}
#Override
public boolean verify(JComponent input) {
String name = input.getName();
if (name.equals("FnTF")) {
String text = ((JTextField) input).getText().trim();
if (text.matches(".*\\d.*") || text.length() == 0) {
//disable dependent components
for (JComponent r : component) {
r.setEnabled(false);
}
return false;
}
} else if (name.equals("LnTF")) {
String text = ((JTextField) input).getText();
if (text.matches(".*\\d.*") || text.length() == 0) {
//disable dependent components
for (JComponent r : component) {
r.setEnabled(false);
}
return false;
}
}
//enable dependent components
for (JComponent r : component) {
r.setEnabled(true);
}
return true;
}
}
}
The purpose of InputVerifier class is to help clients support smooth focus navigation through GUIs with text fields. Before focus is transfered to another Swing component that requests it, the input verifier's shouldYieldFocus method is called(which ask the verify function to validate data). Focus is transfered only if that method returns true.
Please Try to fix the issues about using InutVerifier, verify and shouldYieldFunction as mentioned in your previous post. If you are not going to change your practice, you will be danger in future. Remove you components enabling and disabling code from verify function.
Your Problem in this post: In this case, what really happening is that, when your data is invalid and you try to lose your input text field focus by clicking another component, your JRadioButtons get disabled. A disabled cant be focused until it is re-enabled. As input-verifier responds with focus-lose event, clicking on the disabled RadioButton isn't resulting in focus navigation, and thus ShouldYieldFocus(which calls verify) is not being called to re-enable your components.
Pressing the tab works, because it is sending the Focus to your second text input field according to swing's focus traversal policy. Hence a focus lose event occur on first input text field and this time InputVerifier's verify function get called which eventually enables your component. To understand the problem better, try rewriting your own example with one JRadioButton and one JTextFeild.
Try using a DocumentListener with your text Field. upon data insertion and removal event, check your data validity using InputVerifier and then, enable/disable related components.
I am writing a sample code snippets to demonstrate, how adding DocumentListener to your fNameTF and lNameTF text fields will resolve your problem:
fNameTF.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
doOnDataValidity(verifier.verify(fNameTF));
}
#Override
public void removeUpdate(DocumentEvent e) {
doOnDataValidity(verifier.verify(fNameTF));
}
#Override
public void changedUpdate(DocumentEvent e) {}
});
doOnValidity(boolean isValid) function is as follows:
public void doOnDataValidity(boolean isDataValid)
{
if(isDataValid)
{
//enable your components
}else
{
//disable your components
}
}
Add a DocumentListener to your lNameTf.getDocument() the same way.
Tutorial Resources: How to use DocumentListener.
I need to clean my labelResult each time on textField Action, but on the first time it adds 'null' in front of string and then - prints new string right after. Please help.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame extends JFrame implements ActionListener {
boolean isDirect = true;
String[] typeStr = {"direct", "invert"};
JLabel labelTip = new JLabel("Choose 'direct' OR 'invert' to print your next line in direct order or inverted respectively.");
JTextField textField = new JTextField("Some text!", 40);
JComboBox comboBox = new JComboBox(typeStr);
EventProcessing eventProcessing = new EventProcessing();
JLabel labelResult = new JLabel();
public Frame() {
setLayout(new BorderLayout());
getContentPane().add(labelTip, BorderLayout.PAGE_START);
getContentPane().add(comboBox, BorderLayout.CENTER);
getContentPane().add(textField, BorderLayout.AFTER_LINE_ENDS);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField.addActionListener(this);
pack();
}
public void actionPerformed(ActionEvent e) {
getContentPane().remove(labelResult);
labelResult = new JLabel();
labelResult.setText("");
if (!(comboBox.getSelectedItem()).equals("direct")) {
isDirect = false;
}
else {
isDirect = true;
}
labelResult.setText(eventProcessing.action(isDirect, textField.getText()));
getContentPane().add(labelResult, BorderLayout.PAGE_END);
pack();
}
}
#Tim I know that in official tutorial about JComboBox is used ActionListener, but for any of actions from JComboBox to the GUI is better look for ItemListener, there you are two states (always be called twice, but you can filtering between thes two options SELECTED / DESELECTED by wraping to the if ... else)
and your code should be only
Runnable doRun = new Runnable() {
#Override
public void run() {
labelResult.setText(eventProcessing.action(isDirect, textField.getText()));
add(labelResult, BorderLayout.PAGE_END);
//1) this.pack(); if you want to re-layout with effect to size of JFrame too
//2a revalidate();
//2b plus in most cases
//2b repaint(); relayout Container with fitting JComponents inside Container,
//2b but without resize of JFrame
}
};
SwingUtilities.invokeLater(doRun);
Without the code to EventProcessing.action() it's hard to determine, but I would guess you attempt to concatenate two strings, the first of which is null. Null strings get converted to the literal string "null."
I have a value called 'AmountWrongGuessed' that gives the amount of wrong guesses the users puts while guessing a word.
Each times the word is not found in the arraylist the AmountWrongGuessed goes ++. (tested this wih a println and it works properly)
Now the problem is each time the AmountWrongGuessed goes 1 up it should display a ImageIcon.
But insteed it displays the last image icon all the time, and skips the other icons.
I use no layout mananger (its set to null, if this makes any difference in the total picture setLayout = null)
Also while initialising this game the amountwrongguessed is default 0, yet it does not display the first imageicon either. (i used different labels before to add each icon on the same position but then i had the problem only the first image displayed and nothing changed).
public HrView(Hrgame hg) {
this.hg = hg;
CreateComponents();
SetLayoutComponents();
UpdateComponents();
AddListeners();
}
Creation of the images:
private void CreateComponents() {
hang0 = new ImageIcon("hang0.gif");
lblHang = new JLabel(hang0);
lblHang.setLocation(60, -10);
lblHang.setSize(200, 200);
hang1 = new ImageIcon("hang1.gif");
lblHang = new JLabel(hang1);
lblHang.setLocation(60, -10);
lblHang.setSize(200, 200);
hang2 = new ImageIcon("hang2.gif");
lblHang = new JLabel(hang2);
lblHang.setLocation(60, -10);
lblHang.setSize(200, 200);
}
private void AddListeners()
{
btnCheck.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
hg.Input(tfToGuessInput.getText().toLowerCase());
Pictures();
lblHang.updateUI();
}
});
}
private void Pictures()
{
//works, does increment
System.out.println(hg.getAmountWrongGuessed());
if (hg.getAmountWrongGuessed() == 0) {
add(lblHang);
}
if (hg.getAmountWrongGuessed() == 1) {
add(lblHang);
}
if (hg.getAmountWrongGuessed() == 2) {
add(lblHang);
}
}
After CreateComponents() your attribute lblHang references the label you created last (the one containing image hang2.) In order to use the 3 labels later on, you need to have 3 label attibutes which you can then use in Pictures().
Btw, in Java the naming convention is that method names start with a lowercase character.
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import java.awt.BorderLayout;
import java.awt.*;
import java.awt.event.*;
public class testgui{
private static int flag = 1;
public static void main(String[] args){
final JLabel label = new JLabel("",new ImageIcon("0.jpg"),JLabel.CENTER);
final JLabel label1 = new JLabel("",new ImageIcon("1.jpg"),JLabel.CENTER);
final JLabel label2 = new JLabel("",new ImageIcon("2.jpg"),JLabel.CENTER);
final JFrame frame = new JFrame();
final JPanel panel = new JPanel();
frame.add(panel,BorderLayout.CENTER);
frame.setVisible(true);
final JButton button = new JButton("Next");
frame.add(button,BorderLayout.SOUTH);
panel.add(label);
frame.pack();
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if(flag==0){
System.out.println("0.jpg");
//label image, flag increment
flag = flag+1;
panel.removeAll();
panel.add(label);
frame.pack();
} else if(flag==1){
System.out.println("1.jpg");
//label1 image, flag increment
flag = flag+1;
panel.removeAll();
panel.add(label1);
frame.pack();
} else if (flag==2){
System.out.println("2.jpg");
//label2 image, reset flag to 0
flag = 0;
panel.removeAll();
panel.add(label2);
frame.pack();
}
else{
System.out.println("Wrong flag number !");
}
panel.validate();
panel.updateUI();
}
});
}
}
I think if you want to switch images, using jlabels, the above codes would help. It would help to rotate jlabels containing images but this codes are not optimized.