// FlagsApplet.java Copyright (c) Kari Laitinen // http://www.naturalprogramming.com // 2007-11-08 This file was created. // 2010-01-28 Latest modification. Flag of Austria is now better. /* This program demonstrates: - the use of inherited classes - the use of a constructor (method) that accepts a varying number of arguments (actual parameters) - dynamic ArrayList-based arrays - how to build a multi-layered user interface with a TabbedPane object. A TabbedPane object can contain several tabs, and each tab may contain a panel into which GUI components can be attached. This program displays flags of some countries. Flags are a nice example of classification: some flags contain three colored stripes in vertical direction, some flags contain colored stripes in horizontal direction, the flags of Nordic countries contain a cross, etc. In this program flags are classified in this way, and they are drawn according to this classification. I must, however, apologize and warn that all the flags are not displayed according to the exact specifications of the flags. For example, many flags are displayed so that their length-to-height ratio is a certain fixed value. In reality, however, the mentioned ratio can vary from country to country. Moreover, the flag colors shown by this program are not necessarily the exact variations of blue, green, red, or yellow that are used in real flags. The specifications of national flags are stipulated by laws of each country in question, and it is possible that this program thus breaks the laws of many countries. However, I hope that you might enjoy this program despite the fact that some flags are not drawn according to the official specifications. This program shows only flags that are relatively easy to draw. So, those flags that contain decorations that do not consist of straight lines cannot be displayed by this program. In some cases, which are mentioned, this program shows only the flag bacground, leaving a complicated detail undrawn. More notes at the end of this file. */ import java.awt.* ; import java.awt.event.* ; import javax.swing.* ; import java.util.ArrayList ; abstract class Flag { int flag_height = 240 ; int flag_length = flag_height * 3 / 2 ; int flag_position_x = 100, flag_position_y = 80 ; String flag_description ; ArrayList flag_colors = new ArrayList() ; public abstract void draw( Graphics graphics ) ; } class VerticalStripesFlag extends Flag { int number_of_stripes_to_draw, stripe_width ; public VerticalStripesFlag( String given_flag_description, Color... given_colors ) { flag_description = given_flag_description ; for ( Color given_color : given_colors ) { flag_colors.add( given_color ) ; } number_of_stripes_to_draw = flag_colors.size() ; stripe_width = flag_length / number_of_stripes_to_draw ; // The following statement adjusts flag_length in the case // when the previous statement "lost pixels" in rounding. flag_length = number_of_stripes_to_draw * stripe_width ; } public void draw( Graphics graphics ) { for ( int stripe_index = 0 ; stripe_index < number_of_stripes_to_draw ; stripe_index ++ ) { graphics.setColor( flag_colors.get( stripe_index ) ) ; graphics.fillRect( flag_position_x + stripe_index * stripe_width, flag_position_y, stripe_width, flag_height ) ; } graphics.setColor( Color.black ) ; graphics.drawRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.drawString( flag_description, flag_position_x, flag_position_y + flag_height + 20 ) ; } } class HorizontalStripesFlag extends Flag { int number_of_stripes_to_draw, stripe_height ; public HorizontalStripesFlag( String given_flag_description, Color... given_colors ) { flag_description = given_flag_description ; for ( Color given_color : given_colors ) { flag_colors.add( given_color ) ; } number_of_stripes_to_draw = flag_colors.size() ; stripe_height = flag_height / number_of_stripes_to_draw ; // The following statement ensures that the flag height, // which is an int value, corresponds with the stripe height. flag_height = number_of_stripes_to_draw * stripe_height ; } public void draw( Graphics graphics ) { for ( int stripe_index = 0 ; stripe_index < number_of_stripes_to_draw ; stripe_index ++ ) { graphics.setColor( flag_colors.get( stripe_index ) ) ; graphics.fillRect( flag_position_x, flag_position_y + stripe_index * stripe_height, flag_length, stripe_height ) ; } graphics.setColor( Color.black ) ; graphics.drawRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.drawString( flag_description, flag_position_x, flag_position_y + flag_height + 20 ) ; } } class CrossFlag extends Flag { int cross_point, wide_cross_width, narrow_cross_width ; // The ratios, which must be given when a CrossFlag // object is created, describe flag dimensions in relation to // the length of the flag. The term "wide cross" means the cross // that is underneath the other cross, the "narrow cross". In the flag // of Norway, for instance, the wide cross is white and the narrow cross is // blue. Not all cross flags (e.g., the Swedish flag) have a wide cross. // Such flags can be defined so that the color and width of the wide cross // are the same as the color and the width of the narrow cross. // The cross_point_ratio tells in which horizontal point the the // vertical cross bar is located. The horizontal cross bar is always // at the middle of the flag. // If the ratios are correctly specified, cross flags will be // shown with right proportional dimensions by this program. // These ratios are fairly easy to specify if you see (e.g. on // the Internet) how flags are officially defined. More information // about this subject can be found at the end of this file. public CrossFlag( String given_flag_description, Color given_background_color, Color given_wide_cross_color, Color given_narrow_cross_color, double given_flag_ratio, double given_cross_point_ratio, double given_wide_cross_width_ratio, double given_narrow_cross_width_ratio ) { flag_description = given_flag_description ; flag_colors.add( given_background_color ) ; flag_colors.add( given_wide_cross_color ) ; flag_colors.add( given_narrow_cross_color ) ; flag_length = (int) ( flag_height / given_flag_ratio ) ; cross_point = (int) ( flag_length * given_cross_point_ratio ) ; wide_cross_width = (int) ( flag_length * given_wide_cross_width_ratio ) ; narrow_cross_width = (int) (flag_length * given_narrow_cross_width_ratio); } public void draw( Graphics graphics ) { graphics.setColor( flag_colors.get( 0 ) ) ; // flag background color graphics.fillRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.setColor( flag_colors.get( 1 ) ) ; // wide cross color graphics.fillRect( flag_position_x, flag_position_y + flag_height / 2 - wide_cross_width / 2, flag_length, wide_cross_width ) ; graphics.fillRect( flag_position_x + cross_point - wide_cross_width / 2, flag_position_y, wide_cross_width, flag_height ) ; graphics.setColor( flag_colors.get( 2 ) ) ; // narrow cross color graphics.fillRect( flag_position_x, flag_position_y + flag_height / 2 - narrow_cross_width / 2, flag_length, narrow_cross_width ) ; graphics.fillRect( flag_position_x + cross_point - narrow_cross_width / 2, flag_position_y, narrow_cross_width, flag_height ) ; graphics.setColor( Color.black ) ; graphics.drawRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.drawString( flag_description, flag_position_x, flag_position_y + flag_height + 20 ) ; } } class FlagPanel extends JPanel implements ActionListener { JButton button_to_see_previous_flag, button_to_see_next_flag ; ArrayList flags_to_be_shown = new ArrayList() ; int index_of_currently_shown_flag = 0 ; public FlagPanel() { setLayout( new BorderLayout() ) ; JPanel button_panel = new JPanel() ; button_to_see_previous_flag = new JButton( " < " ) ; button_to_see_next_flag = new JButton( " > " ) ; button_to_see_previous_flag.addActionListener( this ) ; button_to_see_next_flag.addActionListener( this ) ; button_panel.add( button_to_see_previous_flag ) ; button_panel.add( button_to_see_next_flag ) ; add( "South", button_panel ) ; } public void add_flag( Flag new_flag_to_this_panel ) { flags_to_be_shown.add( new_flag_to_this_panel ) ; } public void actionPerformed( ActionEvent event ) { if ( event.getSource() instanceof JButton ) { if ( event.getSource() == button_to_see_previous_flag ) { index_of_currently_shown_flag -- ; if ( index_of_currently_shown_flag < 0 ) { index_of_currently_shown_flag = flags_to_be_shown.size() - 1 ; } } else if ( event.getSource() == button_to_see_next_flag ) { index_of_currently_shown_flag ++ ; if ( index_of_currently_shown_flag >= flags_to_be_shown.size() ) { index_of_currently_shown_flag = 0 ; } } repaint() ; } } public void paintComponent( Graphics graphics ) { super.paintComponent( graphics ) ; flags_to_be_shown.get( index_of_currently_shown_flag).draw( graphics ) ; } } public class FlagsApplet extends JApplet { public void init() { FlagPanel panel_for_flags_of_africa = new FlagPanel() ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Botswana",Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN, Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN,Color.WHITE, Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK, Color.WHITE,Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN, Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN,Color.CYAN)); panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Chad", Color.BLUE, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Ethiopia",Color.GREEN, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Gabon", Color.GREEN, Color.YELLOW, Color.BLUE ) ) ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "The Gambia", Color.RED, Color.RED, Color.RED, Color.RED, Color.RED, Color.RED, Color.WHITE, Color.BLUE,Color.BLUE,Color.BLUE, Color.BLUE, Color.WHITE, Color.GREEN, Color.GREEN, Color.GREEN,Color.GREEN,Color.GREEN,Color.GREEN ) ) ; panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Guinea", Color.RED, Color.YELLOW, Color.GREEN ) ) ; panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Ivory Coast", Color.ORANGE, Color.WHITE, Color.GREEN ) ) ; panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Libya", Color.GREEN.darker() ) ) ; panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Mali", Color.GREEN, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Mauritius", Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN ) ) ; panel_for_flags_of_africa.add_flag( new VerticalStripesFlag( "Nigeria", Color.GREEN.darker(), Color.WHITE, Color.GREEN.darker())); panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Sierra Leone", Color.GREEN, Color.WHITE, Color.BLUE ) ) ; panel_for_flags_of_africa.add_flag( new HorizontalStripesFlag( "Uganda (flag background)", Color.BLACK, Color.YELLOW, Color.RED, Color.BLACK, Color.YELLOW, Color.RED ) ); FlagPanel panel_for_flags_of_europe = new FlagPanel() ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Austria", Color.RED, Color.WHITE, Color.RED )); panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Belgium", Color.BLACK, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Bulgaria",Color.WHITE, Color.GREEN, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Denmark", Color.RED, Color.RED, Color.WHITE, 28.0/37, 14.0/37, 4.0/37, 4.0/37 ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Denmark, Faroe Islands", Color.WHITE, Color.BLUE, Color.RED, 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Estonia", Color.BLUE, Color.BLACK, Color.WHITE ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Finland", Color.WHITE, Color.BLUE, Color.BLUE, 11.0/18, 6.5/18, 3.0/18, 3.0/18 ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Finland, Åland Province",Color.BLUE.darker(),Color.YELLOW,Color.RED, 34.0/52, 21.0/52, 10.0/52, 4.0/52 ) ) ; panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "France", Color.BLUE, Color.WHITE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Germany", Color.BLACK, Color.RED, Color.ORANGE ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Holland", Color.RED, Color.WHITE, Color.BLUE ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Hungary", Color.RED, Color.WHITE, Color.GREEN ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Iceland", Color.BLUE, Color.WHITE, Color.RED, 18.0/25, 9.0/25, 4.0/25, 2.0/25 ) ) ; panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Ireland", Color.GREEN, Color.WHITE, Color.ORANGE ) ) ; panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Italy", Color.GREEN, Color.WHITE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Latvia", Color.RED, Color.RED, Color.WHITE, Color.RED, Color.RED)); panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Liechtenstein (flag background)", Color.BLUE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Lithuania", Color.YELLOW, Color.GREEN, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Malta (flag background)", Color.WHITE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Norway", Color.RED, Color.WHITE, Color.BLUE, 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Poland", Color.WHITE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Portugal (flag background)", Color.GREEN.darker(), Color.GREEN.darker(), Color.RED, Color.RED, Color.RED ) ); panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Romania", Color.BLUE, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Russia", Color.WHITE, Color.BLUE, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "San Marino (Civil flag)", Color.WHITE, Color.CYAN ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Spain (flag background)", Color.RED, Color.YELLOW, Color.YELLOW, Color.RED ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Spain, Andalucia Civil flag", Color.GREEN, Color.WHITE, Color.GREEN ) ); panel_for_flags_of_europe.add_flag( new VerticalStripesFlag( "Spain, Canary Islands Civil flag", Color.WHITE, Color.BLUE, Color.YELLOW ) ); panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Spain, Catalonia ", Color.YELLOW, Color.RED, Color.YELLOW, Color.RED, Color.YELLOW, Color.RED, Color.YELLOW, Color.RED, Color.YELLOW ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Sweden", Color.BLUE, Color.YELLOW, Color.YELLOW, 10.0/16, 6.0/16, 2.0/16, 2.0/16 ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "Sweden, Scania Region", Color.RED, Color.YELLOW, Color.YELLOW, 14.0/17, 7.0/17, 2.0/17, 2.0/17 ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Ukraine", Color.BLUE, Color.YELLOW ) ) ; panel_for_flags_of_europe.add_flag( new CrossFlag( "United Kingdom, England", Color.WHITE, Color.RED, Color.RED, 3.0/5, 0.5, 3.0/25, 3.0/25 ) ) ; panel_for_flags_of_europe.add_flag( new HorizontalStripesFlag( "Armenia", Color.RED, Color.BLUE, Color.ORANGE ) ) ; FlagPanel panel_for_flags_of_asia = new FlagPanel() ; panel_for_flags_of_asia.add_flag( new HorizontalStripesFlag( "India (flag background)", Color.ORANGE, Color.WHITE, Color.GREEN.darker() ) ) ; panel_for_flags_of_asia.add_flag( new HorizontalStripesFlag( "Indonesia", Color.RED, Color.WHITE ) ) ; panel_for_flags_of_asia.add_flag( new VerticalStripesFlag( "Mongolia (flag backround)", Color.RED, Color.BLUE, Color.RED ) ) ; panel_for_flags_of_asia.add_flag( new HorizontalStripesFlag( "Thailand", Color.RED, Color.WHITE, Color.BLUE, Color.BLUE, Color.WHITE, Color.RED ) ) ; FlagPanel panel_for_flags_of_the_americas = new FlagPanel() ; panel_for_flags_of_the_americas.add_flag( new HorizontalStripesFlag( "Argentina (flag background)", Color.CYAN, Color.WHITE, Color.CYAN)); panel_for_flags_of_the_americas.add_flag( new HorizontalStripesFlag( "Chile, old flag of 1810", Color.BLUE, Color.WHITE, Color.YELLOW) ) ; panel_for_flags_of_the_americas.add_flag( new HorizontalStripesFlag( "Colombia", Color.YELLOW, Color.YELLOW, Color.BLUE, Color.RED ) ) ; panel_for_flags_of_the_americas.add_flag( new HorizontalStripesFlag( "Costa Rica (flag background)", Color.BLUE, Color.WHITE, Color.RED, Color.RED, Color.WHITE, Color.BLUE ) ) ; panel_for_flags_of_the_americas.add_flag( new VerticalStripesFlag( "Guatemala civil flag", new Color(0,102,255), Color.WHITE, new Color(0,102,255) )); panel_for_flags_of_the_americas.add_flag( new VerticalStripesFlag( "Peru", Color.RED, Color.WHITE, Color.RED ) ) ; JTabbedPane tabbed_pane_for_flag_panels = new JTabbedPane() ; tabbed_pane_for_flag_panels.addTab( "Africa", panel_for_flags_of_africa ) ; tabbed_pane_for_flag_panels.addTab( "Europe", panel_for_flags_of_europe ); tabbed_pane_for_flag_panels.addTab( "Asia", panel_for_flags_of_asia ) ; tabbed_pane_for_flag_panels.addTab( "Americas", panel_for_flags_of_the_americas ) ; getContentPane().add( tabbed_pane_for_flag_panels ) ; } } /* Possible exercises with this program: Explore the documentation of class JTabbedPane and make the used tabs selectable via the keyboard. The FlagPanel class does not work if no flags are added to it. The reason for this problem is that it always attempts to show the first flag in the ArrayList array. Fix this problem. Modify the user interface provided by the FlagPanel class so that a flag can be selected from a list. Create a new tab which shows flags of imaginary countries. Create a new tab which contains a panel that allows the user to design new flags. The user should be able to select a flag type and its colors. Consider if you can write new classes to display more complicated flags. For example, the British flag cannot be displayed by this program. If you could produce the structure of the flag of the United Kingdom, it might be easy to produce the Australia and New Zealand flags as well. The U.S. flag is also difficult to draw. The stripes can by created with the following statement. panel_for_flags_of_the_americas.add_flag( new HorizontalStripesFlag( "Stripes flag. This could serve as a basis for the USA flag.", Color.RED, Color.WHITE, Color.RED, Color.WHITE, Color.RED, Color.WHITE, Color.RED, Color.WHITE, Color.RED, Color.WHITE, Color.RED, Color.WHITE, Color.RED ) ) ; but the "star-section" of the U.S. flag is a more difficult structure to be created. HorizontalStripesFlag could serve as a base class for the class that creates the U.S. flag. INFORMATION ABOUT FLAGS: A nice site to find information about flags is http://www.crwflags.com It might be a good idea to use Google to search the site and give the site name as one search word. For example, the crwflags site gives the following information about the flag of Norway. The official proportions of the flag are 16:22, being divided horizontally 6:1:2:1:12 and vertically 6:1:2:1:6 This means that the length of the flag is 22 units and its height is 16 units. The width of the wide cross is 4 units and the width of the narrow cross is 2 units. The site also shows a clear picture that explains the flag dimensions. As we have this information, we can create the Norwegian flag with the statement panel_for_flags_of_europe.add_flag( new CrossFlag( "Norway", Color.RED, Color.WHITE, Color.BLUE, 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) ; THE FOLLOWING CLASS WAS USED IN AN EARLY VERSION OF THIS PROGRAM. IT IS REPLACED BY THE CrossFlag class. class NordicCrossFlag extends Flag { public NordicCrossFlag( String given_flag_description, Color given_background_color, Color given_middle_color, Color given_cross_color ) { flag_description = given_flag_description ; flag_colors.add( given_background_color ) ; flag_colors.add( given_middle_color ) ; flag_colors.add( given_cross_color ) ; } public void draw( Graphics graphics ) { graphics.setColor( flag_colors.get( 0 ) ) ; graphics.fillRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.setColor( flag_colors.get( 1 ) ) ; graphics.fillRect( flag_position_x, flag_position_y + flag_height * 3/8, flag_length, flag_height * 2/8 ) ; graphics.fillRect( flag_position_x + flag_length * 3/12, flag_position_y, flag_length * 2/12, flag_height ) ; graphics.setColor( flag_colors.get( 2 ) ) ; graphics.fillRect( flag_position_x, flag_position_y + flag_height * 7/16, flag_length, flag_height * 1/8 ) ; graphics.fillRect( flag_position_x + flag_length * 7/24, flag_position_y, flag_length * 1/12, flag_height ) ; graphics.setColor( Color.black ) ; graphics.drawRect( flag_position_x, flag_position_y, flag_length, flag_height ) ; graphics.drawString( flag_description, flag_position_x, flag_position_y + flag_height + 20 ) ; } } */