[Tutor] Python WX module program issues.

john fabiani johnf at jfcomputer.com
Thu Mar 23 09:23:10 EDT 2023


You need to join the wxPython forum ( https://discuss.wxpython.org).  
I'm sure they can answer your questions.
Johnf

On 3/23/23 2:14 AM, mhysnm1964 at gmail.com wrote:
> 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()
>
> _______________________________________________
> Tutor maillist  -Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


More information about the Tutor mailing list