env:python37,windows,wxpython
There's a main frame keep opening while app is running, now I'm trying to create a new frame on mouse right click, the new frame works good if I open it by button click, but if it is triggered by a mouse click event, it will hang and no responding. I'm thinking if there's something wrong with mouse listener, really appreciate if you have any idea.
here's the code detail:
import wx
import time
import win32api
from threading import Thread
class OtherFrame(wx.Frame):
"""
Class used for creating frames other than the main one
"""
def __init__(self, title, parent=None):
wx.Frame.__init__(self, parent=parent, title=title)
panel = wx.Panel(self)
panel.SetBackgroundColour('yellow')
self.Show()
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
btn = wx.Button(self, label='Create New Frame')
btn.Bind(wx.EVT_BUTTON, self.on_new_frame)
self.frame_number = 1
thread = Thread(target=self.monitorMouse, name='monitorMouse')
thread.daemon = True
thread.start()
def monitorMouse(self):
state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
state_right = win32api.GetKeyState(0x02) # Right button down = 0 or 1. Button up = -127 or -128
while True:
a = win32api.GetKeyState(0x01)
b = win32api.GetKeyState(0x02)
if b != state_right: # Button state changed
state_right = b
if b < 0:
print('Right Button Pressed')
else:
print('Right Button Released')
self.on_new_frame(None)
time.sleep(0.001)
def on_new_frame(self, event):
title = 'SubFrame {}'.format(self.frame_number)
frame = OtherFrame(title=title)
self.frame_number += 1
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Main Frame', size=(800, 600))
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
If are determined to monitor the mouse using a thread, then I think that you are going to have to look at wx.lib.newevent.NewEvent().
From within the thread you would use wx.PostEvent to send the mouse event back to the main program.
However, wxpython already has the mouse events available to you, to which you can bind directly e.g.
import wx
class OtherFrame(wx.Frame):
def __init__(self, title, parent=None):
wx.Frame.__init__(self, parent=parent, title=title)
panel = wx.Panel(self)
panel.SetBackgroundColour('yellow')
self.Show()
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
btn = wx.Button(self, label='Create New Frame')
btn.Bind(wx.EVT_BUTTON, self.on_new_frame)
self.Bind(wx.EVT_LEFT_DOWN, self.Left)
self.Bind(wx.EVT_RIGHT_DOWN, self.Right)
self.Bind(wx.EVT_RIGHT_DCLICK, self.on_new_frame)
self.Bind(wx.EVT_CLOSE, self.Quit)
self.frame_number = 1
def Quit(self, event):
self.Destroy()
def Left(self, event):
print("Left Button")
event.Skip()
def Right(self, event):
print("Right Button")
def on_new_frame(self, event):
title = 'SubFrame {}'.format(self.frame_number)
frame = OtherFrame(parent=self,title=title)
self.frame_number += 1
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Main Frame', size=(800, 600))
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
As an aside, note the line
frame = OtherFrame(parent=self,title=title)
sending the parent allows all outstanding OtherFrame's to close when the main frame is closed.
Related
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
btn = wx.Button(self, label="Press me")
btn.Bind(wx.EVT_BUTTON, self.on_button_press)
def on_button_press(self, event):
print("You pressed the button")
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="Hello wxPython")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(redirect=False)
frame = MyFrame()
app.MainLoop()
In the code above we used btn.Bind for binding wx.Button to wx.EVT_BUTTON. if instead, we use this way:
self.Bind(wx.EVT_BUTTON, self.on_button_press, btn)
The result will be the same as above. Now my question is the difference between self.Bind and btn.Bind.
Each widget has an Id.
Events when triggered, pass the Id of the triggering widget, in this case a button.
Binding an event to a function can be specific or generic i.e. a specific widget or any widget that fires that event type.
In short, in this case, the self.Bind binds any button event unless you specify a widget ID.
See: https://docs.wxpython.org/events_overview.html
Hopefully, the code below will help explain.
N.B. event.Skip() says don't stop at this event, see if there are more events to process.
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
btn1 = wx.Button(self, label="Press me 1", pos=(10,10))
btn2 = wx.Button(self, label="Press me 2", pos=(10,50))
Abtn = wx.Button(self, label="Press me", pos=(10,90))
# Bind btn1 to a specific callback routine
btn1.Bind(wx.EVT_BUTTON, self.on_button1_press)
# Bind btn2 to a specific callback routine specifying its Id
# Note the order of precedence in the callback routines
self.Bind(wx.EVT_BUTTON, self.on_button2_press, btn2)
# or identify the widget via its number
# self.Bind(wx.EVT_BUTTON, self.on_button2_press, id=btn2.GetId())
# Bind any button event to a callback routine
self.Bind(wx.EVT_BUTTON, self.on_a_button_press)
# button 1 pressed
def on_button1_press(self, event):
print("You pressed button 1")
event.Skip()
# button 2 pressed
def on_button2_press(self, event):
print("You pressed button 2")
event.Skip()
# Any button pressed
def on_a_button_press(self, event):
print("You pressed a button")
event.Skip()
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="Hello wxPython")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(redirect=False)
frame = MyFrame()
app.MainLoop()
I have wxPython GUI program that has to get an input from the user to run. I want to show the dialog before the main frame, store the input, close the dialog and then run the main program. Right now I am using raw_input instead. This is my code:
import wx
import wx.lib.iewin as iewin
import subprocess
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = iewin.IEHtmlWindow(self)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
def SetTransparent(self, value):
self.transparency = value
wx.Frame.SetTransparent(self, value)
def GetTransparent(self):
return self.transparency
def decreaseTransparency(self, e):
self.SetTransparent(self.GetTransparent() - 10)
def increaseTransparency(self, e):
self.SetTransparent(self.GetTransparent() + 10)
def onKey(self, evt):
if evt.GetKeyCode() == wx.WXK_DOWN:
self.decreaseTransparency(self)
elif evt.GetKeyCode() == wx.WXK_UP:
self.increaseTransparency(self)
else:
evt.Skip()
def load(self,uri):
self.browser.Navigate(uri)
#starts livestreamer process
response = raw_input("Livestreamers name:\n")
livestreamer = "livestreamer twitch.tv/"
host = subprocess.Popen(['livestreamer', 'twitch.tv/'+response, 'best'], stdout=subprocess.PIPE)
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.Navigate("https://www.twitch.tv/" + response+ "/chat?popout=")
dialog.Show()
app.MainLoop()
host.communicate()[0]
This is what I have in mind:
dialog example
In your browser init create a dialog box, run ShowModal on it, and then get the input with dialog.GetValue
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
self.dialog = wx.TextEntryDialog(None, message="Enter stuff")
self.dialog.ShowModal()
print self.dialog.GetValue()
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
Obviously replace printing it with whatever you want to do with the value
If you want to access it after instantiation of the MyBrowser object assign it as an instance variable rather than printing.
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
self.dialog = wx.TextEntryDialog(None, message="Enter stuff")
self.dialog.ShowModal()
self.dlg_val = self.dialog.GetValue()
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
Then use it further down
if __name__ == "__main__":
dialog = MyBrowser(None)
print dialog.dlg_val
i have two py files that each have its own frame made using wxPython, MainWindow and RecWindow. MainWindow has the RecWindow python file included using the keyword "recovery".
MainWindow code:
class MainWindow(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self, parent, wx.ID_ANY,title,pos=(500,200), size = (650,500), style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self.Bind(wx.EVT_CLOSE,self.OnExit)
self.SetIcon(wx.Icon('etc\icons\download.ico', wx.BITMAP_TYPE_ICO))
panel = wx.Panel(self)
RecWindow code:
class RecWindow(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self, parent, wx.ID_ANY,title,pos=(400,200), size = (700,600), style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self.SetIcon(wx.Icon('etc\icons\download.ico', wx.BITMAP_TYPE_ICO))
self.count = 0
when i click on a button in MainWindow , it will hide the MainWindow create an instance of RecWindow, shown below;
def OpenRec(self,event):#this will be used to open the next frame
OR = recovery(None,-1,"RAVE")
OR.Show(True)
MainWindow.Hide()
now, what i am unsure of is how i can return to the MainWindow once i close the RecWindow. RecWindow has a cancel and finish button which both map to a self.close() function. How would i then get MainWindow to show itself again?
Use pubsub to send a message to the main window telling it to Show itself again. I actually have an example of how to do that here:
http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/
Note that this tutorial is using slightly older API that was available in wxPython 2.8. If you're using wxPython 2.9, then you'll have to use the slightly different API that I detail in this article:
http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/
When you create an instance of RecWindow keep a reference to it on main_window and bind to its close event.
In the main_window's close handler check if the window closed was the RecWindow.
If it was, clear the reference to it and show the main_window.
Elif the closed window was main_window carry out any required code.
Finally call event.Skip() so the windows get destroyed.
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, (500, 200), (650, 500),
wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
panel = wx.Panel(self)
button = wx.Button(panel, wx.ID_OPEN)
panel.sizer = wx.BoxSizer(wx.VERTICAL)
panel.sizer.Add(button, 0, wx.ALL, 7)
panel.SetSizer(panel.sizer)
button.Bind(wx.EVT_BUTTON, self.on_button)
self.Bind(wx.EVT_CLOSE, self.on_close)
self.rec_window = None
def on_button(self, event):
rec_window = RecWindow(self, 'Rec window')
rec_window.Show()
self.Hide()
rec_window.Bind(wx.EVT_CLOSE, self.on_close)
self.rec_window = rec_window
def on_close(self, event):
closed_window = event.EventObject
if closed_window == self.rec_window:
self.rec_window = None
self.Show()
elif closed_window == self:
print 'Carry out your code for when Main window closes'
event.Skip()
class RecWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, (400, 200), (700, 600),
wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
app = wx.App(False)
main_window = MainWindow(None, 'Main window')
main_window.Show()
app.MainLoop()
The code is only used to write a simple UI( there is only a textbox on the window), and bind the event wx.EVT_KEY_DOWN to the function OnKeyDown, but when I pressed the Esc key, the window will pop up Esc, Test, then another Esc, Test, finally it will exit after the four message box, why? I only define two message box int the wx.WXK_ESCAPE bindings.
# -*- coding: utf-8 -*-
import wx
class Command(wx.Frame):
def __init__(self, parent, title):
super(Command, self).__init__(parent, title=title,
size=(600, 500))
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
pnl = wx.Panel(self)
self.Bind(wx.EVT_CHAR_HOOK, self.OnKeyDown)
hbox = wx.BoxSizer(wx.HORIZONTAL)
self.__tc_command = wx.TextCtrl(pnl, style=wx.TE_MULTILINE)
self.Bind(wx.EVT_CHAR_HOOK, self.OnKeyDown)
hbox.Add(self.__tc_command, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)
pnl.SetSizer(hbox)
def OnKeyDown(self, evt):
"""Enter to send data, Esc to exit."""
key = evt.GetKeyCode()
if key == wx.WXK_ESCAPE:
##################Only two MessageBox, but pop up four##################
wx.MessageBox("Esc")
wx.MessageBox("Test")
##################Only two MessageBox, but pop up four##################
self.Close()
if key == wx.WXK_RETURN:
wx.MessageBox("Enter")
evt.Skip()
if __name__ == '__main__':
app = wx.App(redirect=False)
Command(None, title='Command')
app.MainLoop()
You are calling self.Bind(wx.EVT_CHAR_HOOK, self.OnKeyDown) twice in your code.
What event is used when I close a tab in an auinotebook? I tested with
EVT_AUINOTEBOOK_PAGE_CLOSE(D). It didn't work.
I would also like to fire a right click on the tab itself event.
Where can I find all the events that can be used with the aui manager/notebook? Might just be my poor searching skills, but I can't find any lists over the different events that exist, not for mouse/window events either. It would be really handy to have a complete list.
#!/usr/bin/python
#12_aui_notebook1.py
import wx
import wx.lib.inspection
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.nb = wx.aui.AuiNotebook(self)
self.new_panel('Page 1')
self.new_panel('Page 2')
self.new_panel('Page 3')
self.nb.Bind(wx.EVT_AUINOTEBOOK_PAGE_CLOSED, self.close)
def new_panel(self, nm):
pnl = wx.Panel(self)
pnl.identifierTag = nm
self.nb.AddPage(pnl, nm)
self.sizer = wx.BoxSizer()
self.sizer.Add(self.nb, 1, wx.EXPAND)
self.SetSizer(self.sizer)
def close(self, event):
print 'closed'
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, '12_aui_notebook1.py')
frame.Show()
self.SetTopWindow(frame)
return 1
if __name__ == "__main__":
app = MyApp(0)
# wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
Oerjan Pettersen
This is the bind command you want:
self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSED, self.close, self.nb)
To detect a right click on the tab (e.g. to show a custom context menu):
self.Bind(wx.aui.EVT_AUINOTEBOOK_TAB_RIGHT_DOWN, self.right, self.nb)
Here's a list of the aui notebook events:
EVT_AUINOTEBOOK_PAGE_CLOSE
EVT_AUINOTEBOOK_PAGE_CLOSED
EVT_AUINOTEBOOK_PAGE_CHANGED
EVT_AUINOTEBOOK_PAGE_CHANGING
EVT_AUINOTEBOOK_BUTTON
EVT_AUINOTEBOOK_BEGIN_DRAG
EVT_AUINOTEBOOK_END_DRAG
EVT_AUINOTEBOOK_DRAG_MOTION
EVT_AUINOTEBOOK_ALLOW_DND
EVT_AUINOTEBOOK_DRAG_DONE
EVT_AUINOTEBOOK_BG_DCLICK
EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN
EVT_AUINOTEBOOK_TAB_MIDDLE_UP
EVT_AUINOTEBOOK_TAB_RIGHT_DOWN
EVT_AUINOTEBOOK_TAB_RIGHT_UP
From: {python folder}/Lib/site-packages/{wxpython folder}/wx/aui.py