Friday, May 22, 2009

Rapid application development with Jython and JFace (part III – main menu and actions)

In first part of this series I showed how to create hello world application with Jython and JFace. In second part we added event listers and layouts. In this part we will add main menu and action. Menu This useful thing by which user can trigger commands and then application will do it's stuff. In order to have it in your application you should write class that will inherits from the MenuManager class. Add method to construct menu. And the last thing: you need to call addMenuBar() method to your application's constructor. Good now you have menu, right? Not jet, first you have to write some actions. Luck use your Actions! All action classes should inherit from Action (org.eclipse.jface.action.Action) class. Action is abstraction above event listeners. Actions are easy to implement and you reduce code size by using them. We will implement exit application action in todays example application. Code:
"""
Hello world application with Jython and JFace
Part III - Main menu and actions 
GUID of this code snippet: 7f75fc86-d78c-4ce1-8e28-97bb4f5d5b31
Author: Darius Kucinskas (c) 2008-2009
Email: d[dot]kucinskas[eta]gmail[dot]com
Blog: http://blog-of-darius.blogspot.com/
License: GPL
"""
from org.eclipse.swt import *
from org.eclipse.swt.SWT import *
from org.eclipse.swt.widgets import *
from org.eclipse.swt.layout import *
from org.eclipse.jface.window import *
from org.eclipse.jface.action import *

# Skip this for now
# Draw Lithuanian flag (I use it as icon for this example)
from org.eclipse.swt.graphics import *
def drawIcon(display):
    image = Image(display, 16, 16)
    gc = GC(image)
    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT))
    gc.fillRectangle(0, 0, 16, 16)
    gc.setBackground(Color(display, 253, 185, 19))
    gc.fillRectangle(0, 1, 16, 5)
    gc.setBackground(Color(display, 0, 106, 68))
    gc.fillRectangle(0, 6, 16, 10)
    gc.setBackground(Color(display, 193, 39, 45))
    gc.fillRectangle(0, 11, 16, 15)
    gc.dispose()
    return image

class ExitAction(Action):
    """ This is simple quit application action.
    
    All action classes should inherit from Action (org.eclipse.jface.action.Action) class.
    """
    
    def __init__(self, app):
        """ constructor of ExitAction
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        self.app = app
        self.text = "E&xit@Ctrl+Q"
        self.toolTipText = "Exit the application"
        
    def run(self):
        """ run() method of action. Every action class should have one.
        This time it closes application.
        """
        if self.app != None:
            self.app.close()

class MainMenuManager(MenuManager):
    """ MenuManager is responsible for constructing  menu """
    
    def __init__(self, app):
        """constructor of MainMenuManager
        
        arguments:
        app - in order to do anything useful I am passing 
        object of my application.    
        """
        # let parent class to do it's stuff first
        MenuManager.__init__(self)
        self.app = app
        
    def createMainMenu(self):
        """ creates menu """
        mainMenu = MenuManager("")
        fileMenu = MenuManager("&File")       
        mainMenu.add(fileMenu)
        
        # add Exit action to file menu 
        fileMenu.add(ExitAction(self.app))
        
        return mainMenu   

class App(ApplicationWindow):
    """ Your second JFace application in jython """
        
    def __init__(self, shell):
        """ application constructor """
        # let parent class to do it's stuff first
        ApplicationWindow.__init__(self, shell)
        
        # lets add menu
        self.addMenuBar()
    
    def dispose(self):
        """ dispose resources here """
        pass
        
    def createContents(self, parent):
        """ 
        Creates the main window's contents
        parent - the main window
        return - control
        """
        self.getShell().setImage(drawIcon(Display.getCurrent())) 
        self.getShell().text = 'Third Jython & JFace example'
        
        panel = Composite(parent, SWT.BORDER)
        # set layout as one column grid
        panel.setLayout(GridLayout(1, True))
        
        label = Label(panel, SWT.CENTER)
        label.text = 'Hello, World'
        label.setLayoutData(GridData(SWT.CENTER, SWT.CENTER, False, False, 1, 1))
        
        # you can use action instead of button        
        ActionContributionItem(ExitAction(self)).fill(panel)
        
        return panel
    
    def createMenuManager(self):
        """ create main menu """
        return MainMenuManager(self).createMainMenu()
    
if __name__ == "__main__":
    """ The application entry point """
    display = Display()
    shell = Shell(display)
    
    app = App(shell)
    
    # Voodoo of SWT message loop
    try:
        app.setBlockOnOpen(True)
        app.open()
    finally:
        if app != None:
            app.dispose()
    
    display.dispose()
May the Jython force be with you!