Python Forum

Full Version: moving from tkinter to wxpython
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10
UPDATE:
thinks are a bit slow today. Watching a golf match on the telly.
But almost have dictionary update done (adds audio links to bible JSON file)
final step is to incorporate into your code, getting there.
Don't worry about my time, I wouldn't do it if I wasn't having fun.
I've been at it for 50 years this year (started programming in 1968), and still love it!
Still something wrong with the code of the last module...
It's like the last bolt that needs to be removed when working on a car...
It's almost always the stubborn one.
I have to sleep for a few hours, and then have to go out for a couple before we get yet another 14 inches of snow (this I believe is our
16th storm this winter).
But this makes it almost all the way through before it explodes (ugly with all debug stuff included)
I'll finish it up after I get back from wally mart
import BiblePaths
import json
import re


class UpdateBibleIndexAudioLinks:
    """
    Scans bpath.KingJamesAudiopath for all audio files, and either updates existing
    IndexedBible links or adds one if missing. (Larz60+)
    """
    def __init__(self):
        self.bpath = BiblePaths.BiblePaths()
        self.debug = True

        with self.bpath.IndexedBible.open() as f:
            self.bible_dict = json.load(f)

        self.audio_xref = {}
        self.audio_parent_paths = []
        self.bible_dict_chapters = []

        self.update_links()

    def get_parents(self):
        # Get parent paths
        parents = [dir.name for dir in self.bpath.KingJamesAudiopath.iterdir() if dir.is_dir()]
        parents.sort()
        if self.debug:
            print(f'parents: {parents}')

        return parents

    def get_books(self):
        # get list of IndexBible chapters
        books = list(self.bible_dict['Old Testament'].keys()) + list(self.bible_dict['New Testament'].keys())
        books.sort()
        if self.debug:
            print(f'books: {books}')

        return books

    def get_audio_xref(self, parents, books):
        audio_xref = dict(zip(parents, books))

        with self.bpath.AudioXref.open('w') as f:
            json.dump(audio_xref, f)

        if self.debug:
            print(f'audio_xref: {audio_xref}')

        return audio_xref

    def get_mp3_list(self, audio_path):
        mp3_list = [file.name for file in audio_path.iterdir() if file.is_file() and file.suffix == '.mp3']
        if self.debug:
            print(f'mp3_list: {mp3_list}')
        self.rename_mp3s(mp3_list, audio_path)
        return mp3_list

    def rename_mp3s(self, mp3_list, audio_path):
        # rename audio files eliminate spaces
        for filename in mp3_list:
            if ' ' in filename:
                new1 = filename.replace(' ', '_')
                new_filename = audio_path / new1
                file_path = audio_path / filename
                file_path.rename(new_filename)

    def get_book_key(self, audio_key, audio_xref):
        bible_key = audio_xref[audio_key]
        if bible_key in self.bible_dict['Old Testament']:
            book_key = self.bible_dict['Old Testament'][bible_key]
        else:
            book_key = self.bible_dict['New Testament'][bible_key]

        if  self.debug:
            print(f'book_key: {book_key}')
        return book_key

    def remove_old_mp3_reference(self, book_key):
        try:
            temp = book_key['mp3']
            if self.debug:
                print(f'temp: {temp}')
            del (book_key['mp3'])
        except KeyError:
            pass

    def get_verse(self, audio_file):
        verse = None
        # looking at this too long may cause insanity
        verse = str(int(re.sub('.*?([0-9]*)$', r'\1', audio_file.split('-')[-1].split('.')[0])))
        if self.debug:
            print(f'verse: {verse}')

        return verse

    def update_links(self):
        """
        Get a list of all sub-directories and their contents fromm root of bpath.KingJamesAudiopath
        :return: updates self.audio_paths_dict
        """
        parent_paths = self.get_parents()
        books = self.get_books()
        audio_xref = self.get_audio_xref(parent_paths, books)

        # For loop gets book info
        for audio_key, bible_key in audio_xref.items():
            print(f'audio_key: {audio_key}')
            audio_path = self.bpath.KingJamesAudiopath / audio_key
            mp3_list = self.get_mp3_list(audio_path)

            book_key = self.get_book_key(audio_key, audio_xref)
            self.remove_old_mp3_reference(book_key)

            for audio_file in mp3_list:
                verse = self.get_verse(audio_file)
                verse_key = book_key[verse]
                mp3_path = self.bpath.KingJamesAudiopath / audio_key / audio_file
                mp3path = f'{mp3_path.resolve()}'
                mp3path = mp3path.replace('\\', '/')
                print(f'mp3path: {mp3path}')
                print(mp3_path.resolve())
                verse_key['mp3path'] = mp3path
                print(f'verse_key: {verse_key}')
        
        # don't remove comments until all is working
        # with self.bpath.IndexedBible.open('w') as f:
        #      json.dump(self.bible_dict, f)

if __name__ == '__main__':
    UpdateBibleIndexAudioLinks()
I couldn't sleep until finished, so the module UpdateBibeIndexAudioLinks.py
is finished and updated on github.
Do a complete pull, I updated a couple of other programs.
Final step: incorporation is next.
Question: what is the significance of 67
used to select notebook page number and other things
seen here:
        # Selecting notebook page
        sel = self.nb.SetSelection(67)
        # first item in books
        # For making buttons
        # etc...
Is there a particular reason for this method, or is it because it did the trick?
Here's a sample of what the code looks like, the index page displays, but nothing else working yet:
import BiblePaths
import json
import wx


class BibleNB:
    def __init__(self, parent, id = wx.ID_ANY, title = "Bible for the Blind", xpos=20, ypos=20,
                 width=1200, height=600, style=wx.DEFAULT_FRAME_STYLE):
        self.bpath = BiblePaths.BiblePaths()
        self.app = wx.App()
        self.frame = wx.Frame(None, id=wx.ID_ANY, title=title, pos=(xpos, ypos),
                              size=(width, height), style=style)

        self.app.Bind(wx.EVT_CLOSE, self.OnClose)

        self.app.SetTopWindow(self)

        with self.bpath.IndexedBible.open() as f:
            self.bible = json.load(f)
        self.ot = 'Old Testament'
        self.nt = 'New Testament'
        self.book_list = list(self.bible[self.ot].keys()) + list(self.bible[self.nt].keys())

        self.books = list(self.bible['Old Testament'].keys()) + \
                     list(self.bible['New Testament'].keys())

        # dictionary to hold all notebook pages
        self.pages = {}

        # Button position and dimensions
        self.button_width = 110
        self.button_height = 36

        self.left_x = 5
        self.upper_left_y = 5

        self.x_increment = 150
        self.y_increment = 55

        self.x_max = width

        count = self.get_chapter_count('Old Testament', 'Genesis')
        print(f'Genesis chapters: {count}')

        self.create_application()
        self.frame.Show()
        self.app.MainLoop()

    def create_application(self):
        self.create_notebook()
        self.create_index_page()

    def get_chapter_count(self, volume, book):
        return len(self.bible[volume][book])

    def create_notebook(self):
        self.nb = wx.Notebook(self.frame, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
                              style=0, name=wx.NotebookNameStr)
        self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)

    def set_page(self, event):
        self.nb.SetSelection(self.pages['Index']['panel'])
        event.skip()

    def add_page(self, title):
        self.pages[title] = {}
        self.pages[title]['panel'] = wx.Panel(self.nb, id=wx.ID_ANY, style=wx.CLIP_CHILDREN)
        self.nb.AddPage(self.pages[title]['panel'], text=title)
        return self.pages[title]

    def add_buttons(self, page, title, button_list):
        print(f'button_list: {button_list}')
        xpos = self.left_x
        ypos = self.upper_left_y
        page['buttons'] = {}
        # Button(parent, id=ID_ANY, label="", pos=DefaultPosition,
        #        size=DefaultSize, style=0, validator=DefaultValidator,
        #        name=ButtonNameStr)
        for button_name in button_list:
            page['buttons'][button_name] = wx.Button(page['panel'], id=wx.ID_ANY, label=button_name,
                                                     pos=(xpos, ypos), size=(self.button_width, self.button_height),
                                                     name=f'btn_{button_name}')
            xpos += self.x_increment
            if xpos >= self.x_max:
                ypos += self.y_increment
                xpos = self.left_x

        # self.page['buttons'][button_name].Bind(wx.EVT_BUTTON, self.set_page)


    def create_index_page(self):
        self.index_page = self.add_page('Index')
        self.add_buttons(self.index_page, 'Index', self.book_list)

    def OnPageChanged(self):
        pass

    def OnPageChanging(self):
        pass

    def OnClose(self):
        self.app.Destroy()

if __name__ == '__main__':
    BibleNB(None, width=1200)
Screenshot:
[attachment=382]
(Mar-13-2018, 04:33 AM)Larz60+ Wrote: [ -> ]Question: what is the significance of 67
used to select notebook page number and other things
seen here:
        # Selecting notebook page
        sel = self.nb.SetSelection(67)
        # first item in books
        # For making buttons
        # etc...
Is there a particular reason for this method, or is it because it did the trick?
It did the trick. As this is my first attempt at wxpython I know little about it. This worked so my attitude was why would I search for anything else. If there are a number of ways to do it maybe later as I get more familiar with it I would be in a better position to make the right decision over which to use. This is true of all the code in this project.
Actually your code is pretty good, considering you're new with wxpython. I don't know if you have had a chance to look at what I've done,
but with everything consolidated into the json file, it makes it fit together more easily. If at any point you want me to stop, so you can finish, just say so, I won't be offended.
This is almost totally finished.
what remains to be done:
add volume, book and chapter to self.pages, so that when a chapter is selected,
the keys for fetching the audio file are at your fingertips.
then code for actually playing the audio file
There is already a method that will return a path to the mp3 file:
get_mp3_filepath(self, volume, book, chapter)
here's the code as it stands. I'm taking the rest of the evening off.
You can finish if you like, or wait until my tomorrow. EST time zone
code (not on github yet)
import BiblePaths
import json
import wx


class BibleNB:
    def __init__(self, parent, id = wx.ID_ANY, title = "Bible for the Blind", xpos=20, ypos=20,
                 width=1200, height=600, style=wx.DEFAULT_FRAME_STYLE):
        self.bpath = BiblePaths.BiblePaths()
        self.app = wx.App()
        self.frame = wx.Frame(None, id=wx.ID_ANY, title=title, pos=(xpos, ypos),
                              size=(width, height), style=style)

        self.app.Bind(wx.EVT_CLOSE, self.OnClose)

        self.app.SetTopWindow(self)

        with self.bpath.IndexedBible.open() as f:
            self.bible = json.load(f)

        self.ot = 'Old Testament'
        self.nt = 'New Testament'

        self.book_list = self.get_book_list()

        self.chapter_list = None

        # dictionary to hold all notebook pages
        self.pages = {}
        self.current_page = None

        # Button position and dimensions
        self.button_width = 110
        self.button_height = 36
        self.button_hover_color = '#87ceeb'
        self.button_normal_color = '#f8fcfe'

        self.left_x = 5
        self.upper_left_y = 5

        self.x_increment = 150
        self.y_increment = 55

        self.x_max = width

        self.create_application()
        self.frame.Show()
        self.app.MainLoop()

    def get_book_list(self):
        book_list = []
        for key, value in self.bible.items():
            for key1, value1 in value.items():
                if key == self.ot:
                    book_list.append(['OT', key1])
                else:
                    book_list.append(['NT', key1])
        return book_list

    def create_application(self):
        self.create_notebook()
        self.create_index_page()
        self.create_book_pages()

    def create_notebook(self):
        self.nb = wx.Notebook(self.frame, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
                              style=0, name=wx.NotebookNameStr)
        self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)

    def set_page(self, event):
        self.nb.SetSelection(self.pages['Index']['panel'])
        event.skip()

    def add_page(self, title):
        self.pages[title] = {}
        self.pages[title]['panel'] = wx.Panel(self.nb, id=wx.ID_ANY, style=wx.CLIP_CHILDREN)
        self.nb.AddPage(self.pages[title]['panel'], text=title)
        return self.pages[title]

    def add_buttons(self, page, title, button_list):
        xpos = self.left_x
        ypos = self.upper_left_y
        page['buttons'] = {}
        for btn in button_list:

            if isinstance(btn, list):
                button_name = f'{btn[0]} {btn[1]}'
            else:
                button_name = btn

            bloc = page['buttons'][button_name] = wx.Button(page['panel'], id=wx.ID_ANY, label=button_name,
                                                     pos=(xpos, ypos), size=(self.button_width, self.button_height),
                                                     name=f'btn_{button_name}')
            bloc.name = [button_name, page]
            xpos += self.x_increment
            if xpos >= self.x_max:
                ypos += self.y_increment
                xpos = self.left_x
            bloc.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, bloc)
            bloc.Bind(wx.EVT_LEAVE_WINDOW, self.OnExitWindow, bloc)
            bloc.Bind(wx.EVT_BUTTON, self.OnClick, bloc)

        # self.page['buttons'][button_name].Bind(wx.EVT_BUTTON, self.set_page)

    def OnEnterWindow(self, event):
        namelist = event.GetEventObject().name
        name = namelist[0]
        page = namelist[1]
        page['buttons'][name].SetBackgroundColour(self.button_hover_color)

    def OnExitWindow(self, event):
        namelist = event.GetEventObject().name
        name = namelist[0]
        page = namelist[1]
        page['buttons'][name].SetBackgroundColour(self.button_normal_color)

    def OnClick(self, event):
        namelist = event.GetEventObject().name
        # print(self.pages)
        name = namelist[0]
        page = namelist[1]
        # print(f'name: {name}')

    def get_mp3_filepath(self, volume, book, chapter):
        mp3path = self.bible[volume][book][chapter]['mp3path']
        print(f'mp3path: {mp3path}')
        fullpath = self.bpath.KingJamesAudiopath / mp3path[0] / mp3path[1]
        return fullpath

    def get_chapter_list(self, item):
        if item[0] == 'OT':
            volume = 'Old Testament'
        else:
            volume = 'New Testament'
        chapter_list = []
        for key, value in self.bible[volume][item[1]].items():
            if str(key).startswith('chap'):
                continue
            chapter_list.append(key)
        return chapter_list

    def create_index_page(self):
        self.current_page = self.add_page('Index')
        index_button_labels = []
        for item in self.book_list:
            index_button_labels.append(f'{item[0]}-{item[1]}')
        self.add_buttons(self.current_page, 'Index', index_button_labels)

    def create_book_pages(self):
        for item in self.book_list:
            title = item[1]
            self.current_page = self.add_page(item[1])
            chapter_list = self.get_chapter_list(item)
            self.add_buttons(self.current_page, title, chapter_list)

    def OnPageChanged(self, event):
        pass

    def OnPageChanging(self, event):
        pass

    def OnClose(self):
        self.app.Destroy()

if __name__ == '__main__':
    BibleNB(None, width=1200)
As I am not sure of the syntax for such as
 print(f"Mp3 file for Leviticus is here: {self.BibleIndex['Old Testament']['Leviticus']['mp3']}") 
I decided to install python 3.6.
With Linux Mint at present depending on 3.5 I had to find a way to get 3.6 installed along with it, which I did.
Now I am still trying to figure out how to install wxpython for 3.6.
I have pip 3.6 installed but the wx install still fails. I have posted separately about this.
Of course it means that at the moment I cannot run your code.
what do you use for an ide?
Do you have pip available? if so, pip install wxpython should work.
I have used Linux (and Unix) more over the past 38 years (since Unix was made available by Bell Labs )
but for the past few years have been stuck on windows (My Linux box crashed beyond recovery, and I have not
replaced it yet). I hope wxpython is not a problem on Mint.
the syntax for:
print(f"Mp3 file for Leviticus is here: {self.BibleIndex['Old Testament']['Leviticus']['mp3']}")
f is the f-string, it allows printing with interpretation of any code between '{' and '}'.
The code that is in there: self.BibleIndex['Old Testament']['Leviticus']['mp3']
references the BibleIndex dictionary that was loaded from the json file that I created.
That dictionary has several nested levels, everything between '[' and ']' is a key to the next level.
Here's and example (book of jude which is short in actual portion of json dictionary, modified to make complete dictionary:

Output:
BibleIndex = { "New Testament": { "Jude": { "1": { "chapter_title": "Contending for the Faith", "1": "Jude, the servant of Jesus Christ, and brother of James, to them that are sanctified by God the Father, and preserved in Jesus Christ, [and] called:", "2": "Mercy unto you, and peace, and love, be multiplied.", "3": "Beloved, when I gave all diligence to write unto you of the common salvation, it was needful for me to write unto you, and exhort [you] that ye should earnestly contend for the faith which was once delivered unto the saints.", "4": "For there are certain men crept in unawares, who were before of old ordained to this condemnation, ungodly men, turning the grace of our God into lasciviousness, and denying the only Lord God, and our Lord Jesus Christ.", "5": "I will therefore put you in remembrance, though ye once knew this, how that the Lord, having saved the people out of the land of Egypt, afterward destroyed them that believed not.", "6": "And the angels which kept not their first estate, but left their own habitation, he hath reserved in everlasting chains under darkness unto the judgment of the great day.", "7": "Even as Sodom and Gomorrha, and the cities about them in like manner, giving themselves over to fornication, and going after strange flesh, are set forth for an example, suffering the vengeance of eternal fire.", "8": "Likewise also these [filthy] dreamers defile the flesh, despise dominion, and speak evil of dignities.", "9": "Yet Michael the archangel, when contending with the devil he disputed about the body of Moses, durst not bring against him a railing accusation, but said, The Lord rebuke thee.", "10": "But these speak evil of those things which they know not: but what they know naturally, as brute beasts, in those things they corrupt themselves.", "11": "Woe unto them! for they have gone in the way of Cain, and ran greedily after the error of Balaam for reward, and perished in the gainsaying of Core.", "12": "These are spots in your feasts of charity, when they feast with you, feeding themselves without fear: clouds [they are] without water, carried about of winds; trees whose fruit withereth, without fruit, twice dead, plucked up by the roots;", "13": "Raging waves of the sea, foaming out their own shame; wandering stars, to whom is reserved the blackness of darkness for ever.", "14": "And Enoch also, the seventh from Adam, prophesied of these, saying, Behold, the Lord cometh with ten thousands of his saints,", "15": "To execute judgment upon all, and to convince all that are ungodly among them of all their ungodly deeds which they have ungodly committed, and of all their hard [speeches] which ungodly sinners have spoken against him.", "16": "These are murmurers, complainers, walking after their own lusts; and their mouth speaketh great swelling [words,] having men's persons in admiration because of advantage.", "17": "But, beloved, remember ye the words which were spoken before of the apostles of our Lord Jesus Christ;", "18": "How that they told you there should be mockers in the last time, who should walk after their own ungodly lusts.", "19": "These be they who separate themselves, sensual, having not the Spirit.", "20": "But ye, beloved, building up yourselves on your most holy faith, praying in the Holy Ghost,", "21": "Keep yourselves in the love of God, looking for the mercy of our Lord Jesus Christ unto eternal life.", "22": "And of some have compassion, making a difference:", "23": "And others save with fear, pulling [them] out of the fire; hating even the garment spotted by the flesh.", "24": "Now unto him that is able to keep you from falling, and to present [you] faultless before the presence of his glory with exceeding joy,", "25": "To the only wise God our Saviour, [be] glory and majesty, dominion and power, both now and ever. Amen.", "mp3path": [ "Jude", "65005_0_KJV_Bible-Jude.mp3" ] }, "chapter_title": [ "The General Epistle of Jude" ] } } }
if you cut and paste this into an interactive python session, you can try the following operations:
>>> volume = 'New Testament'
>>> book = 'Jude'
>>> chapter = '1'
>>> verse = '16'
>>> print(BibleIndex[volume][book][chapter][verse])
These are murmurers, complainers, walking after their own lusts; and their mouth speaketh great swelling [words,] having men's persons in admiration because of advantage.
>>> print(BibleIndex[volume][book][chapter]['mp3path'])
['Jude', '65005_0_KJV_Bible-Jude.mp3']
>>> print(BibleIndex[volume][book][chapter]['chapter_title'])
Contending for the Faith
>>>
Hope that helps. This is information is available for the entire bible.
The audio files are located in src/data/KingJames/Audio/ChapterName/ with ChapterName like '1Samuel'
they can be opened (example 65005_0_KJV_Bible-Jude.mp3 form snippet above) with:
mp3file = self.bpath.KingJamesAudiopath / BibleIndex[volume][book][chapter]['chapter_title']
# Or
mp3file = self.bpath.KingJamesAudiopath / BibleIndex['New Testament']['Jude']['16']['mp3path']
# Then open for reading like
with mp3file.open('rb') as f:
    ...
One final note. I'm testing from a new installation, and finding some bugs. I have all but one fixed. I also
added a new program: RunMeOnce.py
which when run on a new install will set up all directories, create the json files, sownload text and audio files,
basically everything.
Even though I said I was going to take the night off, I didn't. It's 7:51 AM here in New England, and we had 2 feet of
snow last night, I am waiting for Mr. Plow, and then sleep for a while. but all will be done today, unless you would like
me to continue with adding the keys to the page dictionary (post 68:)
Quote:add volume, book and chapter to self.pages, so that when a chapter is selected,
the keys for fetching the audio file are at your fingertips.

Let me know.
Pages: 1 2 3 4 5 6 7 8 9 10