[Tutor] Python WX module program issues.

mhysnm1964 at gmail.com mhysnm1964 at gmail.com
Thu Mar 23 05:14:47 EDT 2023


All,

 

I have created a simple Python 3.10 app using WX module. There is a main
frame and two horizontal panels. Panel1 has an edit object in it. Panel2 has
a list box. The issues I cannot resolve:
1. I cannot add any new content to the status bar from the class EditPanel. 

2. The RecordListPanel does not show any content and the database is
populated.

3.  F6 is meant to switch between the two panels and set the keyboard focus
to the next panel.

 

There is some issues with the saveDb method in the EditPanel Class which I
am still working on. If record key publisher has no values, it receives
"None". The Publisher table has unique records set to prevent duplication.
The same applies to authors, genre, narrator.

 

Can someone look at this code an let me know why point 1 to 3 isn't working?

 

 

import wx, os, codecs, chardet

from books_db import Book, Author, Narrator, Series, Publisher, Genre,
Session

from sqlalchemy.exc import IntegrityError

 

from books_db import Book, Author, Narrator, Series, Publisher, Genre,
Session

 

class RecordListPanel(wx.Panel):

    def __init__(self, parent):

        wx.Panel.__init__(self, parent=parent)

 

        self.list_ctrl = wx.ListCtrl(self, style=wx.LC_REPORT)

        self.list_ctrl.InsertColumn(0, 'Title', width=200)

        self.list_ctrl.InsertColumn(1, 'Author', width=200)

        self.list_ctrl.InsertColumn(2, 'Genre', width=200)

        self.list_ctrl.InsertColumn(3, 'Narrator', width=200)

        self.list_ctrl.InsertColumn(4, 'Publisher', width=200)

        self.list_ctrl.InsertColumn(5, 'Series', width=200)

        self.list_ctrl.InsertColumn(6, 'Series No.', width=100)

        self.populate_list_ctrl()

        #sizer = wx.BoxSizer(wx.VERTICAL)

        #sizer.Add(self.list_ctrl, 1, wx.EXPAND)

        #self.SetSizer(sizer)

 

    def populate_list_ctrl(self):

        session = Session()

        books = session.query(Book).all()

 

        for book in books:

            row = [book.title]

 

            # authors

            authors = ', '.join([author.author for author in book.authors])

            row.append(authors)

 

            # genres

            genres = ', '.join([genre.genre for genre in book.genres])

            row.append(genres)

 

           # narrators

            narrators = ', '.join([narrator.narrator for narrator in
book.narrators])

            row.append(narrators)

 

            row.append(book.publisher.publisher)

            row.append(book.series.series)

            row.append(str(book.series_no))

 

            self.list_ctrl.Append(row)

        session.close()

 

class EditPanel(wx.Panel):

    def __init__(self, parent):

        wx.Panel.__init__(self, parent=parent)

 

        # Initialize variables

        self.books = []

        self.current_book_index = 0

        self.record = {}

 

        # Create controls

        self.edit = wx.TextCtrl(self,
style=wx.TE_MULTILINE|wx.SUNKEN_BORDER)

        # Load the books

        self.load_books_paths()

        # Load the first book into the edit field

        self.load_book()

 

        #sizer = wx.BoxSizer(wx.VERTICAL)

        #sizer.Add(self.edit, 1, wx.EXPAND)

        #self.SetSizer(sizer)

 

    def load_books_paths(self):

        for root, dirs, files in os.walk("c:\\books"):

            for filename in files:

                if filename.endswith(".txt"):

                    filepath = os.path.join(root, filename)

                    self.books.append(filepath)

        print("loaded file paths ")

 

    def load_book(self):

        # Get the current book file path

        current_book = self.books[self.current_book_index]

        self.record['path'] = current_book

        with open(current_book, 'rb') as f:

            contents = f.read()

        encoding = chardet.detect(contents)['encoding']

 

        try:

            with codecs.open(current_book, "r", encoding=encoding) as f:

                contents = f.read()

        except UnicodeDecodeError:

            content = "Unknown file type for " + current_book

 

        # Load the contents of the file into the text box

        self.edit.SetValue(contents)

 

    def priorBook(self, event):

        self.record.clear() # initialize record.

        # Move to the prior  book and load it

        self.current_book_index -= 1

        if self.current_book_index < 0: # cannot pass 0.

            dlg = wx.MessageDialog(self, "Beginning of book path",
caption="Record Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)

            dlg.ShowModal()

            return 

        self.load_book()

        prior_file = self.books[self.current_book_index]

        self.GetTopWindow().SetStatusText(f"Prior    file: {prior_file}")

 

    def nextBook(self, event=None):

        self.record.clear() # initialize record.

        # Move to the next book and load it

        self.current_book_index += 1

        if self.current_book_index >= len(self.books):

            dlg = wx.MessageDialog(self, "end  of book path",
caption="Record Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)

            dlg.ShowModal()

            return 

        self.load_book()

        # Update status bar with path of next file

        next_file = self.books[self.current_book_index]

        self.GetTopWindow().SetStatusText(f"Next file: {next_file}")

 

    def titleSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['title'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"title: {selected_text}")

 

    def authorSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'author' not in self.record:

            self.record['author'] = []

        self.record['author'].append(selected_text.strip())

        self.GetTopWindow().SetStatusText(f"Author: {selected_text}")

 

    def aboutAuthorSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'about_author' not in self.record:

            self.record['about_author'] = selected_text.strip()

        else:

            self.record['about_author'] = self.record['about_author'] + '\n'
+ selected_text.strip()

        self.GetTopWindow().SetStatusText("About Author saved")

 

    def descriptionSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'description' not in self.record:

            self.record['description'] = selected_text.strip()

        else:

            self.record['description'] = self.record['description'] + "\n" +
selected_text.strip()

        self.GetTopWindow().SetStatusText("Description saved")

 

    def seriesSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['series'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"Series: {selected_text}")

 

    def seriesNoSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['series_no'] = int(selected_text.strip())

        self.GetTopWindow().SetStatusText(f"Series Number: {selected_text}")

 

    def narratorSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'narrator' not in self.record:

            self.record['narrator'] = []

        self.record['narrator'].append(selected_text.strip())

        self.GetTopWindow().SetStatusText(f"Narrator: {selected_text}")

 

    def miscSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'misc' not in self.record:

            self.record['misc'] = selected_text.strip()

        else:

            self.record['misc'] = self.record['misc'] + "\n" +
selected_text.strip()

        self.GetTopWindow().SetStatusText("Misc saved")

 

    def genreSave(self, event):

        selected_text = self.edit.GetStringSelection()

        if 'genre' not in self.record:

            self.record['genre'] = []

        self.record['genre'].append(selected_text.strip())

        self.GetTopWindow().SetStatusText(f"Genre: {selected_text}")

 

    def publisherSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['publisher'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"Publisher: {selected_text}")

 

    def durationSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['duration'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"Duration saved:
{selected_text}")

 

    def releaseSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['release'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"Release: {selected_text}")

 

    def copyrightSave(self, event):

        selected_text = self.edit.GetStringSelection()

        self.record['copyright'] = selected_text.strip()

        self.GetTopWindow().SetStatusText(f"Copyright: {selected_text}")

 

    def reviewDb(self, event):

    # review the dict

        print (self.record)

        msgString = ""

        for key, value in self.record.items():

            if isinstance(value, int):

                value = str(value)

            elif isinstance(value, list) and value:

                for v in value:

                    v += "\n"

            msgString += " ".join([key, value]) + "\n"

        dlg = wx.MessageDialog(self, msgString, caption="Record Content",
style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)

        dlg.ShowModal()

 

    def saveDb(self, event):

        if self.record.get('title') is None or self.record.get('author') is
None or self.record.get('description') is None:

            dlg = wx.MessageDialog(self, "Cannot save update database. Not
all required fields have been defined.", caption="Record Warning",
style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)

            dlg.ShowModal()

            return

        elif self.record.get('genre') is None:

            self.record.get['genre'] =  "None"

        elif   self.record.get('narrator') is None: 

            self.record['narrator'] = []

            self.record['narrator'].append("None")

        elif self.record.get('publisher') is None:

            self.record['publisher'] = "None"

        elif self.record.get('title') == '' or
self.record.get('description') == '':

            dlg = wx.MessageDialog(self, "Title and description   are
required before record can be  saved  to the database. ", caption="Record
Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)

            dlg.ShowModal()

            return

 

        # establish session with database.

        session = Session()

        try:

            # create objects

            publisher  =
session.query(publisher).filter_by(publisher=self.record.get('publisher')).f
irst()

            if publisher is None:

                publisher = Publisher(publisher=self.record.get('publisher',
''))

 

            # check if author exists

            authors = []

            for author_name in self.record.get('author', []):

                author =
session.query(Author).filter_by(author=author_name).first()

                if author is None:

                    author = Author(author=author_name,
about_author=self.record.get('about_author', ''))

                authors.append(author)

 

            # check if genre exists

            genres = []

            for genre_name in self.record.get('genre', []):

                genre =
session.query(Genre).filter_by(genre=genre_name).first()

                if genre is None:

                    genre = Genre(genre=genre_name)

                genres.append(genre)

 

            # check if narrator exists

            narrators = []

            for narrator_name in self.record.get('narrator', []):

                narrator =
session.query(Narrator).filter_by(narrator=narrator_name).first()

                if narrator is None:

                    narrator = Narrator(narrator=narrator_name)

                narrators.append(narrator)

 

            series = Series(series=self.record.get('series', ''))

            book = Book(title=self.record.get('title', ''),

                        path=self.record.get('path', ''),

                        release=self.record.get('release', ''),

                        duration=self.record.get('duration', ''),

                        copyright=self.record.get('copyright', ''),

                        description=self.record.get('description', ''),

                        misc=self.record.get('misc', ''),

                        series_no=self.record.get('series_no', 0))

 

            book.publisher = publisher

            book.authors = authors

            book.narrators = narrators

            book.genres = genres

            book.series = series

 

            # add objects to session

            session.add_all([book, publisher, series] + authors + narrators
+ genres)

            # commit changes

            session.commit()

            self.GetTopWindow().SetStatusText("Record saved successfully")

        except Exception as e:

            session.rollback()

            print(f"Error occurred: {e}")

            self.GetTopWindow().SetStatusText("Record did not saved
successfully")

        finally:

            session.close()

 

    def clearRecord(self, event):

        self.record.clear()

        self.GetTopWindow().SetStatusText("Record in memory cleared
successfully")

 

class MyApp(wx.App):

    def OnInit(self):

        # Create the main frame

        self.frame = wx.Frame(None, title="Library", size=(1920, 1080 ))

        self.frame.Maximize()

        sizer_main = wx.BoxSizer(wx.VERTICAL)

        # Create the two panels

        self.panel1 = EditPanel(self.frame)

        self.panel2 = RecordListPanel(self.frame)

        # Create the horizontal box sizers for the panels

        sizer_panel1 = wx.BoxSizer(wx.HORIZONTAL)

        sizer_panel2 = wx.BoxSizer(wx.HORIZONTAL)

 

 

        # Create the menubar

        menubar = wx.MenuBar()

        # Create the "Options" menu

        options_menu = wx.Menu()

        save_record_item = options_menu.Append(wx.ID_ANY, "Save
Record\tCtrl+S", "Save to database")

        self.Bind(wx.EVT_MENU,self.panel1.saveDb, save_record_item)

        next_file_item = options_menu.Append(wx.ID_ANY, "Next file\tCtrl+N",
"Load next file")

        prior_file_item = options_menu.Append(wx.ID_ANY, "Prior
file\tCtrl+P", "Load prior file")

        review_record_item = options_menu.Append(wx.ID_ANY, "Review
Record\tCtrl+r", "Review  record")

        self.Bind(wx.EVT_MENU,self.panel1.reviewDb, review_record_item)

        self.Bind(wx.EVT_MENU,self.panel1.nextBook, next_file_item)

        self.Bind(wx.EVT_MENU,self.panel1.priorBook, prior_file_item)

        clear_record_item = options_menu.Append(wx.ID_ANY, "Clear
Record\Alt+I", "Clear record in memory")

        self.Bind(wx.EVT_MENU,self.panel1.clearRecord, clear_record_item)

        options_menu.Append(wx.ID_EXIT, "Exit", "Exit the program")

        menubar.Append(options_menu, "&Options")

 

        # Create the "Save to record" menu

        save_menu = wx.Menu()

        title_item = save_menu.Append(wx.ID_ANY, "Title\tAlt+T", "Save book
title")

        self.Bind(wx.EVT_MENU,self.panel1.titleSave, title_item)

        author_item = save_menu.Append(wx.ID_ANY, "Author\tAlt+A", "Save
book author")

        self.Bind(wx.EVT_MENU,self.panel1.authorSave, author_item)

        series_item = save_menu.Append(wx.ID_ANY, "Series\tAlt+S", "Save
book Series")

        self.Bind(wx.EVT_MENU,self.panel1.seriesSave, series_item)

        seriesNo_item = save_menu.Append(wx.ID_ANY, "SeriesNo\tCtrl+3",
"Save Series No")

        self.Bind(wx.EVT_MENU,self.panel1.seriesNoSave, seriesNo_item)

        genre_item = save_menu.Append(wx.ID_ANY, "Genre\tAlt+G", "Save book
genre")

        self.Bind(wx.EVT_MENU,self.panel1.genreSave, genre_item)

        description_item = save_menu.Append(wx.ID_ANY, "Description\tAlt+D",
"Save book description")

        self.Bind(wx.EVT_MENU,self.panel1.descriptionSave, description_item)

        aboutAuthor_item = save_menu.Append(wx.ID_ANY, "About
Author\tAlt+B", "Save about author")

        self.Bind(wx.EVT_MENU,self.panel1.aboutAuthorSave, aboutAuthor_item)

        narrator_item = save_menu.Append(wx.ID_ANY, "Narrator\tAlt+N", "Save
book narrator")

        self.Bind(wx.EVT_MENU,self.panel1.narratorSave, narrator_item)

        release_item = save_menu.Append(wx.ID_ANY, "Release Date\tAlt+R",
"Save book release date")

        self.Bind(wx.EVT_MENU,self.panel1.releaseSave, release_item)

        duration_item = save_menu.Append(wx.ID_ANY, "Duration\tCtrl+D",
"Save book duration")

        self.Bind(wx.EVT_MENU,self.panel1.durationSave, duration_item)

        copyright_item = save_menu.Append(wx.ID_ANY, "Copyright\tAlt+C",
"Save book copyright")

        self.Bind(wx.EVT_MENU,self.panel1.copyrightSave, copyright_item)

        publisher_item = save_menu.Append(wx.ID_ANY, "Publisher\tAlt+P",
"Save book publisher")

        self.Bind(wx.EVT_MENU,self.panel1.publisherSave, publisher_item)

        misc_item = save_menu.Append(wx.ID_ANY, "Misc\tAlt+M", "Save book
misc")

        self.Bind(wx.EVT_MENU,self.panel1.miscSave, misc_item)

        menubar.Append(save_menu, "Sa&ve to record")

 

        self.frame.SetMenuBar(menubar)

 

        # Create the status bar

        self.frame.CreateStatusBar()

        #self.statusbar.SetFieldsCount(3)

        #self.statusbar.SetStatusWidths([-2, -1, -1])

 

# Set up the panel switching

        self.currentPanel = self.panel1

        self.panel1.SetFocus()

        self.frame.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)

        self.frame.Show()

        self.SetTopWindow(self.frame)

        

        return True

 

    def onKeyDown(self, event):

        if event.GetKeyCode() == wx.WXK_F6:

            if self.currentPanel == self.panel1:

                self.currentPanel = self.panel2

                self.panel2.SetFocus()

            else:

                self.currentPanel = self.panel1

                self.panel1.SetFocus()

        else:

            event.Skip()

 

        # set focus to the current panel.

        self.currentPanel.SetFocus()

 

if __name__ == '__main__':

    # Create the wx

    app = MyApp()

 

    # Start the main event loop

    app.MainLoop()



More information about the Tutor mailing list