New things to learn in this part: Tree, SashForm, DirectoryDialog, TreeViewer, ITreeContentProvider, LabelProvider, ISelectionChangedListener.
Tree control
Tree control is used to display a hierarchy of items and issues notification when an item in the hierarchy is selected. We'll use this control in our application to display hierarchy of directories and files. User will be able to select image file and then we'll display selected image.
Divides client are into independent areas. We'll use it to divide application screen into two peaces: tree of files and image view area.
DirectoryDialogDirectory selection dialog.
TreeViewer, ITreeContentProvider, LabelProvider, ISelectionChangedListenerThese classes help to customize and simplify control of tree control. TreeViewer – sits on top of tree control and provides easy control of it, less of manual control is needed. ITreeContentProvider – provides items that should be displayed in tree control. LabelProvider – controls how items should apier in tree control. ISelectionChangedListener – tels what actions should be taken on item selection in tree control.
Explanation of source codeCreate SashFrom as top window and divide client area of it into two peaces: treePanel (displays tree control) and imagePanel (displays selected image). Tree will get 30% of application window and image will get 70% of application window.
mainForm = SashForm(parent, SWT.HORIZONTAL | SWT.NULL) treePanel = Composite(mainForm, SWT.NONE) imagePanel = Composite(mainForm, SWT.NONE) mainForm.setWeights([30, 70])In treePanel we should put tree control.
self.treeViewer = TreeViewer(treePanel, SWT.BORDER | SWT.VIRTUAL)We'll add ITreeContentProvider, LabelProvider, IselectionChangedListener to it.
self.treeViewer.setContentProvider(FileTreeContentProvider()) self.treeViewer.setLabelProvider(FileTreeLabelProvider()) self.treeViewer.addSelectionChangedListener(FileTreeSelectionChangedListener(self))We'll add canvas to imagePanel.
self.canvas = Canvas(imagePanel, SWT.BORDER | SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL)Class FileTreeContentProvider implements ITreeContentProvider
We search directory for directories and files and add those to tree.
Class FileTreeLabelProvider extends LabelProviderWe display short name of directory or file in tree control. If item is directory we are displaying directory image. If item is file we are displaying picture image.
Class FileTreeSelectionChangedListener implements ISelectionChangedListenerThen user selects item which is file we will display it in canvas.
Full Code
"""
Not so dumb image displaying application JPictureMaster II (Jython & JFace example)
Part VI - First application reviewed
GUID of this code snippet: 979fa00c-3001-4c24-b04d-f41d06f1d6d2
[ extends code snippet: eef8f89a-d1d6-4211-9063-ba4c736eb620 ]
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 *
from org.eclipse.jface.resource import *
from org.eclipse.swt.graphics import *
from org.eclipse.swt.custom import SashForm
from org.eclipse.jface.viewers import TreeViewer
from org.eclipse.jface.viewers import ITreeContentProvider
from org.eclipse.jface.viewers import LabelProvider
from org.eclipse.jface.viewers import ISelectionChangedListener
from java.lang import Math
from java.io import File
import jarray
# Skip this for now
# Draw glider emblem (I use it as icon for this example)
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, 193, 39, 45))
gc.fillRectangle( 1, 11, 4, 4)
gc.fillRectangle( 6, 11, 4, 4)
gc.fillRectangle(11, 11, 4, 4)
gc.fillRectangle(11, 6, 4, 4)
gc.fillRectangle( 6, 1, 4, 4)
gc.setBackground(Color(display, 253, 185, 19))
gc.fillRectangle( 1, 1, 4, 4)
gc.fillRectangle( 1, 6, 4, 4)
gc.fillRectangle(11, 1, 4, 4)
gc.setBackground(Color(display, 0, 106, 68))
gc.fillRectangle( 6, 6, 4, 4)
gc.dispose()
return image
class HBarListener(Listener):
""" Listener for horizontal scroll events """
def __init__(self, app):
self.app = app
def handleEvent(self, e):
selection = self.app.canvas.getHorizontalBar().getSelection()
x = -selection - self.app.origin.x
rect = self.app.image.getBounds()
self.app.canvas.scroll(x, 0, 0, 0, rect.width, rect.height, False)
self.app.origin.x = -selection
class VBarListener(HBarListener):
""" Listener for vertical scroll events """
def handleEvent(self, e):
selection = self.app.canvas.getVerticalBar().getSelection()
y = -selection - self.app.origin.y
rect = self.app.image.getBounds()
self.app.canvas.scroll(0, y, 0, 0, rect.width, rect.height, False)
self.app.origin.y = -selection
class CanvasPaintListener(HBarListener):
""" Listener for paint events """
def handleEvent(self, e):
gc = e.gc
gc.drawImage(self.app.image, self.app.origin.x, self.app.origin.y)
rect = self.app.image.getBounds()
client = self.app.canvas.getClientArea()
marginW = client.width - rect.width
if (marginW > 0):
gc.fillRectangle(rect.width, 0, marginW, client.height)
marginH = client.height - rect.height
if (marginH > 0):
gc.fillRectangle(0, rect.height, client.width, marginH)
class CanvasResizeListener(HBarListener):
""" Listener for resize events """
def handleEvent(self, e):
self.app.newOrResizeImage()
self.app.canvas.redraw()
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"
self.imageDescriptor = App.getImageRegistry().getDescriptor("file.exit")
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 OpenDirectoryAction(Action):
""" Simple open image action """
def __init__(self, app):
self.app = app
self.text = "O&pen@Ctrl+O"
self.toolTipText = "Open directiory and scan it for images"
self.imageDescriptor = App.getImageRegistry().getDescriptor("file.open")
def run(self):
# this code shows DirectoryDialog usage
dlg = DirectoryDialog(self.app.shell, SWT.OPEN)
dlg.filterPath = "."
dlg.text = "Select directory to scan for images"
dir = dlg.open()
if (not dir):
return
self.app.treeViewer.setInput(File(dir))
self.app.treeViewer.refresh()
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))
fileMenu.add(OpenDirectoryAction(self.app))
return mainMenu
class MainToolbarManager(ToolBarManager):
""" """
def __init__(self, app):
"""construcotr of MainToolbar
arguments:
app - in order to do anything useful I am passing
object of my application.
"""
# let parent class to do it's stuff first
ToolBarManager.__init__(self)
self.app = app
def createMainToolBar(self, style):
""" add items to toolbar """
mainToolBar = ToolBarManager(style)
# add Exit action to toolbar
mainToolBar.add(ExitAction(self.app))
mainToolBar.add(OpenDirectoryAction(self.app))
return mainToolBar
class FileTreeContentProvider(ITreeContentProvider):
def getChildren(self, element):
if (not element):
return None
kids = element.listFiles()
return kids
def getElements(self, element):
return self.getChildren(element)
def hasChildren(self, element):
if (not element):
return False
kids = self.getChildren(element)
if (not kids):
return False
if (len(kids) < 1):
return False
return True
def getParent(self, element):
return element.getParent()
def dispose(self):
pass
def inputChanged(self, viewer, old_input, new_input):
pass
class FileTreeLabelProvider(LabelProvider):
def getImage(self, element):
if (element.isDirectory()):
return App.getImageRegistry().getDescriptor("file.open").createImage()
return App.getImageRegistry().getDescriptor("file.image").createImage()
def getText(self, element):
return element.getName()
class FileTreeSelectionChangedListener(ISelectionChangedListener):
def __init__(self, app):
self.app = app
def selectionChanged(self, e):
selection = e.getSelection()
file = selection.getFirstElement()
if (file.isDirectory()):
return
self.app.image = Image(Display.getCurrent(), file.getPath())
self.app.setStatus("Open file: " + file.getPath())
self.app.newOrResizeImage()
gc = GC(self.app.canvas)
rect = self.app.canvas.getClientArea()
gc.drawImage(self.app.image, 0, 0)
gc.dispose()
self.app.canvas.redraw()
class App(ApplicationWindow):
""" Main class for JFace application drived from ApplicationWindow class """
# add static image registry
imageRegistry = None
# add class method for image registry
@classmethod
def getImageRegistry(cls):
if (not cls.imageRegistry):
cls.imageRegistry = ImageRegistry()
cls.imageRegistry.put("app.icon", ImageDescriptor.createFromImage(drawIcon(Display.getCurrent())))
# load icon image from file
cls.imageRegistry.put("file.exit", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/system-log-out.png")))
cls.imageRegistry.put("file.open", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/document-open.png")))
cls.imageRegistry.put("file.image", ImageDescriptor.createFromImage(Image(Display.getCurrent(), "img/image-x-generic.png")))
return cls.imageRegistry
def __init__(self, shell):
""" application constructor """
# let parent class to do it's stuff first
ApplicationWindow.__init__(self, shell)
self.canvas = None
self.image = None
self.origin = Point(0, 0)
self.treeViewer = None
# lets add menu
self.addMenuBar()
# lets add toolbar
self.addToolBar(SWT.FLAT | SWT.WRAP)
# lets add status line
self.addStatusLine()
def dispose(self):
""" dispose resources here """
if (self.image != None):
self.image.dispose()
def createContents(self, parent):
"""Creates the main window's contents
parent - the main window
return - control
"""
self.shell.setImage(drawIcon(Display.getCurrent()))
self.shell.text = 'JPictureMaster II (Jython & JFace example)'
# create split form
mainForm = SashForm(parent, SWT.HORIZONTAL | SWT.NULL)
mainForm.setLayout(FillLayout())
# create tree
treePanel = Composite(mainForm, SWT.NONE)
treePanel.setLayout(GridLayout(1, True))
self.treeViewer = TreeViewer(treePanel, SWT.BORDER | SWT.VIRTUAL)
self.treeViewer.getControl().setLayoutData(GridData(SWT.FILL, SWT.FILL, True, True, 3, 3))
self.treeViewer.setContentProvider(FileTreeContentProvider())
self.treeViewer.setLabelProvider(FileTreeLabelProvider())
self.treeViewer.setInput(File("."))
self.treeViewer.addSelectionChangedListener(FileTreeSelectionChangedListener(self))
self.treeViewer.refresh()
imagePanel = Composite(mainForm, SWT.NONE)
# set layout as one column grid
imagePanel.setLayout(GridLayout(1, True))
# create canvas for image displaying
self.canvas = Canvas(imagePanel, SWT.BORDER | SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL)
self.canvas.setLayoutData(GridData(SWT.FILL, SWT.FILL, True, True, 1, 1))
# add listeners to canvas, so we could react to events
self.canvas.getHorizontalBar().addListener(SWT.Selection, HBarListener(self))
self.canvas.getVerticalBar().addListener(SWT.Selection, VBarListener(self))
self.canvas.addListener(SWT.Paint, CanvasPaintListener(self))
self.canvas.addListener(SWT.Resize, CanvasResizeListener(self))
mainForm.setWeights([30, 70])
return mainForm
def createMenuManager(self):
""" create main menu """
return MainMenuManager(self).createMainMenu()
def createToolBarManager(self, style):
""" create main toolbar """
return MainToolbarManager(self).createMainToolBar(style)
def getStatusLineManagerForUpdate(self):
""" get status line manager """
return self.getStatusLineManager()
def newOrResizeImage(self):
if (not self.canvas):
return
client = self.canvas.getClientArea()
if (not self.image):
self.image = Image(self.shell.getDisplay(), client.width, client.height)
gc = GC(self.image)
gc.fillRectangle(0, 0, client.width, client.height)
gc.drawLine (0, 0, client.width, client.height)
gc.drawLine (0, client.height, client.width, 0)
gc.drawText ("No Image", 10, 10)
gc.dispose ()
rect = self.image.getBounds()
self.canvas.getHorizontalBar().setMaximum(rect.width)
self.canvas.getVerticalBar().setMaximum(rect.height)
self.canvas.getHorizontalBar().setThumb(Math.min (rect.width, client.width))
self.canvas.getVerticalBar().setThumb(Math.min (rect.height, client.height))
hPage = rect.width - client.width
vPage = rect.height - client.height
hSelection = self.canvas.getHorizontalBar().getSelection()
vSelection = self.canvas.getVerticalBar().getSelection()
if (hSelection >= hPage):
if (hPage <= 0):
hSelection = 0
self.origin.x = -hSelection
if (vSelection >= vPage):
if (vPage <= 0):
vSelection = 0
self.origin.y = -vSelection
if __name__ == "__main__":
""" The entry point for our application """
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()
0 comments:
Post a Comment