What's wrong with this Java?

hockeygoalie5

In Runtime
Messages
299
Location
United States
Okay, so I made this. It is supposed to detect that if the font is bold or italic while the other font change button is pressed and make the font both bold and italic. But this is ignored and when the button is pressed, it is only one font.

Code:
package org.gui;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class GUI1 extends JFrame {

    private static final long serialVersionUID = -8003666480923795663L;
    
    public static void main(String args[]) {
        JFrame frame = new JFrame();
        frame.setLayout(new FlowLayout());
        frame.setVisible(true);
        frame.setSize(500, 100);
        final Font boldFont = new Font("Bold", Font.BOLD, 12);
        final Font italic = new Font("Italic", Font.ITALIC, 12);
        final Font boldItalic = new Font("Bold Italic", Font.BOLD+Font.ITALIC, 12);
        final JLabel label = new JLabel("JLable");
        JButton button = new JButton("Change color");
        JButton bold = new JButton("Toggle bold");
        JButton italicButton = new JButton("Toggle italic");
        label.setFont(null);
        label.setForeground(Color.BLUE);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getForeground() == Color.BLUE) {
                    label.setForeground(Color.RED);
                }
                else if(label.getForeground() == Color.RED) {
                    label.setForeground(Color.BLUE);
                }
            }
        });
        bold.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getFont() != boldFont) {
                    label.setFont(boldFont);
                }
                else if(label.getFont() == boldFont) {
                    label.setFont(null);
                }
                else if(label.getFont() == italic) {
                    label.setFont(boldItalic);
                }
                else if(label.getFont() == boldItalic) {
                    label.setFont(italic);
                }
            }
        });
        italicButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getFont() != italic) {
                    label.setFont(italic);
                }
                else if(label.getFont() == italic) {
                    label.setFont(null);
                }
                else if(label.getFont() == boldFont) {
                    label.setFont(boldItalic);
                }
                else if(label.getFont() == boldItalic) {
                    label.setFont(boldFont);
                }
            }
        });
        frame.add(label);
        frame.add(button);
        frame.add(bold);
        frame.add(italicButton);
    }

}
 
Haven't got time to study it in detail, but one problem that jumps out is you're doing:

Font.BOLD+Font.ITALIC

This won't work - you actually need to use a bitwise OR to get both bold and italic:

Font.BOLD | Font.ITALIC

(It's usually a bitwise OR when combining pre-enum integer constants for a very good, but low level reason. I'll explain more if you're interested.)

Not sure if it'll fix the issue but that's one thing that's definitely not right.
 
I see my error now, but wouldn't the AND operator be more appropriate since I want both?

The OR nor AND operators work.

EDIT: I changed the font size of every font (and made a 'normal' font rather than using null) but the boldItalic font. After a fun round of button pushing, I learned that boldItalic is never used. The problem is within my 'else if'.

EDIT AGAIN: I figured it out, I have an if checking if the font does not equal boldFont/italic. Changed it, it works.

If anyone wants to play around with it, I made more changes since the last piece up there:
Code:
package org.gui;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class GUI1 extends JFrame {

    private static final long serialVersionUID = -8003666480923795663L;
    
    public static void main(String args[]) {
        JFrame frame = new JFrame();
        frame.setLayout(new FlowLayout());
        frame.setVisible(true);
        frame.setSize(600,75);
        frame.setTitle("Font Changer");
        final Font normal = new Font("Normal", Font.PLAIN, 32);
        final Font boldFont = new Font("Bold", Font.BOLD, 32);
        final Font italic = new Font("Italic", Font.ITALIC, 32);
        final Font boldItalic = new Font("Bold Italic", Font.BOLD|Font.ITALIC, 32);
        final JLabel label = new JLabel("Text");
        JCheckBox check = new JCheckBox("Show text?");
        check.setSelected(true);
        JButton button = new JButton("Change color");
        JButton bold = new JButton("Toggle bold");
        JButton italicButton = new JButton("Toggle italic");
        label.setFont(normal);
        label.setForeground(Color.BLUE);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getForeground() == Color.BLUE) {
                    label.setForeground(Color.RED);
                }
                else if(label.getForeground() == Color.RED) {
                    label.setForeground(Color.BLUE);
                }
            }
        });
        bold.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getFont() == normal) {
                    label.setFont(boldFont);
                }
                else if(label.getFont() == boldFont) {
                    label.setFont(normal);
                }
                else if(label.getFont() == italic) {
                    label.setFont(boldItalic);
                }
                else if(label.getFont() == boldItalic) {
                    label.setFont(italic);
                }
            }
        });
        check.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.isVisible() == true) {
                    label.setVisible(false);
                }
                else {
                    label.setVisible(true);
                }

            }
        });
        italicButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if(label.getFont() == normal) {
                    label.setFont(italic);
                }
                else if(label.getFont() == italic) {
                    label.setFont(normal);
                }
                else if(label.getFont() == boldFont) {
                    label.setFont(boldItalic);
                }
                else if(label.getFont() == boldItalic) {
                    label.setFont(boldFont);
                }
            }
        });
        frame.add(label);
        frame.add(button);
        frame.add(bold);
        frame.add(italicButton);
        frame.add(check);
    }

}
 
I see my error now, but wouldn't the AND operator be more appropriate since I want both?
From a high up, abstract perspective yes - however the manipulation here is actually bit manipulation on integers (very yucky which is why in the newer APIs it's been replaced by much nicer enums.) Before the days of enums it was common to use integers to represent constants, going up in powers of 2.

So option 1 might be 1, option 2, 2, option 3, 4, option 4, 8 and option 5 16.

The key with using the above options is when the number is represented in binary they all just have 1 "1" in different places:

00001
00010
00100
01000
10000

(This is when you'll need to read up on bitwise manipulation a bit if you don't know it already!)

From the above, and now that you know a bit about bitwise manipulation you should be able to see why OR is the appropriate one to use here. Combining any 2 options with OR gives you both those options' 1's in the appropriate place. So combining options 1 and 3 would be:

00101

However, if you used AND on any of the above options you'd just get 0 unless you used it with two OR combinations of course - but that's where it gets complicated!)

Bitwise manipulation is a very powerful thing when used in the right hands, however it's also potentially very confusing and doesn't really fit Java's philosophy - hence its replacement. The simple parts of it are relatively easy to understand, but these days it's really best avoided simply because it makes your code non intuitive to read (as you've just proven with the above completely valid question!) :)
 
Back
Top Bottom