Get user input from a dialog before showing the mainframe - python

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

Related

WxPython Cut, Copy, Paste functions

I am making a small application and I have trouble defining efficient "Edit" menu functions.
I have tried this:
from pyautogui import hotkey
.
.
.
def OnCopy ( self, event ):
hotkey ( 'ctrl, 'c' )
However, the above doesn't always work and even breaks sometimes. Is there a better method?
wxPython has its own Clipboard object. Its implementation depends on the use of a wxDataObject because, of course, you can copy and paste many types of data onto the clipboard
import wx
class MainFrame(wx.Frame):
"""Create MainFrame class."""
def __init__(self, *args, **kwargs):
super().__init__(None, *args, **kwargs)
self.size = (400, 1000)
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
def on_copy(self, event):
if wx.TheClipboard.Open():
# Put some text onto the clipboard
text = self.panel.txt_input.GetValue()
data_object = wx.TextDataObject(text)
wx.TheClipboard.SetData(data_object)
# Now retrieve it from the clipboard and print the value
text_data = wx.TextDataObject()
success = wx.TheClipboard.GetData(text_data)
wx.TheClipboard.Close()
if success:
print(f'This data is on the clipboard: {text_data.GetText()}')
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent
self.txt_input = wx.TextCtrl(self)
cmd_copy = wx.Button(self, wx.ID_COPY)
cmd_copy.Bind(wx.EVT_BUTTON, parent.on_copy)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.txt_input)
sizer.Add(cmd_copy)
self.SetSizer(sizer)
if __name__ == '__main__':
wx_app = wx.App()
MainFrame()
wx_app.MainLoop()

wxpython open second frame on mouse click no responding

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.

How to make Wxpython NewWindow appear to the Top

When right key pressed down, Popup Menu for 'edit' or 'delete' listctrl Item
If user selected 'edit', create a new window for editing
But the new window appear bottom of the old main window,
I know it may because i using wx.CallAfter(self.PopupMenu, MyPopupMenu(self, item), self.position)
But if i don't use wx.Callafter,
when i select a list item ,
Press right mouse key, choose the 'delete' menu,
A error dialog will appear " can not retrive information from list item XXX".
how to make the new Window top and active?
Thank You
import wx
DATA = {
0 : (u"Test2", "123456", ),
1 : (u"Test", "123456",),
2 : (u"doe", "156789", ),
3 : (u"John", "13455", )
}
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None)
frame.Show()
self.SetTopWindow(frame)
return True
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, wx.NewId(), size=(500, -1))
wx.Frame.CenterOnScreen(self)
self.panel = MyPanel(self)
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.list = MyListCtrl(self,3)
self.add_button = wx.Button(self, label="add")
h_sizer = wx.BoxSizer(wx.HORIZONTAL)
h_sizer.Add(self.add_button, proportion=1, flag=wx.ALL, border=5)
v_sizer = wx.BoxSizer(wx.VERTICAL)
v_sizer.Add(h_sizer, proportion=0, flag=wx.EXPAND)
v_sizer.Add(self.list, proportion=1, flag=wx.EXPAND, border=5)
self.SetSizer(v_sizer)
self.add_button.Bind(wx.EVT_BUTTON,self.onAdd)
def onAdd(self, event):
self.new_w = NewWindow(self)
self.new_w.Show()
class MyPopupMenu(wx.Menu):
def __init__(self,parent, item):
super(MyPopupMenu,self).__init__()
self.parent = parent
self.item = item
menuEdit = wx.MenuItem(self,wx.NewId(), 'edit %s' % item[0])
self.AppendItem(menuEdit)
self.Bind(wx.EVT_MENU, self.onEdit, menuEdit)
menuDel = wx.MenuItem(self,wx.NewId(), 'delete %s' % item[0])
self.AppendItem(menuDel)
self.Bind(wx.EVT_MENU, self.OnDelete, menuDel)
def onEdit(self,e):
self.parent.parent.edit_w = NewWindow(self.parent.parent)
self.parent.parent.edit_w.Show()
def OnDelete(self,e):
self.parent.DeleteAllItems()
class MyListCtrl(wx.ListCtrl):
def __init__(self, parent, columns):
wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT)
self.parent = parent
self.R_MOUSE = 0
self.InsertColumn(0, "name")
self.InsertColumn(1, "phone")
self.InsertColumn(2, "address")
self.SetColumnWidth(0, 200)
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelect)
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
self.itemDataMap = {}
self.refresh_list()
def refresh_list(self):
self.DeleteAllItems()
for entry in DATA.items():
self.Append(entry[1])
self.SetItemData(entry[0],entry[0])
def OnRightDown(self, event):
self.R_MOUSE = 1
self.position = event.GetPosition()
event.Skip()
def OnSelect(self, event):
index = event.GetIndex()
item = []
for i in range(3):
item.append(self.GetItem(itemId=index, col=i).GetText())
self.SetItemState(index, 0, wx.LIST_STATE_SELECTED)
self.SetItemBackgroundColour(index, wx.Colour(255,255,0))
if self.R_MOUSE:
self.R_MOUSE = 0
self.PopupMenu(MyPopupMenu(self, item), self.position)
class NewWindow(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, size=(400,250), style=wx.DEFAULT_FRAME_STYLE)
self.parent = parent
self.CenterOnParent()
panel = wx.Panel(self)
def onClick(self,event):
self.Close()
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
You can use the flag wx.STAY_ON_TOP
try this:
class NewWindow(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, size=(400,250), style=wx.DEFAULT_FRAME_STYLE| wx.STAY_ON_TOP)

Save the selected value of a combobox in wxpython

I'm working to design a gui using wxpython, a pecie of my code is that i have a class which a fram
declaration and also i declared variables that i wanna chage their values based on the comboboxes
selection. i did the folowing:
class myMenu(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(900, 700))
self.ct = 0
self.phaseSelection = ""
self.opSelection = ""
self.instSelection = ""
self.orgSelection = ""
panel = wx.Panel(self, -1)
panel.SetBackgroundColour('#4f3856')
phasesList = ["preOperations", "inOperations", "postOperations"]
self.cbPhases = wx.ComboBox(panel, 500, 'Phase', (50, 150), (160,-1), phasesList, wx.CB_DROPDOWN)
self.Bind(wx.EVT_COMBOBOX, self.OnPhaseSelection, id = self.cbPhases.GetId())
and this is the code of the "OnPhaseSelection" event :
def OnPhaseSelection(self, event):
self.phaseSelection = self.cbPhases.GetValue()
where i wanna save the selected value in the variable "self.phaseSelection" that i declared it with an
empty string as initial value, then i wanna use this variable with the new saved value, but when i run
the program, the variable contains the default value of the combobox! so please what is the problem in
my work ?
I'm not sure what's wrong with that. It looks like it should work. I copied most of it and put it into a runnable example that works on Windows:
import wx
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
panel = wx.Panel(self, wx.ID_ANY)
self.ct = 0
self.phaseSelection = ""
self.opSelection = ""
self.instSelection = ""
self.orgSelection = ""
phasesList = ["preOperations", "inOperations", "postOperations"]
self.combo = wx.ComboBox(panel, choices=phasesList)
self.combo.Bind(wx.EVT_COMBOBOX, self.onCombo)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.combo)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onCombo(self, event):
"""
"""
self.phaseSelection = self.combo.GetValue()
print self.phaseSelection
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()

wxMessageBox with an auto-close timer in wxPython

Platforms: Windows, OS X
Python Version: Active State Python 2.7
wxPython Version: Version 2.9
Here is a sample code in which I use a wxMessageBox:
import wx,os
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(100, 100),style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
host=os.system('hostname')
if host!='superman':
self.dialogBox=wx.MessageBox('The host name should be superman. Closing this dialog box in 2s...','Info')
self.Destroy()
else:
self.Center()
self.Show()
if __name__ == '__main__':
app = wx.App(redirect=False)
frame = Frame(None, -1, 'Sample')
app.MainLoop()
According to the above piece of code, If the host name is not 'superman' , then the user is displayed a message box and prompted to press 'OK'. If the user presses 'OK' button on the message box, then the control moves to the next line in the code (i.e., line number 10) where the frame is destroyed. I want to be to able to automatically close the dialog box and go to the next line in the code i.e., self.Destroy() if the user does not press the 'OK' button in the next 2 seconds. Any thoughts on how do I do that in wxpython ?
If you create your own custom dialog by subclassing wx.Dialog you can use a wx.Timer to generate a periodic event to which you can bind a handler which updates the message every time the timer event fires, then after x event fires you can destroy the dialog.
Working example:
import wx
import os
class MessageDialog(wx.Dialog):
def __init__(self, message, title, ttl=10):
wx.Dialog.__init__(self, None, -1, title,size=(400, 150))
self.CenterOnScreen(wx.BOTH)
self.timeToLive = ttl
stdBtnSizer = self.CreateStdDialogButtonSizer(wx.OK|wx.CANCEL)
stMsg = wx.StaticText(self, -1, message)
self.stTTLmsg = wx.StaticText(self, -1, 'Closing this dialog box in %ds...'%self.timeToLive)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(stMsg, 1, wx.ALIGN_CENTER|wx.TOP, 10)
vbox.Add(self.stTTLmsg,1, wx.ALIGN_CENTER|wx.TOP, 10)
vbox.Add(stdBtnSizer,1, wx.ALIGN_CENTER|wx.TOP, 10)
self.SetSizer(vbox)
self.timer = wx.Timer(self)
self.timer.Start(1000)#Generate a timer event every second
self.timeToLive = 10
self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)
def onTimer(self, evt):
self.timeToLive -= 1
self.stTTLmsg.SetLabel('Closing this dialog box in %ds...'%self.timeToLive)
if self.timeToLive == 0:
self.timer.Stop()
self.Destroy()
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(100, 100),style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
host=os.system('hostname')
if host!='superman':
dlg = MessageDialog('The host name should be superman', 'Info', ttl=10)
dlg.ShowModal()
else:
self.Center()
self.Show()
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = Frame(None, -1, "")
frame.Show(1)
app.MainLoop()
I think you might have to use a custom wx.Dialog for this. You can use wx.FutureCall to call trigger an event in the future. Something like:
class MessageDialog(wx.Dialog):
def __init__(self, message, title):
wx.Dialog.__init__(self, None, -1, title,size=(300, 120))
self.CenterOnScreen(wx.BOTH)
ok = wx.Button(self, wx.ID_OK, "OK")
ok.SetDefault()
text = wx.StaticText(self, -1, message)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(text, 1, wx.ALIGN_CENTER|wx.TOP, 10)
vbox.Add(ok, 1, wx.ALIGN_CENTER|wx.BOTTOM, 10)
self.SetSizer(vbox)
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(100, 100),style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
host=os.system('hostname')
if host!='superman':
dlg = MessageDialog('The host name should be superman. Closing this dialog box in 2s...', 'Info')
wx.FutureCall(2000, dlg.Destroy)
dlg.ShowModal()
else:
self.Center()
self.Show()

Categories

Resources