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) |
moving from tkinter to wxpython - Barrowman - Feb-18-2018 I have been using tkinter for some time but I have seen so much about how much better wxpython is that I am trying to start using it. I am trying to create a program which reads from a list and creates buttons which are in a grid and which I can bind to an event handler. I have been searching for a few hours now but cannot figure out how to do it so I have started with this I found: import wx class Example(wx.Frame): def __init__(self, parent, title): super(Example, self).__init__(parent, title = title,size = (300,200)) self.InitUI() self.Centre() self.Show() def InitUI(self): p = wx.Panel(self) gs = wx.GridSizer(4, 4, 5, 5) for i in range(1,17): btn = "Btn"+str(i) gs.Add(wx.Button(p,label = btn),0,wx.EXPAND) p.SetSizer(gs) # Adding the line below caused an error btn.bind('<Button-1>', onButton) # I have added this def to the original so I can test it def onButton(self, event): """ This method is fired when its corresponding button is pressed """ print ("Button pressed!") app = wx.App() Example(None, title = 'Grid demo') app.MainLoop()It gives a good layout and I can figure out how to adjust it to manage my list of 66 items. I cannot seem to work out how to get bind into the for loop.
RE: moving from tkinter to wxpython - Larz60+ - Feb-18-2018 Let me make a suggestion that will help you out tremendously:
you can search for the control that you are interested in, and click on that demo. Take a look at the demo and see if it's close to what you want. the middle tab contains the source code for the demo, use it as a guide, or copy and modify for your application. The demo is really complete and well documented. RE: moving from tkinter to wxpython - Barrowman - Feb-19-2018 Thanks, I have started to look at it and indeed it has already solved that problem for me. RE: moving from tkinter to wxpython - Barrowman - Feb-19-2018 I have been trying to generate 66 buttons and bind them to a function. Buttons do appear fine but there have been errors when I click a button whichever demo code I have tried to modify. This is why I was trying to see if the ButtonPanel demo could give some hints. Still getting problems i'm afraid. I have Python 3.5.2 on my system Tried to run the ButtonPanel demo but 2 modules not installed so tried to install them. sudo -H pip3 install run andsudo -H pip3 install images
RE: moving from tkinter to wxpython - Larz60+ - Feb-19-2018 run.py is a program in the demo directory, it basically sets up the wx.APP runs flash screen and other necessary things to run the demo. You should not use it to run your own programs, but build your own start routine. I haven't done this in a while, and have basically reversed engineered run.py each time. I'll have to look at some of my own code to see what you have to include, this time, I'll put it in the snippets section (and here) so I never have to do it again. It's really simple, unless you forget how to do it, and that's where I'm at right now. I'll be back later with the solution, unless one of the other moderators can fill in here now. RE: moving from tkinter to wxpython - Larz60+ - Feb-20-2018 Almost there... but will pick up tomorrow. One game of 'Heroes IV tribes of the East' and off to bed! RE: moving from tkinter to wxpython - Larz60+ - Feb-20-2018 I forgot to mention, you can copy run.py from the demo directory to your development directory, and then import it without a problem. It will work, but give you a lot of stuff that you don't want, but at least let you work. Ok for now. What I am creating is a new streamlined run.py, that Im trying to setup so that all you will have to do is instantiate the main class, passing __file__, and I'll take care of the rest. Just creating a single window that you can hide if not wanted. I have it almost done, but there are a few things that aren't cooperating. Will pick up in my A.M. RE: moving from tkinter to wxpython - Larz60+ - Feb-20-2018 OK here's the modified run.py. It will run any of the demo's (I only tried a few, if you find some that won't let me know) but without menu which I deleted for your own programs. It produces one window. If you need more, you will have to add them I also added the following options to the window: # 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 I'm still working on a simple instantiate and good to go, to arrive shortly. This will be good for the time being. code: #!/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): 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, useShell=useShell) app.MainLoop() if __name__ == "__main__": main(sys.argv)You will need to start your programs with this routine if __name__ == '__main__': import sys,os import run run.main(['', __file__.split('/').pop(-1)])Ultimately, you want to create your own wx.App() in a class init. That way you will be able to import the module into other code. something like the first few initialize statements here: https://python-forum.io/Thread-Perfectly-proportioned-3-frame-wxpython-application-template RE: moving from tkinter to wxpython - Barrowman - Feb-20-2018 Thanks for the help I am beginning to get a bit more of a grip on it now. I have been playing around with some of the demos but I find that if I have some specific project in mind I find it easier. Now I have an elderly friend who is blind. Before that happened she loved to read her Bible so I thought I would see what I might be able to do to help her. I have downloaded a copy in mp3 format. It is a whole series of files each of which is one chapter so I have started to work out if I can get it set up for her. My current plan is to have a set of buttons each of which represents a book. Then clicking on one will show a frame which has buttons on it and each one when clicked will play the file that relates to that chapter. So she can navigate I want to play another mp3 which I will record announcing the book or chapter when the mouse enters the button. This is what I have so far ( I know it's probably a poor way of doing it ) I am using a script from here http://www.java2s.com/Tutorial/Python/0380__wxPython/BindeventtobuttonMouseenterandleavebuttonclicked.htm which I have been modifying import wx import wx.lib.buttons as buttons books = [' ','Genesis050', 'Exodus040', 'Leviticus027', 'Numbers036', 'Deuteronomy034', 'Joshua024', 'Judges021', 'Ruth004', '1 Samuel031', '2 Samuel024', '1 Kings022', '2 Kings025', '1 Chronicles029', '2 Chronicles036', 'Ezra010', 'Nehemiah013', 'Esther010', 'Job042', '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'] global row, column row = 0 column = 0 class MouseEventFrame(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id, 'Frame and Button', size=(1210, 400)) # wx.Frame.__init__(self, parent, id, size=(1210, 400)) self.panel = wx.Panel(self) row = 0 column = 0 for x in range(1,67): txt = books[x] myname = txt[:-3] while (len(myname) < 15): myname = " " + myname while (len(myname) < 20): myname += " " btn = 'butt' + str(x) btn = wx.Button(self.panel, -1, myname, pos=(column, row ) )#50, 50)) myname self.Bind(wx.EVT_BUTTON, self.OnButton,btn) self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn) column += 120 if column == 1200: column = 0 row += 55 def OnButton(self, event): obj = event.GetEventObject() print("You clicked %s\n"%obj.GetLabel()) event.Skip() def OnEnterWindow(self, event): self.button.SetMyname("Over Me!") event.Skip() app = wx.App() frame = MouseEventFrame(parent=None, id=-1) #frame = MyFrame(None, 'wx.lib.buttons Test') frame.Show() app.MainLoop()It's obviously at an early stage so far and I am developing it on my Linux machine but she has WIn7 Pro so no doubt it will need some changes. The 3 digits at the end of each name are how many chapters there are in the book Problem is that the OnButton click event is detected and works but the OnEnterWindow doesn't. So once again I am stuck.Can you spot the way to fix my problem please? RE: moving from tkinter to wxpython - Larz60+ - Feb-20-2018 Here's an example (for older wxpython, but should work the same): https://wiki.wxpython.org/MouseOvers I would create a panel (or frame) same size as button, and use panel mouse over event to update button |