Joubran Al-maarry
Joubran Al-maarry

Reputation: 15

Can graphics.drawString change it properties outside paintComponent?

I'm trying to change the style of the string based on the status of two check boxes. One is boldCheck and the other is italicCheck. However when I run the program it draws the default string in the paintComponent and the two checkboxes are not working? and there is actual problems in the code itself but the problem seems the way I made this code. Any help on fixing this issue will be much appreciated.

import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class JavaTest {
    public static void main(String[] args) {
        JFrame window = new JFrame("HomeWork");
        DrawMessage message = new DrawMessage();
        window.add(message);
        window.setVisible(true);
        window.setSize(600,300);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }
    static class DrawMessage extends JPanel{
        private static final JCheckBox boldCheck = new JCheckBox("Bold");
        private static final JCheckBox italicCheck = new JCheckBox("Italic");

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setFont(new Font("TimesRoman", Font.PLAIN, 20));
            g.setColor(Color.blue);
            g.drawString("Welcome to java Programing", 40, 40);
            setBackground(Color.yellow);
            add(boldCheck);
            add(italicCheck);
            CheckBoxHandler handler = new CheckBoxHandler();
            boldCheck.addItemListener(handler);
            italicCheck.addItemListener(handler);
        }
        static private class CheckBoxHandler extends DrawMessage implements ItemListener{
            private int valBold = Font.PLAIN;
            private int valItalic = Font.PLAIN;

            @Override
            public void itemStateChanged(ItemEvent e) {
                if(e.getSource() == boldCheck){
                    valBold = boldCheck.isSelected() ? Font.BOLD: Font.PLAIN;
                }
                if(e.getSource() == italicCheck){
                    valItalic = italicCheck.isSelected() ? Font.ITALIC : Font.PLAIN;
                }
                DrawMessage obj = new DrawMessage();
                obj.setFont(new Font("TimesRoman", valBold + valItalic, 20));
            }
        }
    }
}

Upvotes: 0

Views: 112

Answers (2)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51559

I made a few changes to your code.

  1. I started the application with a call to the SwingUtilities invokeLater method. This method ensures that the Swing comp[onents are created and executed on the Event Dispatch Thread.

  2. I created two JPanels, one for the checkbox buttons and one to draw the text. Generally, it's not a good idea to put Swing components on a drawing JPanel.

  3. I made the valBold and valItalic fields global since they're set in the controller class and used in the drawing panel class.

  4. The drawing panel draws the text. Period. The controller class will adjust the global Font fields.

  5. I made the drawing panel class and the item listener class public inner classes.

Here's the complete runnable code.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class DrawStringGUI implements Runnable {
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new DrawStringGUI());
    }
    
    private DrawMessage message;
    
    private JCheckBox boldCheck;
    private JCheckBox italicCheck;
    
    private int valBold = Font.PLAIN;
    private int valItalic = Font.PLAIN;
    
    @Override
    public void run() {
        JFrame window = new JFrame("HomeWork");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        window.add(createCheckBoxPanel(), BorderLayout.BEFORE_FIRST_LINE);
        message = new DrawMessage();
        window.add(message, BorderLayout.CENTER);
        
        window.pack();
        window.setVisible(true);
    }
    
    private JPanel createCheckBoxPanel() {
        JPanel panel = new JPanel();
        
        CheckBoxHandler handler = new CheckBoxHandler();
        
        boldCheck = new JCheckBox("Bold");
        boldCheck.addItemListener(handler);
        panel.add(boldCheck);
        
        italicCheck = new JCheckBox("Italic");
        italicCheck.addItemListener(handler);
        panel.add(italicCheck);
        
        return panel;
    }
    
    private void repaint() {
        message.repaint();
    }

    public class DrawMessage extends JPanel {

        private static final long serialVersionUID = 1L;
        
        public DrawMessage() {
            this.setBackground(Color.YELLOW);
            this.setPreferredSize(new Dimension(350, 100));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            int style = valBold | valItalic;
                    
            g.setFont(new Font("TimesRoman", style, 20));
            g.setColor(Color.BLUE);
            g.drawString("Welcome to Java Programing", 40, 40);
        }

    }
    
    public class CheckBoxHandler implements ItemListener {

        @Override
        public void itemStateChanged(ItemEvent event) {
            if (event.getSource() == boldCheck) {
                valBold = boldCheck.isSelected() ? Font.BOLD : Font.PLAIN;
            }
            if (event.getSource() == italicCheck) {
                valItalic = italicCheck.isSelected() ? Font.ITALIC : Font.PLAIN;
            }

            DrawStringGUI.this.repaint();
        }
    }
    
}

Upvotes: 1

Abra
Abra

Reputation: 20913

I believe the following code achieves what you desire.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class BoldItal extends JPanel implements ItemListener, Runnable {
    private JCheckBox  boldCheckBox;
    private JCheckBox  italicCheckBox;
    private JFrame  frame;

    public BoldItal() {
        setPreferredSize(new Dimension(600, 300));
        setBackground(Color.yellow);
    }

    @Override
    public void run() {
        showGui();
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        repaint();
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int style;
        if (boldCheckBox.isSelected()) {
            style = Font.BOLD;
            if (italicCheckBox.isSelected()) {
                style += Font.ITALIC;
            }
        }
        else {
            if (italicCheckBox.isSelected()) {
                style = Font.ITALIC;
            }
            else {
                style = Font.PLAIN;
            }
        }
        g.setFont(new Font("TimesRoman", style, 20));
        g.setColor(Color.blue);
        g.drawString("Welcome to java Programing", 40, 40);
    }

    private JPanel createCheckBoxes() {
        JPanel checkBoxesPanel = new JPanel();
        boldCheckBox = new JCheckBox("Bold");
        boldCheckBox.addItemListener(this);
        italicCheckBox = new JCheckBox("Italic");
        italicCheckBox.addItemListener(this);
        checkBoxesPanel.add(boldCheckBox);
        checkBoxesPanel.add(italicCheckBox);
        return checkBoxesPanel;
    }

    private void showGui() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(createCheckBoxes(), BorderLayout.PAGE_START);
        frame.add(this, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new BoldItal());
    }
}

You want a repaint to occur whenever you change the selection in one of the check boxes. Hence you add an ItemListener to each check box. Then, in method paintComponent() you set the Font style according to the values of the two check boxes.

You don't change the background color, hence no need to set it in method paintComponent(). Just set it once. I chose to set it in the class constructor, but that is not mandatory. It can also be set, for example, in method showGui().

Upvotes: 2

Related Questions