win32gui_dialog.py :  » Windows » pyExcelerator » pywin32-214 » win32 » Demos » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Windows » pyExcelerator 
pyExcelerator » pywin32 214 » win32 » Demos » win32gui_dialog.py
# A demo of a fairly complex dialog.
#
# Features:
# * Uses a "dynamic dialog resource" to build the dialog.
# * Uses a ListView control.
# * Dynamically resizes content.
# * Uses a second worker thread to fill the list.
# * Demostrates support for windows XP themes.

# If you are on Windows XP, and specify a '--noxp' argument, you will see:
# * alpha-blend issues with icons
# * The buttons are "old" style, rather than based on the XP theme.
# Hence, using:
#   import winxpgui as win32gui
# is recommened.
# Please report any problems.
import sys
if "--noxp" in sys.argv:
    import win32gui
else:
    import winxpgui as win32gui
import win32api
import win32con, winerror
import struct, array
import commctrl
import Queue
import os

IDC_SEARCHTEXT = 1024
IDC_BUTTON_SEARCH = 1025
IDC_BUTTON_DISPLAY = 1026
IDC_LISTBOX = 1027

WM_SEARCH_RESULT = win32con.WM_USER + 512
WM_SEARCH_FINISHED = win32con.WM_USER + 513

class _WIN32MASKEDSTRUCT:
    def __init__(self, **kw):
        full_fmt = ""
        for name, fmt, default, mask in self._struct_items_:
            self.__dict__[name] = None
            if fmt == "z":
                full_fmt += "pi"
            else:
                full_fmt += fmt
        for name, val in kw.iteritems():
            if name not in self.__dict__:
                raise ValueError("LVITEM structures do not have an item '%s'" % (name,))
            self.__dict__[name] = val

    def __setattr__(self, attr, val):
        if not attr.startswith("_") and attr not in self.__dict__:
            raise AttributeError(attr)
        self.__dict__[attr] = val

    def toparam(self):
        self._buffs = []
        full_fmt = ""
        vals = []
        mask = 0
        # calc the mask
        for name, fmt, default, this_mask in self._struct_items_:
            if this_mask is not None and self.__dict__.get(name) is not None:
                mask |= this_mask
        self.mask = mask
        for name, fmt, default, this_mask in self._struct_items_:
            val = self.__dict__[name]
            if fmt == "z":
                fmt = "Pi"
                if val is None:
                    vals.append(0)
                    vals.append(0)
                else:
                    # Note this demo still works with byte strings.  An
                    # alternate strategy would be to use unicode natively
                    # and use the 'W' version of the messages - eg,
                    # LVM_SETITEMW etc.
                    val = val + "\0"
                    if isinstance(val, unicode):
                        val = val.encode("mbcs")
                    str_buf = array.array("b", val)
                    vals.append(str_buf.buffer_info()[0])
                    vals.append(len(val))
                    self._buffs.append(str_buf) # keep alive during the call.
            else:
                if val is None:
                    val = default
                vals.append(val)
            full_fmt += fmt
        return struct.pack(*(full_fmt,) + tuple(vals))


# NOTE: See the win32gui_struct module for an alternative way of dealing 
# with these structures
class LVITEM(_WIN32MASKEDSTRUCT):
    _struct_items_ = [
        ("mask", "I", 0, None),
        ("iItem", "i", 0, None),
        ("iSubItem", "i", 0, None),
        ("state", "I", 0, commctrl.LVIF_STATE),
        ("stateMask", "I", 0, None),
        ("text", "z", None, commctrl.LVIF_TEXT),
        ("iImage", "i", 0, commctrl.LVIF_IMAGE),
        ("lParam", "i", 0, commctrl.LVIF_PARAM),
        ("iIdent", "i", 0, None),
    ]

class LVCOLUMN(_WIN32MASKEDSTRUCT):
    _struct_items_ = [
        ("mask", "I", 0, None),
        ("fmt", "i", 0, commctrl.LVCF_FMT),
        ("cx", "i", 0, commctrl.LVCF_WIDTH),
        ("text", "z", None, commctrl.LVCF_TEXT),
        ("iSubItem", "i", 0, commctrl.LVCF_SUBITEM),
        ("iImage", "i", 0, commctrl.LVCF_IMAGE),
        ("iOrder", "i", 0, commctrl.LVCF_ORDER),
    ]

class DemoWindowBase:
    def __init__(self):
        win32gui.InitCommonControls()
        self.hinst = win32gui.dllhandle
        self.list_data = {}

    def _RegisterWndClass(self):
        className = "PythonDocSearch"
        message_map = {}
        wc = win32gui.WNDCLASS()
        wc.SetDialogProc() # Make it a dialog class.
        wc.hInstance = self.hinst
        wc.lpszClassName = className
        wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW
        wc.hCursor = win32gui.LoadCursor( 0, win32con.IDC_ARROW )
        wc.hbrBackground = win32con.COLOR_WINDOW + 1
        wc.lpfnWndProc = message_map # could also specify a wndproc.
        # C code: wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(HBRUSH) + (sizeof(COLORREF));
        wc.cbWndExtra = win32con.DLGWINDOWEXTRA + struct.calcsize("Pi")
        icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE

        ## py.ico went away in python 2.5, load from executable instead
        this_app=win32api.GetModuleHandle(None)
        try:
            wc.hIcon=win32gui.LoadIcon(this_app, 1)    ## python.exe and pythonw.exe
        except win32gui.error:
            wc.hIcon=win32gui.LoadIcon(this_app, 135)  ## pythonwin's icon
        try:
            classAtom = win32gui.RegisterClass(wc)
        except win32gui.error, err_info:
            if err_info.winerror!=winerror.ERROR_CLASS_ALREADY_EXISTS:
                raise
        return className

    def _GetDialogTemplate(self, dlgClassName):
        style = win32con.WS_THICKFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT | win32con.WS_MINIMIZEBOX
        cs = win32con.WS_CHILD | win32con.WS_VISIBLE
        title = "Dynamic Dialog Demo"

        # Window frame and title
        dlg = [ [title, (0, 0, 210, 250), style, None, (8, "MS Sans Serif"), None, dlgClassName], ]

        # ID label and text box
        dlg.append([130, "Enter something", -1, (5, 5, 200, 9), cs | win32con.SS_LEFT])
        s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
        dlg.append(['EDIT', None, IDC_SEARCHTEXT, (5, 15, 200, 12), s])

        # Search/Display Buttons
        # (x positions don't matter here)
        s = cs | win32con.WS_TABSTOP
        dlg.append([128, "Fill List", IDC_BUTTON_SEARCH, (5, 35, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
        s = win32con.BS_PUSHBUTTON | s
        dlg.append([128, "Display", IDC_BUTTON_DISPLAY, (100, 35, 50, 14), s])

        # List control.
        # Can't make this work :(
##        s = cs | win32con.WS_TABSTOP
##        dlg.append(['SysListView32', "Title", IDC_LISTBOX, (5, 505, 200, 200), s])

        return dlg

    def _DoCreate(self, fn):
        message_map = {
            win32con.WM_SIZE: self.OnSize,
            win32con.WM_COMMAND: self.OnCommand,
            win32con.WM_NOTIFY: self.OnNotify,
            win32con.WM_INITDIALOG: self.OnInitDialog,
            win32con.WM_CLOSE: self.OnClose,
            win32con.WM_DESTROY: self.OnDestroy,
            WM_SEARCH_RESULT: self.OnSearchResult,
            WM_SEARCH_FINISHED: self.OnSearchFinished,
        }
        dlgClassName = self._RegisterWndClass()
        template = self._GetDialogTemplate(dlgClassName)
        return fn(self.hinst, template, 0, message_map)

    def _SetupList(self):
        child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.WS_HSCROLL | win32con.WS_VSCROLL
        child_style |= commctrl.LVS_SINGLESEL | commctrl.LVS_SHOWSELALWAYS | commctrl.LVS_REPORT
        self.hwndList = win32gui.CreateWindow("SysListView32", None, child_style, 0, 0, 100, 100, self.hwnd, IDC_LISTBOX, self.hinst, None)

        child_ex_style = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
        child_ex_style |= commctrl.LVS_EX_FULLROWSELECT
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, child_ex_style)

        # Add an image list - use the builtin shell folder icon - this
        # demonstrates the problem with alpha-blending of icons on XP if
        # winxpgui is not used in place of win32gui.
        il = win32gui.ImageList_Create(
                    win32api.GetSystemMetrics(win32con.SM_CXSMICON),
                    win32api.GetSystemMetrics(win32con.SM_CYSMICON),
                    commctrl.ILC_COLOR32 | commctrl.ILC_MASK,
                    1, # initial size
                    0) # cGrow

        shell_dll = os.path.join(win32api.GetSystemDirectory(), "shell32.dll")
        large, small = win32gui.ExtractIconEx(shell_dll, 4, 1)
        win32gui.ImageList_ReplaceIcon(il, -1, small[0])
        win32gui.DestroyIcon(small[0])
        win32gui.DestroyIcon(large[0])
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETIMAGELIST,
                             commctrl.LVSIL_SMALL, il)

        # Setup the list control columns.
        lvc = LVCOLUMN(mask = commctrl.LVCF_FMT | commctrl.LVCF_WIDTH | commctrl.LVCF_TEXT | commctrl.LVCF_SUBITEM)
        lvc.fmt = commctrl.LVCFMT_LEFT
        lvc.iSubItem = 1
        lvc.text = "Title"
        lvc.cx = 200
        win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTCOLUMN, 0, lvc.toparam())
        lvc.iSubItem = 0
        lvc.text = "Order"
        lvc.cx = 50
        win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTCOLUMN, 0, lvc.toparam())

        win32gui.UpdateWindow(self.hwnd)

    def ClearListItems(self):
        win32gui.SendMessage(self.hwndList, commctrl.LVM_DELETEALLITEMS)
        self.list_data = {}

    def AddListItem(self, data, *columns):
        num_items = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETITEMCOUNT)
        item = LVITEM(text=columns[0], iItem = num_items)
        new_index = win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTITEM, 0, item.toparam())
        col_no = 1
        for col in columns[1:]:
            item = LVITEM(text=col, iItem = new_index, iSubItem = col_no)
            win32gui.SendMessage(self.hwndList, commctrl.LVM_SETITEM, 0, item.toparam())
            col_no += 1
        self.list_data[new_index] = data

    def OnInitDialog(self, hwnd, msg, wparam, lparam):
        self.hwnd = hwnd
        # centre the dialog
        desktop = win32gui.GetDesktopWindow()
        l,t,r,b = win32gui.GetWindowRect(self.hwnd)
        dt_l, dt_t, dt_r, dt_b = win32gui.GetWindowRect(desktop)
        centre_x, centre_y = win32gui.ClientToScreen( desktop, ( (dt_r-dt_l)//2, (dt_b-dt_t)//2) )
        win32gui.MoveWindow(hwnd, centre_x-(r//2), centre_y-(b//2), r-l, b-t, 0)
        self._SetupList()
        l,t,r,b = win32gui.GetClientRect(self.hwnd)
        self._DoSize(r-l,b-t, 1)

    def _DoSize(self, cx, cy, repaint = 1):
        # right-justify the textbox.
        ctrl = win32gui.GetDlgItem(self.hwnd, IDC_SEARCHTEXT)
        l, t, r, b = win32gui.GetWindowRect(ctrl)
        l, t = win32gui.ScreenToClient(self.hwnd, (l,t) )
        r, b = win32gui.ScreenToClient(self.hwnd, (r,b) )
        win32gui.MoveWindow(ctrl, l, t, cx-l-5, b-t, repaint)
        # The button.
        ctrl = win32gui.GetDlgItem(self.hwnd, IDC_BUTTON_DISPLAY)
        l, t, r, b = win32gui.GetWindowRect(ctrl)
        l, t = win32gui.ScreenToClient(self.hwnd, (l,t) )
        r, b = win32gui.ScreenToClient(self.hwnd, (r,b) )
        list_y = b + 10
        w = r - l
        win32gui.MoveWindow(ctrl, cx - 5 - w, t, w, b-t, repaint)

        # The list control
        win32gui.MoveWindow(self.hwndList, 0, list_y, cx, cy-list_y, repaint)
        # The last column of the list control.
        new_width = cx - win32gui.SendMessage(self.hwndList, commctrl.LVM_GETCOLUMNWIDTH, 0)
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETCOLUMNWIDTH, 1, new_width)

    def OnSize(self, hwnd, msg, wparam, lparam):
        x = win32api.LOWORD(lparam)
        y = win32api.HIWORD(lparam)
        self._DoSize(x,y)
        return 1

    def OnSearchResult(self, hwnd, msg, wparam, lparam):
        try:
            while 1:
                params = self.result_queue.get(0)
                self.AddListItem(*params)
        except Queue.Empty:
            pass

    def OnSearchFinished(self, hwnd, msg, wparam, lparam):
        print "OnSearchFinished"

    def OnNotify(self, hwnd, msg, wparam, lparam):
        format = "PPiiiiiiiiP"
        buf = win32gui.PyMakeBuffer(struct.calcsize(format), lparam)
        hwndFrom, idFrom, code, iItem, iSubItem, uNewState, uOldState, uChanged, actionx, actiony, lParam \
                  = struct.unpack(format, buf)
        if code == commctrl.NM_DBLCLK:
            print "Double click on item", iItem+1
        return 1

    def OnCommand(self, hwnd, msg, wparam, lparam):
        id = win32api.LOWORD(wparam)
        if id == IDC_BUTTON_SEARCH:
            self.ClearListItems()
            def fill_slowly(q, hwnd):
                import time
                for i in range(20):
                    q.put(("whatever", str(i+1), "Search result " + str(i) ))
                    win32gui.PostMessage(hwnd, WM_SEARCH_RESULT, 0, 0)
                    time.sleep(.25)
                win32gui.PostMessage(hwnd, WM_SEARCH_FINISHED, 0, 0)

            import threading
            self.result_queue = Queue.Queue()
            thread = threading.Thread(target = fill_slowly, args=(self.result_queue, self.hwnd) )
            thread.start()
        elif id == IDC_BUTTON_DISPLAY:
            print "Display button selected"
            sel = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETNEXTITEM, -1, commctrl.LVNI_SELECTED)
            print "The selected item is", sel+1

    # These function differ based on how the window is used, so may be overridden
    def OnClose(self, hwnd, msg, wparam, lparam):
        raise NotImplementedError

    def OnDestroy(self, hwnd, msg, wparam, lparam):
        pass

# An implementation suitable for use with the Win32 Window functions (ie, not
# a true dialog)
class DemoWindow(DemoWindowBase):
    def CreateWindow(self):
        # Create the window via CreateDialogBoxIndirect - it can then
        # work as a "normal" window, once a message loop is established.
        self._DoCreate(win32gui.CreateDialogIndirect)

    def OnClose(self, hwnd, msg, wparam, lparam):
        win32gui.DestroyWindow(hwnd)

    # We need to arrange to a WM_QUIT message to be sent to our
    # PumpMessages() loop.
    def OnDestroy(self, hwnd, msg, wparam, lparam):
        win32gui.PostQuitMessage(0) # Terminate the app.

# An implementation suitable for use with the Win32 Dialog functions.
class DemoDialog(DemoWindowBase):
    def DoModal(self):
        return self._DoCreate(win32gui.DialogBoxIndirect)

    def OnClose(self, hwnd, msg, wparam, lparam):
        win32gui.EndDialog(hwnd, 0)

def DemoModal():
    w=DemoDialog()
    w.DoModal()

def DemoCreateWindow():
    w=DemoWindow()
    w.CreateWindow()
    # PumpMessages runs until PostQuitMessage() is called by someone.
    win32gui.PumpMessages()
    
if __name__=='__main__':
    DemoModal()
    DemoCreateWindow()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.