PySimpleGui: How to enter text in the text box? - python-3.x

I am learning PySimpleGui by referring the tutorials at
Link-1 and Link-2
I need to add buttons to my layout to enter a value, then display the value in adjoining textbox
So far, i have been able to create the buttons and the textboxes.
Following is my code:-
import PySimpleGUI as sg
layout = [[sg.Text('Enter Value:')],
[sg.Input(do_not_clear=False), sg.Text('Value selected is:'), sg.Text(sg.InputText(""), key='_USERNAME_')],
[sg.Button('Enter'), sg.Exit()],
[sg.Text('List Of Values:')],
[sg.Listbox(values=('value1', 'value2', 'value3'), size=(30, 2), key='_LISTBOX_')]]
window = sg.Window('My Application', layout)
while True:
event, values = window.Read()
print(event, values)
if event is None or event == 'Exit':
break
if event == 'Enter':
window.Element('_LISTBOX_').Update(values=[event, values, 'new value 3'])
#window.Element('_USERNAME_').Update(values=[values]) #need to update the text box with value entered
window.Close()
However, i am not able to display the entered value in the text box.
I have added a comment in the code (which gives an error for now) where i need to update the text box with entered value.
Please help!
Edit: I was able to display the value in a popup, but i need to display in the text box

You can update elements directly by referencing them using their key on the window object:
eg as per your updates
window['_LISTBOX_'].Update(values=[event, values, 'new value 3'])
window['_USERNAME_'].Update(values[0])

I figured it out,
Following code serves my purpose:-
import PySimpleGUI as sg
layout = [[sg.Text('Enter Value:')],
[sg.Input(do_not_clear=False), sg.T('Not Selected ', size=(52,1), justification='left',text_color='red', background_color='white', key='_USERNAME_')],
[sg.Button('Enter'), sg.Exit()],
[sg.Text('List Of Values:')],
[sg.Listbox(values=('value1', 'value2', 'value3'), size=(30, 2), key='_LISTBOX_')]]
window = sg.Window('My Application', layout)
while True:
event, values = window.Read()
print(event, values)
if event is None or event == 'Exit':
break
if event == 'Enter':
window.Element('_LISTBOX_').Update(values=[event, values, 'new value 3'])
window.FindElement('_USERNAME_').Update(values[0])
window.Close()

Related

Qt: QFormLayout - How to find the row from the button

How to find the row number of QFormLayout() from a button which is in that row? I have a delete button on each row of the form. Such that if I click the delete button, that specific row will get deleted. For this, I am planning to use the command QtWidgets.QFormLayout.removeRow(row) command. I have defined the QFormLayout() within my def __init__(self): function like so.
self.attachForm = QFormLayout()
I also have an Add button which calls the self.attachBtn_clicked(self) function given below. So every time the Add button is clicked a new row is added. Any help will be appreciated.
def attachBtn_clicked(self):
hbox = QHBoxLayout()
self.attachForm.addRow('',hbox)
browseBtn = QPushButton("Open")
hbox.addWidget(browseBtn)
addAttachEdit = QLineEdit()
hbox.addWidget(addAttachEdit)
delAttachBtn = QPushButton("x")
delAttachBtn.setFixedSize(15,15)
delAttachBtn.clicked.connect(self.delAttachBtn_clicked)
hbox.addWidget(delAttachBtn)
The objective is now to write the self.delAttachBtn_clicked(self) function which will delete the specific row.
You can iterate through the rows and find the button that matches the sender.
def delAttachBtn_clicked(self):
for i in range(self.attachForm.rowCount()):
if self.sender() == self.attachForm.itemAt(i, QFormLayout.FieldRole).itemAt(2).widget():
self.attachForm.removeRow(i)
return
itemAt(2) is used since delAttachBtn is the 3rd item in each QHBoxLayout.

How can I get the values of my widget items to display in a TextArea and convert the values to dictionary

I am creating a post form that will send my input as dictionary to a server. I planned to display the user entered input in a TextArea with my first display button click. This display button sets the next button (Send) to be visible. The Send button then convert or saves the values to a dictionary (key/value pair).
In my code, i followed the example in the ipywidget documentation (https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Styling.html [cell 12]) by adding all my widgets in a list. I am have difficulty in calling the values of the widget items to display in the Text area
I have tried to access the values using children[0].values but get error each time. AttributeError: 'Button' object has no attribute 'values'. I will appreciate anyone's help to do this form. If i can get my inputs as a dictionary, that will be very helpful
from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider, Text
#Form item layout
form_item_layout = Layout(
display='flex',
flex_flow='row',
justify_content='space-between'
)
#form container
form_items = [
Box([
Label(value='Name'),
Text(value='John')
], layout=form_item_layout),
Box([
Label(value='Collection UUID'),
Dropdown(options=['theme', 'play', 'character'])
], layout=form_item_layout),
Box([Label(value='Result'),
Textarea(rows = 20)], layout=form_item_layout),
Button(description="display"),
Button(description="Send", button_style='success')
]
#box layout that holds the forms
box_lyt = Layout(
display='flex',
flex_flow='column',
border='solid 2px',
align_items='stretch',
width='50%'
)
form = Box(children=form_items, layout=box_lyt)
display(form)
form.children[4].layout.visibility = 'hidden'
def show(b):
form.children[4].layout.visibility = 'visible'
form.children[2] = c.children[0] + c.children[1] + c.children[2]
#Convert textarea values to dictionary
def list_children(c):
return c.children[2].to_dict()
form.children[3].on_click(show)
form.children[4].on_click(list_children )
I expect a widget displaying: Name, ID, result and display button. Clicking the display should show the values in the result TextArea and make the button (send) visible. Clicking the Send button should accept these values from result and save as dictionary. The widget displays but is not responsiveenter image description here

Get system-default labels from QMessageBox standard buttons

I want to show the text from the 'Yes' and the 'No' button in the informative text of a QMessageBox, but I don't see how I can get these labels from the buttons.
from PyQt5.QtWidgets import *
import sys
app = QApplication(sys.argv)
msgbox = QMessageBox()
msgbox.setStandardButtons(msgbox.Yes | msgbox.No)
info_text = "Click '{yes}' to confirm. Click '{no}' to abort."
msgbox.setInformativeText(info_text)
if msgbox.exec_() == msgbox.Yes:
print("Confirmed")
else:
print("Aborted")
By calling setStandardButtons, the button order and the button labels will be set to the default for the current operating system and the current language setting. How can I obtain these defaults so that I can use them for the slots in the string info_text?
I thought about using the buttons attribute from the QMessageBox object, which is a list of QPushButton objects. I can read the labels from there, but I don't see how I could determine whether the first element in the list is the Yes or the No button.
Okay, I was being stupid: along side the buttons attribute, there is also the button() method, which takes as its argument the button type that I want to retrieve. I can then use text() to get the label. Finally, the hotkey marker & has to be stripped from the label:
info_text = "Click '{yes}' to confirm. Click '{no}' to abort.".format(
yes=msgbox.button(msgbox.Yes).text().replace("&", ""),
no=msgbox.button(msgbox.No).text().replace("&", ""))
msgbox.setInformativeText(info_text)

populate a list box with .csv items

I have this.
scrollbar = tk.Scrollbar(listbox)
scrollbar.pack(side=RIGHT, fill=Y)
listbox = tk.Listbox(root)
listbox.insert(1,'a')
listbox.pack()
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
with open('testCUR.csv', newline='') as csvfile:
spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
for row in spamreader:
print(', '.join(row),'\n')
I was wondering how to correctly populate the listbox with values from a .csv file?
And also why I cannot use the scroll bar correctly?
Once the list box is populated I would like to put the value of the last cell from the selection to a variable for use in a URL string. I havent found any tutorials for this so was looking for help here.
I have tried this.
listbox = tk.Listbox(root, height=1)
listbox.place(x=300,y=75)
with open('testCUR.csv', 'r') as f:
reader = csv.reader(f)
your_list = list(reader)
for item in your_list:
listbox.insert(end, item)
or this inputs only first entry
with open('testCUR.csv', 'r') as f:
reader = csv.reader(f)
your_list = list(reader)
for item in your_list:
listbox.insert(1, item)
Once I have all the values in the list box and it is scrollable which I would love if it was just damn.
listbox = tk.Listbox(root, height=1, scroll=auto)
I need to be able to use only the currency code which is the last value in the .csv file and use it as the selected value and then use it in a variable for the url. The .csv file looks like this.
Algeria د.ج DZD
Andorra € EUR
Angola Kz AOA
Anguilla $ XCD
Antigua and Barbuda $ XCD
Argentina $ ARS
Armenia AMD
Aruba ƒ AWG
Ascension Island £ (*none*)
I am also trying pandas but am new to it because it looks much easier and cleaner to use.
csv_file = ('testCUR.csv')
df = pd.read_csv(csv_file)
saved_col = df['CODE']
for item in df:
listbox.insert(end, saved_col)
Always error. NameError: name 'end' is not defined.
Happens with END also
I was wondering how to correctly populate the listbox with values from a .csv file?
To insert text into a listbox you must give it an index to tell it where to insert. The index is a string that is either a number, or the string "end". In your case you used a variable named end, which of course doesn't exist.
You can insert the text like this:
listbox.insert("end", item)
And also why I cannot use the scroll bar correctly?
You haven't described why your scrollbar is not correct.
Making a scrollbar works requires two-way conversation. The scrollbar must be told what widget to scroll (via the command attribute, and the widget needs to know which scrollbar to update when it is scrolled (via the yscrollcommand or xscrollcommand attribute).
It's also good to explicitly set whether the scrollbar is horizontal or vertical, though in your case it's vertical which is the default.
And finally, it's generally the best practice to make the scrollbar and the widget being scrolled to have the same parent. You made the mistake of making the scrollbar a child of the listbox. Instead, make it a child of whatever the listbox is a child of. You also made the mistake of trying to make it the parent of the listbox before you created the listbox. A widget must exist before you can give it children.
Here is how to create the listbox and scrollbar:
listbox = tk.Listbox(root)
scrollbar = tk.Scrollbar(root, orient="vertical", command=listbox.yview)
listbox.configure(yscrollcommand=scrollbar.set)

Tkinter insert a Combobox inside a Treeview widget

For example, lets create a Treeview widget using a class as follows:
class FiltersTree:
def __init__(self, master, filters):
self.master = master
self.filters = filters
self.treeFrame = Frame(self.master)
self.treeFrame.pack()
self._create_treeview()
self._populate_root()
def _create_treeview(self):
self.dataCols = ['filter', 'attribute']
self.tree = ttk.Treeview(self.master, columns = self.dataCols, displaycolumns = '#all')
Populate root, insert children as usual. At the end of the codeblock, you can see where I want to put a Combobox in the tree, using a Combo object:
def _populate_root(self):
# a Filter object
for filter in self.filters:
top_node = self.tree.insert('', 'end', text=filter.name)
# a Field object
for field in filter.fields:
mid_node = self.tree.insert(top_node, 'end', text = field.name)
# insert field attributes
self.insert_children(mid_node, field)
def insert_children(self, parent, field):
name = self.tree.insert(parent, 'end', text = 'Field name:',
values = [field.name])
self.tree.insert(parent, 'end', text = 'Velocity: ',
values = [Combo(self)]) # <--- Combo object
...
Next the class definition of Combo follows. The way I understand it, the combobox widget inherits from and must be placed inside the Labelframe widget from ttk:
class Combo(ttk.Frame):
def __init__(self, master):
self.opts = ('opt1', 'opt2', 'etc')
self.comboFrame = ttk.Labelframe(master, text = 'Choose option')
self.comboFrame.pack()
self.combo = ttk.Combobox(comboFrame, values=self.opts, state='readonly')
self.combo.current(1)
self.combo.pack()
So is this completely wrong? I want to have the ability to change between units (eg m/s, ft/s, etc) from within the Treeview widget.
Any suggestions, plz?
The treeview widget doesn't support embedded widgets. The values for the values attribute are treated as strings.
By default, a Treeview is a static display of a forest of lists of strings. However, with work, after carefully reading Treeview references, one can make a Treeview fairly interactive. For this question, I would bind left click to an event handler that compares the mouse x,y to the bounding box (.bbox) for the units attribute cell. If in the box, display a Combobox, initialized with the current value (such as 'flops'), directly on top of the units attribute cell.
Tkinter.ttk Treeview reference and Tcl/tk treeview reference
Of course, it might be easier to put the Treeview in a frame with with a separate Combobox.

Resources