What happens with QFileDialog.getExistingDirectory? - pyside

I'm new guy with Pyside, and i'm trying do this project can run on the 3Dsmax
My problem with this code is : I press the button "browse_btn" it can not link to "def browse". Nothing happens.
This is my code :
def addnewobject():
w = QtGui.QWidget()
w.setFixedSize(450,90)
w.setWindowTitle('Select folder of new objects')
_GCProtector.widgets.append(w)
w.show()
folder_lb = QtGui.QLabel("Folder : ")
directoryComboBox = QtGui.QComboBox(QtCore.QDir.currentPath())
browse_btn=QtGui.QPushButton("Browse...",browse())
cancel_btn = QtGui.QPushButton("Cancel")
ok_btn = QtGui.QPushButton("OK")
browser = QtGui.QGridLayout()
browser.addWidget(folder_lb,0,0)
browser.addWidget(directoryComboBox,0,1,1,4)
browser.addWidget(browse_btn,0,5)
browser.addWidget(cancel_btn,2,4)
browser.addWidget(ok_btn,2,5)
browser.setColumnStretch(1, 1)
w.setLayout(browser)
cancel_btn.clicked.connect(w.close)
def browse():
directory = QtGui.QFileDialog.getExistingDirectory("Find Files",QtCore.QDir.currentPath())
if directory:
if directoryComboBox.findText(directory) == -1:
directoryComboBox.addItem(directory)
directoryComboBox.setCurrentIndex(directoryComboBox.findText(directory))
I hope everyone can give me some advices. Thanks

To make things easier, you should re-organize your code to use a class. That way, you can access child widgets in other methods using self.
Here is how the class might look:
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setFixedSize(450, 90)
self.setWindowTitle('Select folder of new objects')
self.folder_lb = QtGui.QLabel("Folder : ")
self.directoryComboBox = QtGui.QComboBox()
self.directoryComboBox.addItem(QtCore.QDir.currentPath())
self.browse_btn = QtGui.QPushButton("Browse...")
self.cancel_btn = QtGui.QPushButton("Cancel")
self.ok_btn = QtGui.QPushButton("OK")
browser = QtGui.QGridLayout()
browser.addWidget(self.folder_lb, 0, 0)
browser.addWidget(self.directoryComboBox, 0, 1, 1, 4)
browser.addWidget(self.browse_btn, 0, 5)
browser.addWidget(self.cancel_btn, 2, 4)
browser.addWidget(self.ok_btn, 2, 5)
browser.setColumnStretch(1, 1)
self.setLayout(browser)
self.browse_btn.clicked.connect(self.browse)
self.cancel_btn.clicked.connect(self.close)
def browse(self):
directory = QtGui.QFileDialog.getExistingDirectory(
self, "Find Files", QtCore.QDir.currentPath())
if directory:
if self.directoryComboBox.findText(directory) == -1:
self.directoryComboBox.addItem(directory)
self.directoryComboBox.setCurrentIndex(
self.directoryComboBox.findText(directory))
and you could use it like this:
def addnewobject():
widget = Widget()
widget.show()
_GCProtector.widgets.append(widget)

Related

tk.Entry validate command doesn't restore previous value when False returned

I have carefully reviewed answers to Interactively validating Entry widget content in tkinter, but my script fails to restore previous value if the validate command returns False. I captured %P and %s and print them out...They both show the same value.
import tkinter as tk
class Controller :
def __init__(self) :
i=10
j=20
# list comprehension
self.entry_widgets = [[None for col in range(j)] for row in range(i)]
#print(self.entry_widgets)
self.values = [["string"+str(row) + str(col) for col in range(10)] for row in range(20)]
#print(self.values)
class EnterBox(tk.Entry):
def __init__(self,*args,**kwargs):
#print (args)
self._modified = False
self._save = 0
self._raise = 1
self._lower = 2
frame, i,j, *newargs = args
self._content = tk.StringVar()
# tk.Entry.__init__(self,frame,*newargs,
# validate = 'focusout',
# validatecommand = vcmd,
# **kwargs)
tk.Entry.__init__(self,frame,*newargs,**kwargs)
vcmd = (self.register(self._revert), '%P', '%s')
ct.entry_widgets[i][j] = self
self.config(textvariable=self._content)
self.config(validate = "focusout")
self.config(validatecommand = vcmd )
x=(ct.values[i][j])
self.insert(0,x)
#self._content.set(x)
self.bind("<Return>",lambda event, x=self._save : self._action(event,x) )
self.bind("<Button-2>",lambda event, x=self._save : self._action(event,x) )
self.bind("<FocusIn>", lambda event, x=self._raise : self._action(event,x))
self.bind("<FocusOut>", lambda event, x=self._lower : self._action(event,x))
self.bind('<Button-3>', lambda event, x=self._lower : self._action(event,x))
self.grid(column=i+1,row=j+2)
def _revert(self,P,s):
print ("Hi There")
print(P)
print(s)
return False
def _action(self,event,action):
print(str(action)+' ' + str(event))
if action == self._save :
ct.values[i][j] = self._content.get()
self.config(bg='lightskyblue2')
self._modified = True
elif action == self._raise :
self.config(bg = 'light pink')
elif action == self._lower :
self.config(bg = 'gray80')
self._modified = False
else :
print('action value is bad action =>' + str(action))
if "__main__" == __name__ :
root = tk.Tk()
frame = tk.Frame()
i=j=0
ct = Controller()
root.grid()
frame.grid()
check = EnterBox(frame,i,j,width = 24)
check2 = EnterBox(frame,i+1,j,width = 24)
root.mainloop()
I have tried removing all other bindings, to no avail.
Interestingly, but a separate issue, If I use StringVar. set instead of self.insert, (see commented out line) the validate command runs once, and never again despite several focus changes. Using Python 3.8
The validation isn't designed to restore anything if the validation happens on focusout. The validation can only prevent characters from being added at the time they are added. You will have to add code to restore the previous value.

Struggleing to validate a user entry in tkinter

Here is part of some code i create for a project in tkinter using sqlite3 as a database in python. Im trying to make it so that when a user enters their values into the entry fields it only accepts integer values, and tried to implement this into the validation function. Ive tried using the try and except method, but this still seems to allow all values to be added to the table. How else could i attempt to make this work?
def validation (self):
try:
int(self.inc.get()) and int(self.out.get()) == True
except ValueError:
self.message['text'] = 'Value must be a number!'
def adding (self):
if self.validation:
query = 'INSERT INTO data VALUES (?,?)'
parameters = (self.inc.get(), self.out.get())
self.run_query (query, parameters)
self.message ['text'] = 'Record [] added' .format (self.inc.get ())
self.inc.delete (0, END)
self.out.delete (0, END)
else:
self.message['text'] = 'Income or outgoing field is empty'
self.viewing_records()
def deleting (self):
self.message ['text'] = ''
try:
self.tree.item(self.tree.selection ()) ['values'][0]
except IndexError as e:
self.message['text'] = 'Please, select record!'
return
self.message['text'] = ''
Income = self.tree.item (self.tree.selection ()) ['text']
query = 'DELETE FROM data WHERE totalinc = ?'
self.run_query (query, (Income, ))
self.message['text'] = 'Record [] deleted.'.format(Income)
self.viewing_records()
def editing (self):
self.message['text'] = ''
try:
self.tree.item (self.tree.selection ())['values'][0]
except IndexError as e:
self.message['text'] = 'Please select record'
return
name = self.tree.item (self.tree.selection ())['text']
old_out = self.tree.item (self.tree.selection ())['values'][0]
self.edit_wind = Toplevel ()
self.edit_wind.title ("Editing")
Label (self.edit_wind, text = 'Old income:').grid (row = 0, column = 1)
Entry (self.edit_wind, textvariable = StringVar(self.edit_wind, value = name), state = 'readonly').grid(row = 0, column = 2)
Label (self.edit_wind, text = 'New income:').grid(row = 1, column = 1)
new_inc = Entry (self.edit_wind)
new_inc.grid (row = 1, column = 2)
Label (self.edit_wind, text = 'Old outgoing:').grid (row = 2, column = 1)
Entry (self.edit_wind, textvariable = StringVar(self.edit_wind, value = old_out), state = 'readonly').grid(row = 2, column = 2)
Label (self.edit_wind, text = 'New outgoing: ').grid(row = 3, column = 1)
new_out = Entry (self.edit_wind)
new_out.grid (row = 3, column = 2)
Button (self.edit_wind, text = 'Save changes', command = lambda: self.edit_records (new_inc.get(), name, new_out.get(), old_out)).grid (row = 4, column = 2, sticky = W)
self.edit_wind.mainloop()
def edit_records (self, new_inc, name, new_out, old_out):
query = "UPDATE data SET totalinc = ?, totalout = ? WHERE totalinc = ? AND totalout = ?"
parameters = (new_inc, new_out, name, old_out)
self.run_query (query, parameters)
self.edit_wind.destroy()
self.message['text'] = 'Record [] changed.' .format (name)
self.viewing_records()
if __name__ == '__main__':
wind = Tk()
application = Product (wind)
wind.mainloop()
str = '8'
if str.isdigit():
print(str)
I suggest taking a look at is isdigit().

wxPython ListBox event not firing

I have a wx.Dialog that contains a button and 2 ListBoxes, the button findAppBtn searches through a list of directories and then displays the result in actListBox. Selecting the directory of your choice from actListBox should then fire the event EVT_LISTBOX which calls actListBoxList. This function does an ls on the directory and should list the files it finds in the lower list box binListBox using Append. Upon selecting an item from the lower ListBox, the window closes.
The problem is that the self.Bind(EVT_LISTBOX, self.actListBoxList) does not seem to be firing when an item is selected.
(also please excuse the bad coding, I am trying to get it working before minifying)
self.findAppBtn = wx.Button(panel, -1, "Find app")
self.findAppBtn.SetDefault()
self.Bind(wx.EVT_BUTTON, self.startConf, self.findAppBtn)
hBox2.Add(self.findAppBtn, 0, flag=wx.LEFT, border=5)
vBox.Add(hBox2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=3)
self.actListBox = wx.ListBox(panel, choices=[])
self.Bind(wx.EVT_LISTBOX, self.actListBoxList)
vBox.Add(self.actListBox, 2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=3)
self.binListBox = wx.ListBox(panel, choices=[])
self.Bind(wx.EVT_LISTBOX, self.binListBoxList)
vBox.Add(self.binListBox, 2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=3)
self.closeBtn = wx.Button(panel, wx.ID_OK)
hBox4.Add(self.closeBtn, 0, flag=wx.LEFT, border=5)
vBox.Add(hBox4, 0, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=5)
panel.SetSizer(vBox)
def startConf(self,e):
val = self.cmdTxt.GetValue().replace(" ","\ ")
path = "/private/"
aCmd = "find " + path + " -iname '*"+val+"*.app'"
try:
s = pxssh.pxssh()
s.login(sshIP, "root", sshPort, sshPass)
s.sendline(aCmd)
s.prompt()
AP = s.before
for m in AP.split('\n'):
if path in m:
self.actListBox.Append(m.replace(path,"").strip())
s.logout()
return path
except pxssh.ExceptionPxssh as e:
self.parent.progressBox.AppendText(str(e))
def actListBoxList(self,e):
#get string from top box selection e.g xxxx-xxxx-xxxx-/myapp.app
selName = self.actListBox.GetStringSelection()
path = "/private/"
#list all the files in the dir from top box selection
aCmd = "ls " + path + selName
try:
s = pxssh.pxssh()
s.login(sshIP, "root", sshPort, sshPass)
s.sendline(aCmd)
s.prompt()
ls = s.before
for file in ls.split('\n'):
if not file.endswith("/"):
reg = r"\..*"
matchObj = re.search(reg, file)
if not matchObj:
self.binListBox.Append(file)
s.logout()
except pxssh.ExceptionPxssh as e:
self.parent.progressBox.AppendText(str(e))
def binListBoxList(self,e):
binaryName = self.binListBox.GetStringSelection()
self.Close()
EDIT: self.actListBox.Bind(wx.EVT_LISTBOX, self.actListBoxList) fixed the issue.
calling self.Bind(... binds the event to the parent window which is why you're not seeing the event being called. Bind to the listbox instead:
self.actListBox.Bind(wx.EVT_LISTBOX, self.actListBoxList)

Check OptionMenu selection and update GUI

I'm working on a class project and I'm trying to take it beyond the requirements a little here (I'm doing my own homework, just need help improving it!) so I want to update the GUI based on certain selections the user makes instead of just having all irrelevent options available all the time (requirements are to just present the options).
I'm still new to Python and even more new to Tkinter so my only attempt has been the following:
#Step Type
ttk.Label(mainframe, text = "Step Type").grid(column = 1, row = 16)
type_entry = OptionMenu(mainframe, StepType, "Kill", "Explore" , "Conversation")
type_entry.grid(column = 2, row = 16, sticky = (E))
#Step Goal
if StepType.get() == "Kill":
ttk.Label(mainframe, text = "Required Kills").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
elif StepType.get() == "Explore":
ttk.Label(mainframe, text = "Location ID").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
elif StepType.get() == "Conversation":
ttk.Label(mainframe, text = "NPC ID").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
Obviously what I want to do here is when the user selects one of the options from the menu, to display the corresponding entry box and label instead of having all 3 all the time.
Also looking for the same situation for CheckButton
Full working example: tested od 2.7.5 and 3.3.2
It use command= in OptionMenu to call function when user changed option.
import tkinter as ttk
#----------------------------------------------------------------------
def on_option_change(event):
selected = step_type.get()
if selected == "Kill":
goal_label['text'] = "Required Kills"
elif selected == "Explore":
goal_label['text'] = "Location ID"
elif selected == "Conversation":
goal_label['text'] = "NPC ID"
# show label and entry
#goal_label.grid(column=1, row=17)
#goal_entry.grid(column=2, row=17, sticky='E')
#----------------------------------------------------------------------
mainframe = ttk.Tk()
# Step Type
step_type = ttk.StringVar() # there is the rule: variable name lowercase with _
ttk.Label(mainframe, text="Step Type").grid(column=1, row=16)
type_entry = ttk.OptionMenu(mainframe, step_type, "Kill", "Explore" , "Conversation", command=on_option_change)
type_entry.grid(column=2, row=16, sticky='E')
step_type.set("Kill")
# Step Goal
step_goal = ttk.StringVar()
goal_label = ttk.Label(mainframe, text="Required Kills")
goal_label.grid(column=1, row=17)
goal_entry = ttk.Entry(mainframe, width=20, textvariable=step_goal)
goal_entry.grid(column=2, row=17, sticky='E')
# hide label and entry
#goal_label.grid_forget()
#goal_entry.grid_forget()
# --- star the engine ---
mainframe.mainloop()
BTW: you can use grid() and grid_forget() to show and hide elements.
EDIT: example with Radiobutton using trace on StringVar
import tkinter as ttk
#----------------------------------------------------------------------
def on_variable_change(a,b,c): # `trace` send 3 argument to `on_variable_change`
#print(a, b, c)
selected = step_type.get()
if selected == "Kill":
goal_label['text'] = "Required Kills"
elif selected == "Explore":
goal_label['text'] = "Location ID"
elif selected == "Conversation":
goal_label['text'] = "NPC ID"
#----------------------------------------------------------------------
mainframe = ttk.Tk()
# Step Type
step_type = ttk.StringVar() # there is the rule: variable name lowercase with _
ttk.Label(mainframe, text="Step Type").grid(column=1, row=16)
ttk.Radiobutton(mainframe, text="Kill", value="Kill", variable=step_type).grid(column=2, row=16, sticky='E')
ttk.Radiobutton(mainframe, text="Explore", value="Explore", variable=step_type).grid(column=3, row=16, sticky='E')
ttk.Radiobutton(mainframe, text="Conversation", value="Conversation", variable=step_type).grid(column=4, row=16, sticky='E')
step_type.set("Kill")
# use `trace` after `set` because `on_variable_change` use `goal_label` which is not created yet.
step_type.trace("w", on_variable_change)
# Step Goal
step_goal = ttk.StringVar()
goal_label = ttk.Label(mainframe, text="Required Kills")
goal_label.grid(column=1, row=17)
goal_entry = ttk.Entry(mainframe, width=20, textvariable=step_goal)
goal_entry.grid(column=2, row=17, sticky='E')
# --- star the engine ---
mainframe.mainloop()

How to override the key search in a treectrl?

i wanna know how to override the default keysearch in a treectrl.
When i bind a method to the EVT_TREE_KEY_DOWN event and call the selectItem method of the treectrl, it doesn't have any effect.
This is my Tree:
Test <--root
-Aero orea(EI)
-Blub(BL)
-Test(AX)
-123(45)
-Blib (LOL)
My intention:
With the keydown event i am concatenating a searchstring. when iterating over the treeitems, i split the names to get the content of the brackets(e.g.:"EI", "BL"...).
Then i check if the content of the brackets starts with my searchstring. if it is true the selectItem(TreeItemId) is called. But this won't work. It seems that the default search ist still working and is causing problems in my keysearch.
class MeinTreeCtrl(wx.TreeCtrl):
def __init__(self, parent):
wx.TreeCtrl.__init__(self, parent, -1)
root = self.AddRoot("test")
self.AppendItem(root, "Aero orea(EI)")
self.AppendItem(root, "Blub(BL)")
self.AppendItem(root, "Test(AX)")
self.AppendItem(root, "123(45)")
self.AppendItem(root, "Blib(LOL)")
self.searchString = ""
self.lastKeyDown = time.time()
parent.Bind(wx.EVT_TREE_KEY_DOWN, self.OnTreeKeySearch, self)
def GetItem(self, match, root):
item = self.GetFirstChild(root)
while item.IsOk():
tmp = self.GetItemText(item)
tmp = tmp.split(")")
tmp = tmp[len(tmp) - 2]
tmp = tmp.split("(")
tmp = tmp[len(tmp) - 1]
if tmp.startswith(match):
self.SelectItem(item)
break
item = self.GetNextChild(root, item)
return False
def OnTreeKeySearch(self, event):
now = time.time()
if self.searchString == "":
self.searchString = chr(event.GetKeyCode())
if (now - self.lastKeyDown) < 3:
self.searchString += str(chr(event.GetKeyCode()))
else:
self.searchString = str(chr(event.GetKeyCode()))
self.lastKeyDown = now
self.GetItem(self.searchString, self.GetRootItem())
Do you have any clue?
Thank you and best regards
Thomas
After a few days of search i found my mistake.
This line was the problem:
parent.Bind(wx.EVT_TREE_KEY_DOWN, self.OnTreeKeySearch, self)
First I need just the EVT_KEY_DOWN not the tree event for key down.
Second I binded the method to my parent not to self (That is because i did copy & paste :( )
This statement was really useful to me:
A typical example of an event not propagated is the wx.EVT_KEY_DOWN.
It is send only to the control having the focus, and will not
propagate to its parent.
-- EventPropagation

Resources