Python Forum
moving from tkinter to wxpython - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: Web Scraping & Web Development (https://python-forum.io/forum-13.html)
+--- Thread: moving from tkinter to wxpython (/thread-8405.html)

Pages: 1 2 3 4 5 6 7 8 9 10


RE: moving from tkinter to wxpython - Larz60+ - Feb-26-2018

you can use a notebook which will allow you to have as many pages as you wish.
You can switch from page to page either by clicking, or programmatically force
page change,

Use the demo (https://python-forum.io/Thread-moving-from-tkinter-to-wxpython?pid=40072#pid40072)
look under book controls, and click on Notebook.
Look at the class: TestNB which pretty much lays out what you need to get started.
Also see: https://wxpython.org/Phoenix/docs/html/wx.Notebook.html
which will show:
  • Possible constructors:
    Notebook()
    
    Notebook(parent, id=ID_ANY, pos=DefaultPosition, size=DefaultSize,
             style=0, name=NotebookNameStr)
  • ChangeSelection which will explain how to programmatically change pages
  • InsertPage - allows you to programmatically insert a new page



RE: moving from tkinter to wxpython - Barrowman - Feb-27-2018

Okay so I have had a look at notebook which I initially believed was usable for a few pages.
I have gone a way into using it and have got it developed so far. It's not laid out as I would finally want it. Probably a good bit more to go.
I have been struggling with getting the pages larger until I examined run.py and saw that the size was being set there. Here is my code so far.
#!/usr/bin/env python3
import sys
import wx
import os
import ColorPanel
#import GridSimple
#import ListCtrl
#import ScrolledWindow
#import images
books = ['67','Genesis050', 'Exodus040', 'Leviticus027', 'Numbers036', 'Deuteronomy034', 'Joshua024', 'Judges021', 'Ruth004', '1 Samuel031', '2 Samuel024', '1 Kings022', '2 Kings025', '1 Chronicles029', '2 Chronicles036', 'Ezra010', 'Nehemiah013', 'Esther010', 'Job042', 'Psalms075', 'Psalms150', 'Proverbs031', 'Ecclesiastes012', 'Song of Solomon008', 'Isaiah066', 'Jeremiah052', 'Lamentations005', 'Ezekiel048', 'Daniel012', 'Hosea014', 'Joel003', 'Amos009', 'Obadiah001', 'Jonah004', 'Micah007', 'Nahum003', 'Habakkuk003', 'Zephaniah003', 'Haggai002', 'Zechariah014', 'Malachi004', 'Matthew028', 'Mark016', 'Luke024', 'John021', 'Acts028', 'Romans016', '1 Corinthians016', '2 Corinthians013', 'Galatians006', 'Ephesians006', 'Philippians004', 'Colossians004', '1 Thessalonians005', '2 Thessalonians003', '1 Timothy006', '2 Timothy004', 'Titus003', 'Philemon001', 'Hebrews013', 'James005', '1 Peter005', '2 Peter003', '1 John005', '2 John001', '3 John001', 'Jude001', 'Revelation022']


class TestNB(wx.Notebook):
    def __init__(self, parent, id, log):
        wx.Notebook.__init__(self, parent, id, style=
                             wx.BK_DEFAULT
                             #wx.BK_TOP
                             #wx.BK_BOTTOM
                             #wx.BK_LEFT
                             #wx.BK_RIGHT
                             # | wx.NB_MULTILINE
                             )
        self.log = log

        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
        for pagenum in range(1,68):
            column = 0
            row = 0
            pge = books[pagenum]
            thispage = pge[:-3]
            win = self.makeColorPanel(wx.WHITE)
            win.SetSize(self.GetBestSize())
#            st.SetForegroundColour(wx.BLACK)
            self.AddPage(win, thispage)
#            st.SetBackgroundColour(wx.BLUE)
            numchps = books[pagenum]
            chaps = int(numchps[-3:])
            if(pge == 'Psalms150'):
                for nums in range(76,151):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row ),size=(110, 36 ))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn )
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow,btn )
                    btn.Bind(wx.EVT_BUTTON, self.OnClick,btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55
            else:
                column = 0
                row = 0
                for nums in range(1,chaps+1):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row ),size=(110, 36 ))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn )
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow,btn )
                    btn.Bind(wx.EVT_BUTTON, self.OnClick,btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55
            

    def makeColorPanel(self, color):
        p = wx.Panel(self, -1)
        win = ColorPanel.ColoredPanel(p, color)
        p.win = win
        def OnCPSize(evt, win=win):
            win.SetPosition((0,0))
            win.SetSize(evt.GetSize())  #Best
        p.Bind(wx.EVT_SIZE, OnCPSize)
        return p


    def OnPageChanged(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanged,  old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnPageChanging(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnClick(self, event):
        obj = event.GetEventObject()
        print("You clicked %s"%obj.GetLabel())
        event.Skip()
             
    def OnEnterWindow(self, event):
       obj = event.GetEventObject()
       print("You hovered over %s"%obj.GetLabel())
       cmd = "mpv /home/norman/Blind/genesis.mp3"  #School/Lessons/2tone.mp3 &"
       os.system(cmd)
       event.Skip()  
    def OnExitWindow(self, event):
       obj = event.GetEventObject()
       print("You hovered over %s"%obj.GetLabel())
       cmd = "killall -9 mpv"
       os.system(cmd)


#----------------------------------------------------------------------------

def runTest(frame, nb, log):
    testWin = TestNB(nb, -1, log)
    return testWin

#----------------------------------------------------------------------------


overview = """\
<html><body>
<h2>wx.Notebook</h2>
<p>
This class represents a notebook control, which manages multiple
windows with associated tabs.
<p>
To use the class, create a wx.Notebook object and call AddPage or
InsertPage, passing a window to be used as the page. Do not explicitly
delete the window for a page that is currently managed by wx.Notebook.


"""

if __name__ == '__main__':
    import sys,os
    import run

I had tried a number of ways to set the size within the program. I always get errors due to trying to add
size=(1200,600)
wherever I tried it.
Is it that run.py overrides what I try?
If it is can I remove run.py and then set the size in the program?
Mind you I would then have to figure out how to get it to run without it!


RE: moving from tkinter to wxpython - Larz60+ - Feb-27-2018

You can override a previously set size. I can help with this, give me abit ...
Where does ColorPanel come from? Need it to run.


RE: moving from tkinter to wxpython - Larz60+ - Feb-27-2018

The call to run can be modified:
look at the init:
    def __init__(self, name, module, useShell, title='My title here', xpos=20, ypos=20, width=600,
                 height=338, style=wx.DEFAULT_FRAME_STYLE, winname=wx.FrameNameStr):
if when you call run, you supply width=yourwidth, height=yourheight you can override the defaults
I wrote it this way so you would have control over these.
Any __init__ attribute written with =value is a default and can be overwritten


RE: moving from tkinter to wxpython - Barrowman - Feb-28-2018

Sorry, it was late here when I last posted. Thanks for all your help.
ColorPanel, GridSimple, ListCtrl, ScrolledWindow and images are all in the wxPython-4.0.0b2/demo folder.
I copied them to the folder my program is in.
So I guess they either need copying along with my code or incorporated into it.
It looks like I will use this to learn more about wxpython.


RE: moving from tkinter to wxpython - Larz60+ - Feb-28-2018

Ok, so it's from the demo, I can get that.


RE: moving from tkinter to wxpython - Larz60+ - Feb-28-2018

The document posted is incomplete, can't run.


RE: moving from tkinter to wxpython - Barrowman - Feb-28-2018

Ah yes last line missing
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])



RE: moving from tkinter to wxpython - Larz60+ - Feb-28-2018

OK,
in the last code update for run, I put some of the changes required for modification in but
failed to follow through.
You can now specify title, xpos, ypos, width, height, style, and winname (winname can be used to refer to Frame (by name) see docs).
Look at the last line of your code for an example

new run:
#!/usr/bin/env python
# ----------------------------------------------------------------------------
# Name:         run.py
# Purpose:      Simple framework for running individual demos
#
# Author:       Robin Dunn
# Mod version:  Larz60+ 20 Feb 2018
#
# Created:      6-March-2000
# Copyright:    (c) 2000-2017 by Total Control Software
# Licence:      wxWindows license
# ----------------------------------------------------------------------------

"""
This program will load and run one of the individual demos in this
directory within its own frame window.  Just specify the module name
on the command line.
"""

import wx
import wx.lib.inspection
import wx.lib.mixins.inspection
import sys, os

# stuff for debugging
print("Python %s" % sys.version)
print("wx.version: %s" % wx.version())
##print("pid: %s" % os.getpid()); input("Press Enter...")

assertMode = wx.APP_ASSERT_DIALOG


##assertMode = wx.APP_ASSERT_EXCEPTION


# ----------------------------------------------------------------------------

class Log:
    def WriteText(self, text):
        if text[-1:] == '\n':
            text = text[:-1]
        wx.LogMessage(text)

    write = WriteText


class RunDemoApp(wx.App, wx.lib.mixins.inspection.InspectionMixin):
    def __init__(self, name, module, useShell, title='My title here', xpos=20, ypos=20, width=600,
                 height=338, style=wx.DEFAULT_FRAME_STYLE, winname=wx.FrameNameStr):
        self.title = title
        self.name = name
        self.demoModule = module
        self.useShell = useShell
        self.xpos = xpos
        self.ypos = ypos
        self.width = width
        self.height = height
        self.winname = winname
        self.style = style
        wx.App.__init__(self, redirect=False)

    def OnInit(self):
        wx.Log.SetActiveTarget(wx.LogStderr())

        self.SetAssertMode(assertMode)
        self.InitInspection()  # for the InspectionMixin base class

        frame = wx.Frame(None, id=wx.ID_ANY, title=self.title, pos=(self.xpos, self.ypos),
                         size=(self.width, self.height), style=self.style, name=self.winname)
        frame.CreateStatusBar()

        ns = {}
        ns['wx'] = wx
        ns['app'] = self
        ns['module'] = self.demoModule
        ns['frame'] = frame

        frame.Show(True)
        frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame)

        win = self.demoModule.runTest(frame, frame, Log())

        # a window will be returned if the demo does not create
        # its own top-level window
        if win:
            # so set the frame to a good size for showing stuff
            frame.SetSize((self.width, self.height))
            win.SetFocus()
            self.window = win
            ns['win'] = win
            frect = frame.GetRect()
        else:
            # It was probably a dialog or something that is already
            # gone, so we're done.
            frame.Destroy()
            return True

        self.SetTopWindow(frame)
        self.frame = frame
        # wx.Log.SetActiveTarget(wx.LogStderr())
        # wx.Log.SetTraceMask(wx.TraceMessages)

        if self.useShell:
            # Make a PyShell window, and position it below our test window
            from wx import py
            shell = py.shell.ShellFrame(None, locals=ns)
            frect.OffsetXY(0, frect.height)
            frect.height = 400
            shell.SetRect(frect)
            shell.Show()

            # Hook the close event of the test window so that we close
            # the shell at the same time
            def CloseShell(evt):
                if shell:
                    shell.Close()
                evt.Skip()

            frame.Bind(wx.EVT_CLOSE, CloseShell)

        return True

    def OnExitApp(self, evt):
        self.frame.Close(True)

    def OnCloseFrame(self, evt):
        if hasattr(self, "window") and hasattr(self.window, "ShutdownDemo"):
            self.window.ShutdownDemo()
        evt.Skip()

    def OnWidgetInspector(self, evt):
        wx.lib.inspection.InspectionTool().Show()


# ----------------------------------------------------------------------------


def main(argv, title='My title here', xpos=20, ypos=20, width=600, height=338,
         style=wx.DEFAULT_FRAME_STYLE, winname=wx.FrameNameStr):
    useShell = False
    for x in range(len(sys.argv)):
        if sys.argv[x] in ['--shell', '-shell', '-s']:
            useShell = True
            del sys.argv[x]
            break

    if len(argv) < 2:
        print("Please specify a demo module name on the command-line")
        raise SystemExit

    # ensure the CWD is the demo folder
    demoFolder = os.path.realpath(os.path.dirname(__file__))
    os.chdir(demoFolder)

    sys.path.insert(0, os.path.join(demoFolder, 'agw'))
    sys.path.insert(0, '.')

    name, ext = os.path.splitext(argv[1])
    module = __import__(name)

    # optional parameters:
    # title='your title here'
    # xpos=starting xpos
    # ypos=starting ypos
    # width=window width in pixels
    # height=window height in pixels
    # style=wx window style -- see Window Styles: https://docs.wxpython.org/wx.Frame.html
    # name=windows name
    app = RunDemoApp(name=name, module=module, title=title, useShell=useShell,
                     xpos=xpos, ypos=ypos, width=width, height=height,
                     style=style, winname=winname)
    app.MainLoop()


if __name__ == "__main__":
    main(sys.argv)
your code with example usage:
#!/usr/bin/env python3
# post: https://python-forum.io/Thread-moving-from-tkinter-to-wxpython?page=3
import sys
import wx
import os
import ColorPanel

# import GridSimple
# import ListCtrl
# import ScrolledWindow
# import images
books = ['67', 'Genesis050', 'Exodus040', 'Leviticus027', 'Numbers036', 'Deuteronomy034', 'Joshua024', 'Judges021',
         'Ruth004', '1 Samuel031', '2 Samuel024', '1 Kings022', '2 Kings025', '1 Chronicles029', '2 Chronicles036',
         'Ezra010', 'Nehemiah013', 'Esther010', 'Job042', 'Psalms075', 'Psalms150', 'Proverbs031', 'Ecclesiastes012',
         'Song of Solomon008', 'Isaiah066', 'Jeremiah052', 'Lamentations005', 'Ezekiel048', 'Daniel012', 'Hosea014',
         'Joel003', 'Amos009', 'Obadiah001', 'Jonah004', 'Micah007', 'Nahum003', 'Habakkuk003', 'Zephaniah003',
         'Haggai002', 'Zechariah014', 'Malachi004', 'Matthew028', 'Mark016', 'Luke024', 'John021', 'Acts028',
         'Romans016', '1 Corinthians016', '2 Corinthians013', 'Galatians006', 'Ephesians006', 'Philippians004',
         'Colossians004', '1 Thessalonians005', '2 Thessalonians003', '1 Timothy006', '2 Timothy004', 'Titus003',
         'Philemon001', 'Hebrews013', 'James005', '1 Peter005', '2 Peter003', '1 John005', '2 John001', '3 John001',
         'Jude001', 'Revelation022']


class TestNB(wx.Notebook):
    def __init__(self, parent, id, log):
        wx.Notebook.__init__(self, parent, id, style=
        wx.BK_DEFAULT
                             # wx.BK_TOP
                             # wx.BK_BOTTOM
                             # wx.BK_LEFT
                             # wx.BK_RIGHT
                             # | wx.NB_MULTILINE
                             )
        self.log = log

        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
        for pagenum in range(1, 68):
            column = 0
            row = 0
            pge = books[pagenum]
            thispage = pge[:-3]
            win = self.makeColorPanel(wx.WHITE)
            win.SetSize(self.GetBestSize())
            #            st.SetForegroundColour(wx.BLACK)
            self.AddPage(win, thispage)
            #            st.SetBackgroundColour(wx.BLUE)
            numchps = books[pagenum]
            chaps = int(numchps[-3:])
            if (pge == 'Psalms150'):
                for nums in range(76, 151):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row), size=(110, 36))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, btn)
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow, btn)
                    btn.Bind(wx.EVT_BUTTON, self.OnClick, btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55
            else:
                column = 0
                row = 0
                for nums in range(1, chaps + 1):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row), size=(110, 36))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, btn)
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow, btn)
                    btn.Bind(wx.EVT_BUTTON, self.OnClick, btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55

    def makeColorPanel(self, color):
        p = wx.Panel(self, -1)
        win = ColorPanel.ColoredPanel(p, color)
        p.win = win

        def OnCPSize(evt, win=win):
            win.SetPosition((0, 0))
            win.SetSize(evt.GetSize())  # Best

        p.Bind(wx.EVT_SIZE, OnCPSize)
        return p

    def OnPageChanged(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanged,  old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnPageChanging(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnClick(self, event):
        obj = event.GetEventObject()
        print("You clicked %s" % obj.GetLabel())
        event.Skip()

    def OnEnterWindow(self, event):
        obj = event.GetEventObject()
        print("You hovered over %s" % obj.GetLabel())
        cmd = "mpv /home/norman/Blind/genesis.mp3"  # School/Lessons/2tone.mp3 &"
        os.system(cmd)
        event.Skip()

    def OnExitWindow(self, event):
        obj = event.GetEventObject()
        print("You hovered over %s" % obj.GetLabel())
        cmd = "killall -9 mpv"
        os.system(cmd)


# ----------------------------------------------------------------------------

def runTest(frame, nb, log):
    testWin = TestNB(nb, -1, log)
    return testWin


# ----------------------------------------------------------------------------


overview = """\
<html><body>
<h2>wx.Notebook</h2>
<p>
This class represents a notebook control, which manages multiple
windows with associated tabs.
<p>
To use the class, create a wx.Notebook object and call AddPage or
InsertPage, passing a window to be used as the page. Do not explicitly
delete the window for a page that is currently managed by wx.Notebook.


"""

if __name__ == '__main__':
    import sys, os
    import run
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:], title='Bible For The Blind',
             width=1000, height=600)



RE: moving from tkinter to wxpython - Larz60+ - Mar-01-2018

The run.py program will still be useful if you need to run a demo by itself, without the full phoenix
overhead. But you shouldn't have to carry that around with your application.
Here's a modified version of your code, which allows that:
#!/usr/bin/env python3
import sys
import wx
import os

books = ['67', 'Genesis050', 'Exodus040', 'Leviticus027', 'Numbers036', 'Deuteronomy034', 'Joshua024', 'Judges021',
         'Ruth004', '1 Samuel031', '2 Samuel024', '1 Kings022', '2 Kings025', '1 Chronicles029', '2 Chronicles036',
         'Ezra010', 'Nehemiah013', 'Esther010', 'Job042', 'Psalms075', 'Psalms150', 'Proverbs031', 'Ecclesiastes012',
         'Song of Solomon008', 'Isaiah066', 'Jeremiah052', 'Lamentations005', 'Ezekiel048', 'Daniel012', 'Hosea014',
         'Joel003', 'Amos009', 'Obadiah001', 'Jonah004', 'Micah007', 'Nahum003', 'Habakkuk003', 'Zephaniah003',
         'Haggai002', 'Zechariah014', 'Malachi004', 'Matthew028', 'Mark016', 'Luke024', 'John021', 'Acts028',
         'Romans016', '1 Corinthians016', '2 Corinthians013', 'Galatians006', 'Ephesians006', 'Philippians004',
         'Colossians004', '1 Thessalonians005', '2 Thessalonians003', '1 Timothy006', '2 Timothy004', 'Titus003',
         'Philemon001', 'Hebrews013', 'James005', '1 Peter005', '2 Peter003', '1 John005', '2 John001', '3 John001',
         'Jude001', 'Revelation022']

class Log:
    def WriteText(self, text):
        if text[-1:] == '\n':
            text = text[:-1]
        wx.LogMessage(text)

    write = WriteText

class BibleNB(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="Bible For The Blind", xpos=20, ypos=20, width=600,
                 height=338, style=wx.DEFAULT_FRAME_STYLE, name='BibleApp'):
        # ideal width x height ratio: 16:9
        app = wx.App()
        wx.Frame.__init__(self, parent, id=id, title=title, pos=(xpos, ypos), size=(width, height), style=style)
        app.SetTopWindow(self)
        self.create_notebook()
        app.MainLoop()

    def create_notebook(self):
        wx.Log.SetActiveTarget(wx.LogStderr())
        log = Log()
        # for size use 16:9 ratio for best appearence
        yfactor = 16/9
        width = 1000
        height = int(width / yfactor)
        self.frame =  wx.Frame(self,
                               id=wx.ID_ANY,
                               title='Bible For The Blind',
                               pos=(20, 20),
                               size=(width, height),
                               style=wx.DEFAULT_FRAME_STYLE,
                               name=wx.FrameNameStr)

        self.nb = wx.Notebook(self.frame, id=wx.ID_ANY, style=wx.BK_DEFAULT)
        self.log = log

        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
        for pagenum in range(1, 68):
            column = 0
            row = 0
            pge = books[pagenum]
            thispage = pge[:-3]
            win = wx.Panel(self.nb, -1, style=wx.CLIP_CHILDREN)
            # win = self.makeColorPanel(wx.WHITE)
            win.SetSize(self.GetBestSize())
            # st.SetForegroundColour(wx.BLACK)
            # self.nb.AddPage(win, thispage)
            self.nb.AddPage(win, thispage)
            numchps = books[pagenum]
            chaps = int(numchps[-3:])
            if (pge == 'Psalms150'):
                for nums in range(76, 151):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row), size=(110, 36))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, btn)
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow, btn)
                    btn.Bind(wx.EVT_BUTTON, self.OnClick, btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55
            else:
                column = 0
                row = 0
                for nums in range(1, chaps + 1):
                    btn = 'butt' + str(nums)
                    btn = wx.Button(win, -1, str(nums), pos=(column, row), size=(110, 36))
                    btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, btn)
                    btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow, btn)
                    btn.Bind(wx.EVT_BUTTON, self.OnClick, btn)
                    column += 150
                    if column == 1200:
                        column = 0
                        row += 55
        self.frame.Show()

    def OnPageChanged(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanged,  old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnPageChanging(self, event):
        if self:
            old = event.GetOldSelection()
            new = event.GetSelection()
            sel = self.GetSelection()
            self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel))
        event.Skip()

    def OnClick(self, event):
        obj = event.GetEventObject()
        print("You clicked %s" % obj.GetLabel())
        event.Skip()

    def OnEnterWindow(self, event):
        obj = event.GetEventObject()
        print("You hovered over %s" % obj.GetLabel())
        cmd = "mpv /home/norman/Blind/genesis.mp3"  # School/Lessons/2tone.mp3 &"
        os.system(cmd)
        event.Skip()

    def OnExitWindow(self, event):
        obj = event.GetEventObject()
        print("You hovered over %s" % obj.GetLabel())
        cmd = "killall -9 mpv"
        os.system(cmd)

if __name__ == '__main__':
    BibleNB(None)