# FlagsQt.py Copyright (c) Kari Laitinen # http://www.naturalprogramming.com # 2009-12-07 File created. # 2013-10-14 Last modification (Some names changed.) # This program demonstrates: # - the use of inherited classes # - the use of a constructor that accepts a varying # number of arguments (actual parameters) # - how to build a multi-layered user interface with a QTabWidget # object. A QTabWidget object can contain several tabs, and each # tab may contain, for example, a QWidget 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. import sys from PyQt4.QtCore import * from PyQt4.QtGui import * # Class Flag is a kind of 'abstract' superclass for the other # flag classes. It is abstract only in the sense that no objects of # type Flag are used in this program. Python does not have # abstract classes in the sense like other languages such as Java. # Each subclass of class Flag has its own draw() method which draws # the flag in question. class Flag : def __init__( self ) : self.flag_height = 240 self.flag_length = int( self.flag_height * 3 / 2 ) self.flag_position_x = 100 self.flag_position_y = 80 self.flag_description = "" self.flag_colors = () # The constructor parameter declared as *given_colors in # classes VerticalStripesFlag and HorizontalStripesFlag is # a tuple containing the color strings that are given as # individual strings when the constructors are called. # A formal parameter declared with a * is a tuple that # represents a varying number of actual parameters (arguments) class VerticalStripesFlag ( Flag ) : def __init__( self, given_flag_description, *given_colors ) : Flag.__init__( self ) self.flag_description = given_flag_description self.flag_colors = given_colors self.number_of_stripes_to_draw = len( self.flag_colors ) self.stripe_width = self.flag_length / self.number_of_stripes_to_draw # The following statement adjusts flag_length in the case # when the previous statement "lost pixels" in rounding. self.flag_length = self.number_of_stripes_to_draw * self.stripe_width def draw( self, painter ) : for stripe_index in range( self.number_of_stripes_to_draw ) : painter.fillRect( self.flag_position_x + stripe_index * self.stripe_width, self.flag_position_y, self.stripe_width, self.flag_height, self.flag_colors[ stripe_index ] ) painter.setPen( Qt.black ) painter.setBrush( Qt.NoBrush ) painter.drawRect( self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) painter.drawText( self.flag_position_x, self.flag_position_y + self.flag_height + 20, self.flag_description ) class HorizontalStripesFlag ( Flag ) : def __init__( self, given_flag_description, *given_colors ) : Flag.__init__( self ) self.flag_description = given_flag_description self.flag_colors = given_colors self.number_of_stripes_to_draw = len( self.flag_colors ) self.stripe_height = self.flag_height / self.number_of_stripes_to_draw # The following statement ensures that the flag height, # which is an int value, corresponds with the stripe height. self.flag_height = self.number_of_stripes_to_draw * self.stripe_height def draw( self, painter ) : for stripe_index in range( self.number_of_stripes_to_draw ) : painter.fillRect( self.flag_position_x, self.flag_position_y + stripe_index * self.stripe_height, self.flag_length, self.stripe_height, self.flag_colors[ stripe_index ] ) painter.setPen( Qt.black ) painter.setBrush( Qt.NoBrush ) painter.drawRect( self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) painter.drawText( self.flag_position_x, self.flag_position_y + self.flag_height + 20, self.flag_description ) class CrossFlag ( Flag ) : # 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. def __init__( self, given_flag_description, given_background_color, given_wide_cross_color, given_narrow_cross_color, given_flag_ratio, given_cross_point_ratio, given_wide_cross_width_ratio, given_narrow_cross_width_ratio ) : Flag.__init__( self ) self.flag_description = given_flag_description # We'll construct a tuple of the given flag colors self.flag_colors = ( given_background_color, given_wide_cross_color, given_narrow_cross_color ) self.flag_length = (int) ( self.flag_height / given_flag_ratio ) self.cross_point = (int) ( self.flag_length * given_cross_point_ratio ) self.wide_cross_width = (int) ( self.flag_length * given_wide_cross_width_ratio ) self.narrow_cross_width = (int) (self.flag_length * given_narrow_cross_width_ratio) def draw( self, painter ) : # Let's fill the flag background with the first color painter.fillRect( self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height, self.flag_colors[ 0 ] ) # wide cross will be drawn with the second color painter.fillRect( self.flag_position_x, self.flag_position_y + self.flag_height / 2 - self.wide_cross_width / 2, self.flag_length, self.wide_cross_width, self.flag_colors[ 1 ] ) painter.fillRect( self.flag_position_x + self.cross_point - self.wide_cross_width / 2, self.flag_position_y, self.wide_cross_width, self.flag_height, self.flag_colors[ 1 ] ) # narrow cross will be drawn with the third color painter.fillRect( self.flag_position_x, self.flag_position_y + self.flag_height / 2 - self.narrow_cross_width / 2, self.flag_length, self.narrow_cross_width, self.flag_colors[ 2 ] ) painter.fillRect( self.flag_position_x + self.cross_point - self.narrow_cross_width / 2, self.flag_position_y, self.narrow_cross_width, self.flag_height, self.flag_colors[ 2 ] ) painter.setPen( Qt.black ) painter.setBrush( Qt.NoBrush ) painter.drawRect( self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) painter.drawText( self.flag_position_x, self.flag_position_y + self.flag_height + 20, self.flag_description ) # Class FlagPanel specifies objects that will be attached as # tabs into a QTabWidget. class FlagPanel ( QWidget ) : def __init__( self, parent ) : QWidget.__init__( self, parent ) self.flags_to_be_shown = [] self.index_of_currently_shown_flag = 0 button_to_see_previous_flag = QPushButton( " < ", self ) button_to_see_next_flag = QPushButton( " > ", self ) self.connect( button_to_see_previous_flag, SIGNAL( "clicked()" ), self.previous_button_clicked ) self.connect( button_to_see_next_flag, SIGNAL( "clicked()" ), self.next_button_clicked ) horizontal_box_for_buttons = QHBoxLayout() horizontal_box_for_buttons.addStretch( 1 ) horizontal_box_for_buttons.addWidget( button_to_see_previous_flag ) horizontal_box_for_buttons.addWidget( button_to_see_next_flag ) horizontal_box_for_buttons.addStretch( 1 ) main_vertical_box = QVBoxLayout() main_vertical_box.addStretch( 1 ) main_vertical_box.addLayout( horizontal_box_for_buttons ) self.setLayout( main_vertical_box ) def add_flag( self, new_flag_to_this_panel ) : self.flags_to_be_shown.append( new_flag_to_this_panel ) def previous_button_clicked( self ) : self.index_of_currently_shown_flag -= 1 if self.index_of_currently_shown_flag < 0 : self.index_of_currently_shown_flag = len( self.flags_to_be_shown ) - 1 self.update() def next_button_clicked( self ) : self.index_of_currently_shown_flag += 1 if self.index_of_currently_shown_flag >= len( self.flags_to_be_shown ) : self.index_of_currently_shown_flag = 0 self.update() def paintEvent( self, event ) : painter = QPainter() painter.begin( self ) self.flags_to_be_shown[ \ self.index_of_currently_shown_flag ].draw( painter ) painter.end() class FlagsWindow( QWidget ) : def __init__( self, parent = None ) : QWidget.__init__( self, parent ) self.setGeometry( 100, 100, 580, 470 ) self.setWindowTitle( "VIEW FLAGS OF VARIOUS COUNTRIES" ) panel_for_flags_of_africa = FlagPanel( self ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Botswana",Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan, Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan,Qt.white, Qt.black,Qt.black,Qt.black,Qt.black, Qt.white,Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan, Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan,Qt.cyan)) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Chad", Qt.blue, Qt.yellow, Qt.red ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Ethiopia",Qt.green, Qt.yellow, Qt.red ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Gabon", Qt.green, Qt.yellow, Qt.blue ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "The Gambia", Qt.red, Qt.red, Qt.red, Qt.red, Qt.red, Qt.red, Qt.white, Qt.blue,Qt.blue,Qt.blue, Qt.blue, Qt.white, Qt.green, Qt.green, Qt.green,Qt.green,Qt.green,Qt.green ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Guinea", Qt.red, Qt.yellow, Qt.green ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Ivory Coast", QColor( 255, 190, 0 ), Qt.white, Qt.green ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Libya", QColor( 0, 180, 0 ) ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Mali", Qt.green, Qt.yellow, Qt.red ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Mauritius", Qt.red, Qt.blue, Qt.yellow, Qt.green ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Nigeria", QColor( 0, 180, 0 ), Qt.white, QColor( 0, 180, 0 ))) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Sierra Leone", Qt.green, Qt.white, Qt.blue ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Uganda (flag background)", Qt.black, Qt.yellow, Qt.red, Qt.black, Qt.yellow, Qt.red ) ) panel_for_flags_of_europe = FlagPanel( self ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Austria", Qt.red, Qt.white, Qt.red )) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Belgium", Qt.black, Qt.yellow, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Bulgaria",Qt.white, Qt.green, Qt.red ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Denmark", Qt.red, Qt.red, Qt.white, 28.0/37, 14.0/37, 4.0/37, 4.0/37 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Denmark, Faroe Islands", Qt.white, Qt.blue, Qt.red, 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Estonia", Qt.blue, Qt.black, Qt.white ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Finland", Qt.white, Qt.blue, Qt.blue, 11.0/18, 6.5/18, 3.0/18, 3.0/18 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Finland, Aland Province",QColor( 0, 0, 180 ),Qt.yellow,Qt.red, 34.0/52, 21.0/52, 10.0/52, 4.0/52 ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "France", Qt.blue, Qt.white, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Germany", Qt.black, Qt.red, QColor( 255, 190, 0 ) ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Holland", Qt.red, Qt.white, Qt.blue ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Hungary", Qt.red, Qt.white, Qt.green ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Iceland", Qt.blue, Qt.white, Qt.red, 18.0/25, 9.0/25, 4.0/25, 2.0/25 ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Ireland", Qt.green, Qt.white, QColor( 255, 190, 0 ) ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Italy", Qt.green, Qt.white, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Latvia", Qt.red, Qt.red, Qt.white, Qt.red, Qt.red)) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Liechtenstein (flag background)", Qt.blue, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Lithuania", Qt.yellow, Qt.green, Qt.red ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Malta (flag background)", Qt.white, Qt.red ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Norway", Qt.red, Qt.white, Qt.blue, 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Poland", Qt.white, Qt.red ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Portugal (flag background)", QColor( 0, 180, 0 ), QColor( 0, 180, 0 ), Qt.red, Qt.red, Qt.red ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Romania", Qt.blue, Qt.yellow, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Russia", Qt.white, Qt.blue, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "San Marino (Civil flag)", Qt.white, Qt.cyan ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain (flag background)", Qt.red, Qt.yellow, Qt.yellow, Qt.red ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain, Andalucia Civil flag", Qt.green, Qt.white, Qt.green ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Spain, Canary Islands Civil flag", Qt.white, Qt.blue, Qt.yellow ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain, Catalonia ", Qt.yellow, Qt.red, Qt.yellow, Qt.red, Qt.yellow, Qt.red, Qt.yellow, Qt.red, Qt.yellow ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Sweden", Qt.blue, Qt.yellow, Qt.yellow, 10.0/16, 6.0/16, 2.0/16, 2.0/16 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Sweden, Scania Region", Qt.red, Qt.yellow, Qt.yellow, 14.0/17, 7.0/17, 2.0/17, 2.0/17 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Ukraine", Qt.blue, Qt.yellow ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "United Kingdom, England", Qt.white, Qt.red, Qt.red, 3.0/5, 0.5, 3.0/25, 3.0/25 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Armenia", Qt.red, Qt.blue, QColor( 255, 190, 0 ) ) ) panel_for_flags_of_asia = FlagPanel( self ) panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "India (flag background)", QColor( 255, 190, 0 ), Qt.white, QColor( 0, 180, 0 ) ) ) panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "Indonesia", Qt.red, Qt.white ) ) panel_for_flags_of_asia.add_flag( VerticalStripesFlag( "Mongolia (flag backround)", Qt.red, Qt.blue, Qt.red ) ) panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "Thailand", Qt.red, Qt.white, Qt.blue, Qt.blue, Qt.white, Qt.red ) ) panel_for_flags_of_the_americas = FlagPanel( self ) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Argentina (flag background)", Qt.cyan, Qt.white, Qt.cyan)) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Chile, old flag of 1810", Qt.blue, Qt.white, Qt.yellow) ) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Colombia", Qt.yellow, Qt.yellow, Qt.blue, Qt.red ) ) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Costa Rica (flag background)", Qt.blue, Qt.white, Qt.red, Qt.red, Qt.white, Qt.blue ) ) panel_for_flags_of_the_americas.add_flag( VerticalStripesFlag( "Guatemala civil flag", QColor( 0, 0x66, 0xFF ), Qt.white, QColor( 0, 0x66, 0xFF ) )) panel_for_flags_of_the_americas.add_flag( VerticalStripesFlag( "Peru", Qt.red, Qt.white, Qt.red ) ) tabwidget_for_flag_panels = QTabWidget() tabwidget_for_flag_panels.addTab( panel_for_flags_of_africa, "Africa" ) tabwidget_for_flag_panels.addTab( panel_for_flags_of_europe, "Europe" ) tabwidget_for_flag_panels.addTab( panel_for_flags_of_asia, "Asia" ) tabwidget_for_flag_panels.addTab( panel_for_flags_of_the_americas, "Americas" ) main_vertical_layout = QVBoxLayout() main_vertical_layout.addWidget( tabwidget_for_flag_panels ) self.setLayout( main_vertical_layout ) # The main program begins. this_application = QApplication( sys.argv ) application_window = FlagsWindow() application_window.show() this_application.exec_() # NOTES: # In the Qt version of this program, some colors are made as follows: # "orange" is made as QColor( 255, 190, 0 ) # "green4" is made as QColor( 0, 180, 0 ) # "MidnightBlue" is made as QColor( 0, 0, 180 ) # It is possible to specify colors in Qt with the keywords specified at # http://www.w3.org/TR/SVG/types.html#ColorKeywords # Those keywords can be used as strings that are passed to QColor # constructor, e.g., QColor( "lemonchiffon" )