Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
moving from tkinter to wxpython
#11
Tanks larz60+,
Unfortunately the script wont run
Line 1
from   wxPython.wx     import *
Error:
Traceback (most recent call last): File "./demo1.py", line 1, in <module> from wxPython import * ImportError: No module named 'wxPython'
whether I try it from python 2.7.12 or 3.5.2 and neither pip or pip3 can find it.
Reply
#12
I was hoping that you would look at and extract the mouse over code, not run the application.
I did explain that it was older code, but failed to mention that you probably wouldn't be able to
run it. Never the less, the event code for hovering should (I have not verified) be the same in phoenix.
Reply
#13
I converted the old program, this will run in phoenix:
import wx


class ButtonColumn(wx.Panel):
    '''Create aligned column of equal-sized buttons with distinct labels and OnClick destinations.

    Illustrates use of nested classes for creating a collection of controls.
    Also illustrates use of mouse over and mouse leave events.
    '''

    class aButton(wx.Button):
        '''Nested button class for use by ButtonColumn class.'''

        def __init__(self, parent, label, whotocall, whotonotify, msg):
            """Expects reference to 'ButtonColumn', list of labels for buttons and list of functions to be called for OnClick events"""
            id = wx.NewId()
            wx.Button.__init__(self, parent, id, label, wx.DefaultPosition, wx.DefaultSize, 1)
            self.whotocall = whotocall
            self.whotonotify = whotonotify
            self.msg = msg
            self.Bind(wx.EVT_BUTTON, self.OnClick)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)

        def OnClick(self, event):
            if self.whotocall: self.whotocall()

        def OnEnter(self, event):
            if self.whotonotify: self.whotonotify(1, self.msg)

        def OnLeave(self, event):
            if self.whotonotify: self.whotonotify(0, self.msg)

    def __init__(self, parent, width, buttons, Bottom=0):
        """Expects reference to 'parent' of 'ButtonColumn', button column 'width', list of button descriptor tuples, and number of buttons to be displayed at the bottom of the column.

        Each button descriptor consists of a label for the button and a reference to the function to be called when the button is clicked.
        """
        wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, (100, 200))
        self.parent = parent

        """Create the upper collection of buttons"""
        previous = None
        for button in buttons[0: len(buttons) - Bottom]:
            oneButton = self.aButton(self, button[0], button[1], button[2], button[3])
            lc = wx.LayoutConstraints()
            lc.left.SameAs(self, wx.Left, 5)
            lc.right.SameAs(self, wx.Right, 5)
            lc.height.AsIs()
            if previous:
                lc.top.SameAs(previous, wx.Bottom, 5)
            else:
                lc.top.SameAs(self, wx.Top, 5)
            oneButton.SetConstraints(lc)
            previous = oneButton

        """Create the lower collection of buttons"""
        buttons.reverse()
        previous = None
        for button in buttons[0: Bottom]:
            oneButton = self.aButton(self, button[0], button[1], button[2], button[3])
            lc = wx.LayoutConstraints()
            lc.left.SameAs(self, wx.Left, 5)
            lc.right.SameAs(self, wx.Right, 5)
            lc.height.AsIs()
            if previous:
                lc.bottom.SameAs(previous, wx.Top, 5)
            else:
                lc.bottom.SameAs(self, wx.Bottom, 5)
            oneButton.SetConstraints(lc)
            previous = oneButton


if __name__ == '__main__':
    class TestFrame(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(
                self, None, -1, "Button Column Test",
                size=(450, 300),
                style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
            )
            self.SetAutoLayout(True)
            buttons = [
                ('OK', self.OKClicked, self.OnMessage, 'OK button text',),
                ('Cancel', self.CancelClicked, self.OnMessage, 'Cancel button text',),
                ('Re-invert', self.ReinvertClicked, self.OnMessage, 'Re-invert button text',),
                ('Exit', self.ExitClicked, self.OnMessage, 'Exit button text',),
            ]

            self.tp = ButtonColumn(self, 45, buttons, 2)

            lc = wx.LayoutConstraints()
            lc.right.SameAs(self, wx.Right)
            lc.width.AsIs()
            lc.top.SameAs(self, wx.Top)
            lc.bottom.SameAs(self, wx.Bottom)
            self.tp.SetConstraints(lc)

            self.CreateStatusBar()

        def OnMessage(self, on, msg):
            if not on: msg = ""
            self.SetStatusText(msg)

        def OKClicked(self):
            print
            "OKClicked"

        def CancelClicked(self):
            print
            "CancelClicked"

        def ReinvertClicked(self):
            print
            "ReInvertClicked"

        def ExitClicked(self):
            print
            "ExitClicked"
            self.Close()


    app = wx.App()
    frame = TestFrame()
    frame.Show(True)
    app.MainLoop()
Reply
#14
Thanks very much. When I get time later I will see how I can adapt it to do what I want.
Reply
#15
you need to pull out the parts related to:
self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
Quote:When I get time later I will see how I can adapt it to do what I want.
Isn't this what you were seeking?
Reply
#16
I really appreciate all the help. I think I have a long way to go before I can be anywhere as confident I know as much about the way wxpython works as I do tkinter ( and that isn't much.)
Here is a bit of the script I have so far.
class MouseEventFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, 'Frame and Button', size=(1210, 400))
        self.panel = wx.Panel(self)
        row = 0
        column = 0
  
        for x in range(1,67):
            txt = books[x]
            myname = txt[0:-3]
            while (len(myname) < 15):
               myname = " " + myname
            while (len(myname) < 20):
                myname += " "
            self.btn = 'butt' + str(x)
            btn = wx.Button(self.panel, -1, myname, pos=(column, row ) )
            self.Bind(wx.EVT_BUTTON, self.OnClick,btn)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn)
            column += 120
            if column == 1200:
                column = 0
                row += 55
    def OnClick(self, event):
       obj = event.GetEventObject()
       print("You clicked %s"%obj.GetLabel())
       event.Skip()       

    def OnEnterWindow(self, event,myname):
        obj = event.GetEventObject()
        print("Success at last!%s"%obj.GetLabel())
        print("Success at last! ",btn[-3:])
        event.Skip()
        

app = wx.App()
frame = MouseEventFrame(parent=None, id=-1)

frame.Show()
app.MainLoop()
The OnClick event works but the OnEnterWindow does nothing.
I get no errors but no output appears.
Reply
#17
try changing:
            self.Bind(wx.EVT_BUTTON, self.OnClick,btn)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn)
To:
            btn.Bind(wx.EVT_BUTTON, self.OnClick,btn)
            btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow,btn)
Reply
#18
Thanks Larz60+ that fixed it. I am puzzled as to why the original partially worked.
Out of curiosity I swapped the order of the binds in thatoriginal script thinking it might make the other one work instead but it was still the OnClick which did.
Ah well thanks again.
Reply
#19
The order of the binds is unimportant, as they are not acted upon until triggered by the event.
Reply
#20
Okay I have now got a little further and just to test it's working it plays a note as the mouse pointer enters a button.
Here is my code so far.
This is a modified version of https://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/
import wx
import os 
"""
books[0] is used to create 66 buttons in PanelTwo
"""
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', '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 PanelOne(wx.Panel):
    
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        txt = wx.TextCtrl(self)
 
class PanelTwo(wx.Panel):

    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent, size=(1180, 520))
        row = 0
        column = 0
        howmany = books[0]
        dims = int(howmany)
        for x in range(1,dims):
            tmt = books[x]
            txt = tmt[:-3]
            self.btn = 'butt' + str(x)
            btn = wx.Button(self, -1, txt, 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 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/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)

#
class MyForm(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, 
                          "Panel Switcher Tutorial", size=(1200, 550))
        self.panel_one = PanelTwo(self) #,dims)
 
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.panel_one, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
 
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()
Obviously I want it to say the word which is on the button but when the button is clicked I want it to display a different set of buttons from 1 to the number of chapters in each book. Which it extracts from the right 3 characters in the books list.
As I am just starting with wxpython I am expecting a steep learning curve.At present I am unsure where to go with it. I guess I could just use a sizer to add 66 panels with the appropriate number of buttons on them or use one panel, clear what's on it then replace them with the correct number. I don't know how to do either right now and don't relish the though of adding 66 panels manually.
However I don't know if it can be done in a loop or if the other option is viable. Any suggestions please?
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020