Join Club ShowMeDo to Learn Python!

This series is a part of Club ShowMeDo. Click to learn why you should join our club with a simple monthly subscription.

  • We teach Python and all the cool modules
  • Topics include beginner Python, GUIs, Web and Desktop Apps
  • Long, specially crafted video tutorials just for you
  • Club video tutorials extend our normal Free content
  • Save your time - we've done the research for you
  • Keep your skills up-to-date
  • Learn at your own pace, everything you need is shown to you
  • Over 12 hours of archived material are waiting for you in the club

Name: [002] Ian Ozsvald
Member: 109 months
Authored: 181 videos
Description: I am the co-founder of ShowMeDo (see http://showmedo.com/about), author of `The Screencasting Handbook <http://thescreencastinghandbook.com>`_ and the founder of the professional screencast production company `ProCasts <http://procasts.co.uk>`_: .. image:: http://procasts.co.uk/media/procasts_sma ...

Worked solution - Splash Screen [ID:560] (14/14)

in series: Build a wxPython Image Viewer

(Showmedo is undergoing major changes. To report any problems viewing the videos please email us and include browser and OS specifics. Cheers - Kyran.)

Here I show the worked solution for the Splash Screen exercise. We also test to make sure that the splash-screen image exists and silently ignore it if it doesn't.

import os
import wx
import wx.html

MAIN_WINDOW_DEFAULT_SIZE = (300,200)
ABOUT_DIALOG_SIZE = (400,280)
SPLASH_SCREEN_FILENAME = 'splashscreen.jpg'
SPLASH_SCREEN_TIMEOUT = 3000

class ImageViewerAbout(wx.Dialog):
    """This AboutBox is built from Robin Dunn and Noel Rappin's
    excellent wxPython in Action book, see page 178+ for the About HTML box
    and page 174+ for a short discussion on BoxSizers"""
    
    text = '''<html>
    <h1>ShowMeDo Image Viewer</h1>
    <p>The ShowMeDo Image Viewer is a demonstration application for the ShowMeDo
    wxPython 'image viewing' tutorial.</p>
    <p>More information is available at <a href="http://showmedo.com">ShowMeDo.com</a>.<p>
    <p>Created February 2008, Copyright &copy; ShowMeDo Ltd.</p>
    </html>'''
    
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, -1, 'About the ShowMeDo Image Viewer...',
                           size=ABOUT_DIALOG_SIZE)
        
        html = wx.html.HtmlWindow(self)
        html.SetPage(self.text)
        # If a button has an ID of wx.ID_OK it will automatically close a wx.Dialog when pressed
        # create a 'button' object from wx.Button, give it the ID wx.ID_OK and text 'Okay'
        button = wx.Button(self, wx.ID_OK, 'Okay')

        # Create a BoxSizer which grows in the vertical direction
        sizer = wx.BoxSizer(wx.VERTICAL)
        # Add the html window, tell it to take a 100% portion of the *available* area
        # and to EXPAND in ALL directions.  Use a border of 5 pixels around ALL sides of the button
        sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5)

        # Add the button, ask it to grow by 0%
        #sizer.Add(button, 0)
        # also ask the button to align in the centre (my UK spelling!), with a 5 pixel border
        # around all sides
        sizer.Add(button, 0, wx.ALIGN_CENTER|wx.ALL, 5)

        # Tell our Dialog to use this new Sizer
        self.SetSizer(sizer)
        # Tell our Dialog to calculate the size of its items.  Good practice to always do this
        self.Layout()

class Frame(wx.Frame):
    
    def __init__(self, parent, id, title):
        style=wx.DEFAULT_FRAME_STYLE ^ (wx.RESIZE_BORDER) # XOR to remove the resizeable border        
        wx.Frame.__init__(self, parent, id, title=title, size=MAIN_WINDOW_DEFAULT_SIZE, style=style)
        self.Center() # open in the centre of the screen
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour('White') # make the background of the window white

        self.CreateMenuBar()
        
        # create a StatusBar and give it 2 columns
        self.statusBar = self.CreateStatusBar()
        self.statusBar.SetFieldsCount(2)
        self.statusBar.SetStatusText('No image specified', 1)
        
        self.bitmap = None # set to None as we refer to it in ShowBitmap before we instantiate it
        
    def CreateMenuBar(self):
        "Create a menu bar with Open, Exit items"
        menuBar = wx.MenuBar()
        # Tell our Frame about this MenuBar
        self.SetMenuBar(menuBar)
        menuFile = wx.Menu()
        menuBar.Append(menuFile, '&File')
        # NOTE on wx ids - they're used everywhere, we don't care about them
        # Used to handle events and other things
        # An id can be -1 or wx.ID_ANY, wx.NewId(), your own id
        # Get the id using object.GetId()
        fileOpenMenuItem = menuFile.Append(-1, '&Open Image', 'Open a picture')
        #print "fileOpenMenuItem.GetId()", fileOpenMenuItem.GetId()
        self.Bind(wx.EVT_MENU, self.OnOpen, fileOpenMenuItem)

        # add a 'mirror' option, disable it for now
        # we add mirrorMenuItem to self so that we can reference it later
        self.mirrorMenuItem = menuFile.Append(-1, '&Mirror Image', 'Mirror the image horizontally')
        self.mirrorMenuItem.Enable(False) # we can't mirror an image until we've loaded one in, so start with 'mirror' disabled
        self.Bind(wx.EVT_MENU, self.OnMirrorImage, self.mirrorMenuItem)
        
        # create a menu item for Exit and bind it to the OnExit function       
        exitMenuItem = menuFile.Append(-1, 'E&xit', 'Exit the viewer')        
        self.Bind(wx.EVT_MENU, self.OnExit, exitMenuItem)
        
        # add a Help menu with an About item
        menuHelp = wx.Menu()
        menuBar.Append(menuHelp, '&Help')
        helpMenuItem = menuHelp.Append(-1, '&About', 'About screen')
        self.Bind(wx.EVT_MENU, self.OnAbout, helpMenuItem)

    def OnAbout(self, event):
        dlg = ImageViewerAbout(self)
        dlg.ShowModal()
        dlg.Destroy()

    def OnMirrorImage(self, event):
        # ask the Image to mirror itself on the x-axis
        self.image = self.image.Mirror()
        # whilst we mirror it and show it, we haven't yet forced a repaint so we won't see it unless we hide the window
        self.ShowBitmap()
        # now we can ask for a refresh which repaints the image
        self.Refresh()

    def OnOpen(self, event):
        "Open an image file, set title if successful"
        # Create a file-open dialog in the current directory
        
        filters = 'Image files (*.gif;*.png;*.jpg)|*.gif;*.png;*.jpg'
        dlg = wx.FileDialog(self, message="Open an Image...", defaultDir=os.getcwd(), 
                            defaultFile="", wildcard=filters, style=wx.OPEN)
        
        # Call the dialog as a model-dialog so we're required to choose Ok or Cancel
        if dlg.ShowModal() == wx.ID_OK:
            # User has selected something, get the path, set the window's title to the path
            filename = dlg.GetPath()
            self.SetTitle(filename)
            wx.BeginBusyCursor()            
            # load the image from the filename
            self.image = wx.Image(filename, wx.BITMAP_TYPE_ANY, -1) # auto-detect file type        
            # set the StatusBar to show the image's size
            self.statusBar.SetStatusText('Size = %s' % (str(self.image.GetSize())) , 1)
            # display the image inside the panel
            self.ShowBitmap()
            # enable the 'Mirror' menu item, it only makes sense to enable it when we've loaded
            # an image as before there would be no image to mirror
            self.mirrorMenuItem.Enable(True)
            wx.EndBusyCursor()
                        
        dlg.Destroy() # we don't need the dialog any more so we ask it to clean-up

    def ShowBitmap(self):
        if self.bitmap is not None:
            self.bitmap.Destroy()
        
        # Convert to Bitmap for wxPython to draw it to screen
        self.bitmap = wx.StaticBitmap(self.panel, -1, wx.BitmapFromImage(self.image))       
        # Make the application's window as large as the image
        self.SetClientSize(self.bitmap.GetSize())
        self.Center() # open in the centre of the screen
        
    def OnExit(self, event):
        "Close the application by Destroying the object"
        self.Destroy() 
        
    
class App(wx.App):
    
    def OnInit(self):
        self.frame = Frame(parent=None, id=-1, title='Image Viewer')
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True
    
if __name__ == "__main__":       
    # make an App object, set stdout to the console so we can see errors
    app = App(redirect=False)
        
    # open a splash screen if it exists
    if os.path.exists(SPLASH_SCREEN_FILENAME):
        splash_image = wx.Image(SPLASH_SCREEN_FILENAME, wx.BITMAP_TYPE_ANY, -1)        
        wx.SplashScreen(splash_image.ConvertToBitmap(), 
                        wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, 
                        SPLASH_SCREEN_TIMEOUT, 
                        None, -1)
        
    app.MainLoop()

Got any questions?

Get answers in the ShowMeDo Learners Google Group.

Video statistics:

  • Video's rank shown in the most popular listing
  • Video plays: 76 (since July 30th)
  • Plays in last week: 0
  • Published: 82 months ago

Thank-yous, questions and comments

If this video tutorial was helpful please take some time to say thank-you to the authors for their hard work. Feel free to ask questions. Let the author know why their video tutorial was useful - what are you learning about? Did the video tutorial save you time? Would you like to see more?

You may also want to see our ShowMeDo Google Group to speak to our active users and authors.

Your email address will not be published.

Show some quick comments >>








All comments excluding tick-boxed quick-comments

In addition to the good introduction to wxPython, this set of tutorials strengthened my understanding of Classes. Now off to learn how wxGrid fits into this basic framework as I intend to create a specialized spreadsheet application.


This series has sparked my interest, which brings me to the fact that a image sizer wasn't created for the image viewer.

In which case I am now working on an image sizer that will sense the size of the image uploaded and if it is bigger than a set default it will resize the image to that default. You can then resize the image to your liking using a Image > Resize > 10% - 100% MenuBar option.

Would I be allowed to post a video or two explaining how to make that once it's done?


Excellent series. Refreshed my memory on doing gui stuff in with other packages. I haven't searched the website yet but I hope to find how to use py2exe and something that I could use to create an installer so I coud distribute the program to non python users


I am reading Beginning Python By Magnus Lie Hetland this series really filled the viod that is in his book. Great series. Would like to see more on wx.


Great series - thanks.


Great first video, don't know about the others, even after signing up and logging in I still could not watch them, shame :-(


Great first video, don't know about the others, even after signing up and logging in I still could not watch them, shame :-(


Great series.Very useful

Thanks!


Thank you very much for putting this series together. It gave me a good introduction to writting GUI apps in Python.


Ian, thanks for this series. it was excellent. i am thinking about moving from vba to python to build sophisticated investment models.

JN


Review of Worked solution - Splash Screen

This was a great series. I've never done any GUI programming, but I have a need to create some gui applications. This series really helped me get up and running. It covered many of the topics that I need to develop a useful application.

I work in research and development and I'll be developing some internal software tools to collect and analyze data. I'm getting ready to write a program to analyze scope traces. I plan to draw the traces on a bitmap and have movable cursors to read values from each of the traces. I think I've got a firm foundation from this series to get me up and running.

Thanks very much.

- travis


Hi Ian,

This series is very helpful. Also mentioned on the Learners Group, opening the browser window does happen as planned. However, the browser opens inside the Python dialog window. How can this link become improved to open the browser in its own window?

You also need to know your tutorials have "broken the ice" with Python and leads my interest with future applications including working with Python utilized in Maya 3D. Maya has script code known as MEL that is effective with Python.

Thank you.


Of course I ran into the issue with the Copyright symbol. I didn't read the comments on this page until after I posted on the google group. Silly me :) I really liked the series. I'm learning Python because I've moved to Ubuntu for my main pc and I'd like to contribute to the Open Source Community. I have a bit of programming exp but nothing extensive. Keep up the great work!!


Ian,

thanks for this nice series. It was a good refresher on wxPython and gave me a good wx template for my own application.

Just to add my 2 cents:

* It would be nice to learn something about the differences between wx.Image and wx.Bitmap. Why do two different classes exist to handle pictures? How do they fit together?

* maybe adding the encoding to the source like "# coding: latin-1" or so might make sense. Otherwise the copyright symbol in the triple quoted string of the "about text" might give a Non-ASCII character warning irritating for beginners.

* While building the splash screen you are using

if os.path.exists(SPLASH_SCREEN_FILENAME):

...

to check if the file is present.

This however does not catch cases where the file is present but not readable (e.g. due to missing permissions). Furthermore its possible (while unlikely) that the file disappears between the call to os.path.exists and the actual loading of the file.

When reading a file I usually just try to do so catching errors while actually opening the file to avoid the issues named above.

try:

f = open(SPLASH_SCREEN_FILENAME, "rb")

except IOError:

pass

else:

splash_image = wx.ImageFromStream(f, wx.BITMAP_TYPE_ANY, -1)

wx.SplashScreen(splash_image.ConvertToBitmap(),

wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,

SPLASH_SCREEN_TIMEOUT,

None, -1)

f.close()

* last one: It would be nice to be able to comment on a complete video-series and not just on single videos. I liked all the videos in the wx image viewer tutorial but - well, I just did not want to write 14 comments :)


Video published, thanks for contributing to ShowMeDo


Showmedo is a peer-produced video-tutorials and screencasts site for free and open-source software (FOSS)- with the exception of some club videos, the large majority are free to watch and download.

how to help » about » faq »

Educating the Open-source Community With Showmedo

Although as important as the software it supports, education and documentation are relatively neglected in the Open-source world. Coders love to code, and explaining how best to use or improve the software tends to be deferred or even sidelined.

At Showmedo we believe the community can play a vital role here and also say thanks for the tools and software that make our lives easier. If you have a piece of software you love or a programming langugage you are enthusiastic about, why not make a screencast showing others how to use it? All the stuff you wish you'd been told, the tips, tricks, insights that would have saved you time and frustration.

Screencasting is easier than you think, and we're happy to help you. You can emailus for advice or just use some of the how-to screencasts on the site. This screencasting learning-pathis a good place to start.

Kudos and Thanks for Ian

Content

Feedback

Showmedo's development is fairly rapid and bugs will inevitably creep in. If you have any problems please drop us a line using the contact address below. Likewise, any suggestions for improvements to the site are gratefully received.

feedback@showmedo.com