wxPython ListBox event not firing - events

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)

Related

PYsimpleGUI create a listbox of folders

I am trying to modify the demoprogram from PYsimpleGUI (Browser_START_HERE_Demo_program_Browser.py) to:
manually select a main folder
list all the subfolders in that folder (but not the files inside them)
make it possible to select a few of those folders, and list them as an output.
I thought I'd do so by editting the code for getting the file list dic, but everything I tried, just makes it
Any ideas? I attached it:
'''def get_file_list_dict():
"""
Returns dictionary of files
Key is short filename
Value is the full filename and path
:return: Dictionary of demo files
:rtype: Dict[str:str]
"""
demo_path = get_demo_path()
demo_files_dict = {}
for dirname, dirnames, filenames in os.walk(demo_path):
for filename in filenames:
if filename.endswith('.py') or filename.endswith('.pyw'):
fname_full = os.path.join(dirname, filename)
if filename not in demo_files_dict.keys():
demo_files_dict[filename] = fname_full
else:
# Allow up to 100 dupicated names. After that, give up
for i in range(1, 100):
new_filename = f'{filename}_{i}'
if new_filename not in demo_files_dict:
demo_files_dict[new_filename] = fname_full
break
return demo_files_dict'''
It's much difficult for me to modify code of Browser_START_HERE_Demo_program_Browser.py to my requirements.
Assume the target is
Select a main directory by a button to call function sg.popup_get_folder
List all subdirectories under main directory in one sg.Listbox
Subdirectories selected shown in another sg.Listbox as output when click Add button
Example Code
from pathlib import Path
import PySimpleGUI as sg
font = ("Courier New", 11)
sg.theme("Dark")
sg.set_options(font=font)
subfolders = []
selected = []
frame_subholders = [[sg.Listbox(subfolders, size=(80, 10), key='Subfolders',
select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, enable_events=True,
highlight_background_color='blue', highlight_text_color='white')]]
frame_selected = [[sg.Listbox(selected, size=(80, 10), key='Selected')]]
layout = [
[sg.Input(readonly=True, expand_x=True, key='Main',
disabled_readonly_background_color=sg.theme_input_background_color()),
sg.Button("Main Folder")],
[sg.Frame("Subholder", frame_subholders)],
[sg.Frame("Selected subholder", frame_selected)],
[sg.Button('Add')],
]
window = sg.Window('Title', layout, finalize=True)
entry = window['Main'].Widget
input_size = entry.winfo_width()//sg.Text.char_width_in_pixels(font)
print(input_size)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'Main Folder':
main_folder = sg.popup_get_folder("", no_window=True)
if main_folder and Path(main_folder).is_dir():
main_folder = main_folder.replace("/", '\\') # For Windows
half = input_size//2
text = main_folder if len(main_folder) <= input_size else main_folder[:half-3]+"..."+main_folder[-half:]
window['Main'].update(text)
subfolders = sorted([str(f) for f in Path(main_folder).iterdir() if f.is_dir()])
window['Subfolders'].update(values=subfolders)
selected = []
window['Selected'].update(values=selected)
elif event == 'Add':
selected = sorted([path for path in values['Subfolders']])
window['Selected'].update(values=selected)
window.close()

Ruby with Java swing is saying that count is nil

Hello so i am new to javax.swing and i wanted to ask you guys why am i getting this error(i am going to put the exact error after my code). I have tried everything i can find. Thank you guys and im sorry if this is an easy fix i really suck at ruby right now
testGui.rb
# javaSwingHello.rb
require 'java' # Line 2
JFrame = javax.swing.JFrame
JLabel = javax.swing.JLabel
JPanel = javax.swing.JPanel
JButton = javax.swing.JButton
BorderFactory = javax.swing.BorderFactory
BorderLayout = java.awt.BorderLayout
GridLayout = java.awt.GridLayout
count = 1
frame = JFrame.new
panel = JPanel.new
button = JButton.new "Click me"
button.addActionListener self
label = JLabel.new "Number of clicks: 0"
panel.setBorder BorderFactory.createEmptyBorder(70, 70, 20, 70)
panel.setLayout GridLayout.new(0, 1)
panel.add button
panel.add label
frame.add panel, BorderLayout::CENTER
frame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
frame.setTitle "TEST GUI"
frame.pack
frame.setVisible true
def actionPerformed(event)
count += 1
texttoset = "Number of clicks " + count
label.setText(texttoset)
end
Error( I am getting this when i press the button )
Exception in thread "AWT-EventQueue-0" org.jruby.exceptions.NoMethodError: (NoMethodError) undefined method `+' for nil:NilClass
at testGui.actionPerformed(testGui.rb:26)
more of a Ruby question - local variables won't be copied into a new scope:
def actionPerformed(event)
count += 1
texttoset = "Number of clicks " + count
label.setText(texttoset)
end
count is a local variable for the method (initially nil) thus the failure.
if you're just testing things out you can work-around this using a global:
$count = 1
def actionPerformed(event)
$count += 1
texttoset = "Number of clicks " + count
label.setText(texttoset)
end
that being said do not use globals and rather setup a proper object that will encapsulate the state and 'implement' the actionPerformed inteface.
You did not say, how you are going to use actionPerformed, but one possibility would be make the method a lambda:
count = 1
$ActionPerformed = -> (event) do
count += 1
texttoset = "Number of clicks " + count
label.setText(texttoset)
end
You would have to invoke it as
$ActionPerformed.call(myEvent)

What happens with QFileDialog.getExistingDirectory?

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)

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