In my code I am trying to update a table which is called bag_table (in the row of the container of the right column). And when running my code it does show the table initially, but when I hit the submit button the backed is working. It is actually updating the bag_table variable, but it does not update in the gui itself.
Below is my full code.
pd.options.display.max_columns = 100
from services.bag import PCHN
from utils.convertors import dataframe_to_datatable
import flet as ft
def main(page: ft.page):
def bag_service(e):
pc = '9722LA' if postal_code_field.value == '' else postal_code_field.value
hn = '29' if house_number_field.value == '' else house_number_field.value
address = PCHN(pc,
hn).result
bag_table = dataframe_to_datatable(address)
page.add(bag_table) # I added this for debugging, it is actually adding the table at the bottom of my page, so it is updating the actual bag_table
page.update() # This is not updating my bag_table in place though. It stays static as it is.
# define form fields
postal_code_field = ft.TextField(label='Postal code')
house_number_field = ft.TextField(label='House number')
submit_button = ft.ElevatedButton(text='Submit', on_click=bag_service)
# fields for the right column
address = PCHN('9722GN', '5').result
bag_table = dataframe_to_datatable(address)
# design layout
# 1 column to the left as a frame and one to the right with two rows
horizontal_divider = ft.Row
left_column = ft.Column
right_column = ft.Column
# fill the design
page.add(
horizontal_divider(
[left_column(
[postal_code_field,
house_number_field,
submit_button
]
),
right_column(
[
ft.Container(
ft.Row([bag_table],
scroll='always'),
bgcolor=ft.colors.BLACK,
width=800
)
]
)
]
)
)
if __name__ == '__main__':
ft.app(target=main,
view=ft.WEB_BROWSER,
port=666
)
I have been trouble shooting this like craze (hence all the print statements), but it's a classical thing of looking at a thing for hours, and it's probably a stupid mistake. Any help would be much appreciated.
This is a classic "python variables are just references, not values" problem.
You need something that references the table, but isn't the table itself.
Fortunately you already use a container here:
ft.Row([bag_table],
So we can take advantage of that.
In your setup where you create the original table you also need a container:
bag_table = dataframe_to_datatable(address)
bag_container = [bag_table]
and
...
ft.Container(
ft.Row(bag_container,
scroll='always'),
bgcolor=ft.colors.BLACK,
width=800
)
...
Now you can change what bag_container contains:
def bag_service(e):
pc = '9722LA' if postal_code_field.value == '' else postal_code_field.value
hn = '29' if house_number_field.value == '' else house_number_field.value
address = PCHN(pc,
hn).result
bag_container[0] = dataframe_to_datatable(address)
page.update()
Related
I do have a problem while updating my content on-demand.
My scenario: I want to create a GUI which stores information about some products and it should be displayed via a scroll are. This is working fine, but when I want to update the information like the quantity of my item, the GUI or the layout of my QVBoxLayout does not update the new information on the screen.
My code for the update function:
#pyqtSlot(GroupContent)
def _updateData(self, box: GroupContent) -> None:
prompt = UpdatePrompt(self._conn, box)
prompt.exec()
amount = self._top_layout.count()
for i in range(amount):
tmp = self._top_layout.itemAt(i).widget()
if tmp.id != box.id:
continue
tmp.setTitle(box.title)
tmp.lblPrice.setText(str(box.price))
tmp.lblQuantity.setText(str(box.quantity))
The param box does already get the updated information from a QDialog.
The self._top_layout variable will be created with self._top_layout = QVBoxLayout().
I already tried to call update on the Mainwindow and also on the top layout.
Also tried directly accessing the widget with self._top_layout.itemAt(i).widget().setTitle('test') for example.
If this information is necessary, here is my function to dynamic generate the groupboxes:
def _populate(self, insert: Boolean = False) -> None:
data = self._getDBData(insert)
for row in data:
group_box = GroupContent()
group_box.storage_id.connect(self._updateData)
group_box.id = row.storage_id
group_box.title = row.name
group_box.price = row.price
group_box.quantity = row.quantity
group_box.image = row.image
self._top_layout.addWidget(group_box)
I'm making an application in python that can access an excel file to read and write data. Excel file has weekdays and user will be reading or writing the cell next to them. Below, I wrote some loops to check if user left some changes unsaved. And if the cell for a certain day has unsaved changes, label inside the app changes to point it out to the user.
Like: Monday --> Monday*
"kvlabel", for some reason stays in a darker color and hovering my mouse over it reveals that it's not accessed by Pylance. I changed it's name and position but it doesn't make a difference.
daytexts = [
self.root.get_screen("weeklywin").ids.mon_text.text,
self.root.get_screen("weeklywin").ids.tue_text.text,
self.root.get_screen("weeklywin").ids.wed_text.text,
self.root.get_screen("weeklywin").ids.thu_text.text,
self.root.get_screen("weeklywin").ids.fri_text.text
]
cells = [e4, e10, e16, e22, e28]
daylabel = ["mon_label", "tue_label", "wed_label", "thu_label", "fri_label"]
daylabelkv = [
self.root.get_screen("weeklywin").ids.mon_label.text,
self.root.get_screen("weeklywin").ids.tue_label.text,
self.root.get_screen("weeklywin").ids.wed_label.text,
self.root.get_screen("weeklywin").ids.thu_label.text,
self.root.get_screen("weeklywin").ids.fri_label.text
]
justday = ["Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma"]
for day, cell, label in zip(daytexts, cells, daylabel):
if day != cell and label not in self.excel_unsaved_label:
self.excel_unsaved_label.append(label)
elif day == cell and label in self.excel_unsaved_label:
self.excel_unsaved_label.remove(label)
if self.excel_unsaved_label:
self.show_excel_leave_warn()
for label2, kvlabel, tehday in zip(daylabel, daylabelkv, justday):
if label2 in self.excel_unsaved_label:
kvlabel = tehday+"*"
else:
kvlabel = tehday
else:
self.root.current = caller
Like #slothrop suggested, I removed .text from daylabelkv:
daylabelkv = [
self.root.get_screen("weeklywin").ids.mon_label,
self.root.get_screen("weeklywin").ids.tue_label,
self.root.get_screen("weeklywin").ids.wed_label,
self.root.get_screen("weeklywin").ids.thu_label,
self.root.get_screen("weeklywin").ids.fri_label]
and changed the loop like this:
for label2, i, tehday in zip(daylabel, range(len(daylabelkv)), justday):
if label2 in self.excel_unsaved_label:
daylabelkv[i].text = tehday+"*"
It does what I want now. Thank you all for your help.
I’m using this code to draw myself a server in visio:
import win32com.client as w32
visio = w32.Dispatch("visio.Application")
visio.Visible = 1
doc = visio.Documents.Add("Detailed Network Diagram.vst")
page = doc.Pages.Item(1)
page.name = "My drawing"
stn2 = visio.Documents("Servers.vss")
server = stn2.Masters("Server")
serv = page.Drop(server, 0, 0)
for ssh in serv.shapes:
ssh.Cells( 'Fillforegnd' ).FormulaForceU = 'RGB(255,0,0)'
And my problem is when I’m trying to fill the object with a color (instead of the regular server color) it doesn’t work.
Nothing really worked. I’m using python 3.8.
Try this code please
import win32com.client as w32
visio = w32.Dispatch("visio.Application")
visio.Visible = 1
doc = visio.activedocument
page = doc.pages(1)
page.name = "Mydrawing"
stn2 = visio.Documents(2)
server = stn2.Masters(2)
serv = page.Drop(server, 0, 0)
#iterate all sub-shapes into Serv-shape
for ssh in serv.shapes:
ssh.Cells( 'Fillforegnd' ).FormulaForceU = 'RGB(255,255,0)'
If you dont need iterate all sub-shapes, you can change only same of them
#iterate 2nd, 3rd and 4rd sub-shapes into Serv-shape #
for i in range (2,5):
ssh = serv.shapes(i)
# if you need get solid color for sub-shapes uncomment next line
# ssh.Cells('FillPattern').FormulaForceU = '1'
ssh.Cells('Fillforegnd').FormulaU = 'RGB(255,255,0)'
Code in my Jupyterlab notebook change only 3 sub-shapes, which i select and delete for demonstrate difference…
PS The user's problem was not in the code, but in the Visio sub-shapes, which did not want to inherit the color of the main shape. Because these sub-shapes had formulas that used functions like THEMEGUARD and similar to it in their cells.
I modified the shape from the built-in set of elements and the problem was solved…
PPS Solved! To remove the dependency on those sub-shapes, you need to change their Fillstyle to Normal. Just add new line of code ssh.FillStyle = 'Normal'.
Look at code ↓
import win32com.client as w32
visio = w32.Dispatch("visio.Application")
visio.Visible = 1
# create document based on Detailed Network Diagram template (use full path)
doc = visio.Documents.Add ("C:\Program Files\Microsoft Office\root\Office16\visio content\1033\dtlnet_m.vstx")
# use one of docked stencils
stn2 = visio.Documents("PERIPH_M.vssx")
# define 'Server' master-shape
server = stn2.Masters("Server")
# define page
page = doc.Pages.Item(1)
# rename page
page.name = "My drawing"
# drop master-shape on page, define 'Server' instance
serv = page.Drop(server, 0, 0)
# iterate sub-shapes (side edges)
for i in range (2,6):
# define one od side edges from 'Server'
ssh = serv.shapes(i)
# Change Fill Style to 'Normal'
ssh.FillStyle = 'Normal'
# fix FillForegnd cell for side edge
ssh.Cells( 'Fillforegnd' ).FormulaForceU = 'Guard(Sheet.' + str(serv.id) + '!FillForegnd)'
# fix FillBkgnd cell for side edge
ssh.Cells( 'FillBkgnd' ).FormulaForceU = 'Guard(Sheet.' + str(serv.id) + '!FillBkgnd)'
# instead formula 'Guard(x)' rewrite formula 'Guard(1)'
ssh.Cells( 'FillPattern' ).FormulaForceU = 'Guard(1)'
# fill main shape in 'Server' master-shape
serv.Cells("FillForegnd").FormulaForceU = '5'
I am pretty new to python and this is the first time I use tkinter so I hope someone can help me to find the right direction.
Basically this is what I would like to achieve:
I retrieve from an XML 2 lists (APPs, IDs);
The APP List will be shown in a Dropdown menu;
The APP selection in the Dropdown menu will call the APP status using its ID.
I can't get the last point work, basically I think I understand why (I have no matching between the two lists or a function to match them, and the selection calls automatically the last ID of second list) but I am to the best of my knowledge not able to solve it.
import requests
import xml.etree.ElementTree as ET
import tkinter as tk
APP_OPTIONS = []
ID_OPTIONS = []
session = requests.Session()
session.auth = ('USER', 'PW')
applications = session.get('https://getapplicationslist.myurl.com/application/')
applications_xml = applications.content
root = ET.fromstring(applications_xml)
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
APP_OPTIONS.append(app_name)
ID_OPTIONS.append(app_id)
def appcall(*args):
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
status_xml = app_status.content
root = ET.fromstring(status_xml)
for appStatus in root.findall('appStatus'):
status = appStatus.find('status').text
print(status)
root = tk.Tk()
root.title('Application List')
root.geometry("300x200")
var =tk.StringVar(root)
var.set('Choose an Application')
var.trace('w', appcall)
dropDownMenu = tk.OptionMenu(root, var, *APP_OPTIONS)
dropDownMenu.pack()
root.mainloop()
print('End Request')
As mentioned in my comment, the issue is your app_id in appcall does not change. You need to get the corresponding ID from the ID_OPTIONS instead.
def appcall(*args):
app_id = ID_OPTIONS[APP_OPTIONS.index(var.get())] # Add this line
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
...
The app_id is now set to the ID_OPTIONS of the same index based on the app_name (since the insertion order is the same).
However, a better approach would be to initialize your options as a dictionary instead:
# instead of APP_OPTIONS / ID_OPTIONS, create:
apps = {}
...
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
# add to dictionary here:
apps[app_name] = app_id
def appcall(*args):
# Change the app_id to apps.get(var.get())
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + apps.get(var.get())
...
See how much simpler it is to recall the same reference?
If you are feeling comfortable about the language, you might even opt for a dictionary comprehension:
...
root = ET.fromstring(applications_xml)
app_id = {application.find('name').text: application.find('id').text for application in root.findall('application')}
...
In this simple program I'm drawing a window, adding a search box, getting a search term for the user, looking that up in a postgreSQL DB and displaying the reults. It works up to a point - when the user enters a second query.
I have tried in two different ways but each way gives a different problem. In the first way (lines 32-35 http://pastebin.com/q5bnLxaB) I'm creating the output window in the main and passing that to the search function. It crashes with gtk_scrolled_window_add: assertion 'child_widget == NULL' failed. I think because I'm adding the tree to the window when it has already been done. To fix this, I would need to reset the window somehow.
In the second way (lines 56-58) I have added the output window only in the search function so it no longer has this crashing issue. However, the window itself does not update with the results of a second or subsequent search.
Which, if either, of these methods seems the most sensible? I also need to consider that the next step is adding a clickable button beside each search term which will display extended data for each returned result.
BTW, in both cases the output window does not appear until a search is entered. It doesn't hinder functionality but it strange to me.
#!/usr/bin/python
from gi.repository import Gtk
from gi.repository.GdkPixbuf import PixbufLoader
import urllib2
import psycopg2
import sys
class NotebookWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Rugby Database")
#Create Application Window
self.set_border_width(10)
self.set_default_size(800, 600)
self.set_position(Gtk.WindowPosition.CENTER)
#Add external container (box)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
#Add tabbed window
nbook = Gtk.Notebook()
vbox.pack_start(nbook, True, True, 0)
nbook.show()
#Add Main tab
label = Gtk.Label()
label.set_markup("<b><big>Main</big></b>")
table = Gtk.Table(rows=40, columns=10)
#Add Results field
#results_box = Gtk.ScrolledWindow()
#results_box.set_vexpand(True)
#table.attach(results_box, 0, 1, 1, 39, xpadding=5, ypadding=5)
#Add Search box
entry = Gtk.Entry()
entry.set_property("secondary-icon-stock", Gtk.STOCK_FIND)
entry.connect("icon-press", self.on_search_button)
#entry.connect("activate", self.on_search_enter, results_box)
entry.connect("activate", self.on_search_enter, table)
table.attach(entry, 0, 1, 0, 1, xpadding=5)
nbook.append_page(table, label)
def on_search_button(self, entry, icon, event):
search = entry.get_text()
print("Search for " + search)
def on_search_enter(self, entry, table): #changed from results_box
store = Gtk.ListStore(str, str, str)
tree = Gtk.TreeView(store)
##
results_box = Gtk.ScrolledWindow()
results_box.set_vexpand(True)
table.attach(results_box, 0, 1, 1, 39, xpadding=5, ypadding=5)
##
search = entry.get_text()
search = search.replace("'","''") #deal with apostrophes
entry.set_text("")
print("Search for " + search)
result = self.lookup_player(search)
print result
if len(result) > 0:
for i in range(0, len(result)):
store.append([result[i][0],result[i][1],str(result[i][4])])
print result[i][0],result[i][1],result[i][2],result[i][3],result[i][4],result[i][5],result[i][6],result[i][7],result[i][8]
else:
print "No players found"
#Add column for last name
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Last Name")
column.pack_start(renderer, True)
column.add_attribute(renderer, "text", 0)
tree.append_column(column)
#Add column for first name
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("First Name")
column.pack_start(renderer, True)
column.add_attribute(renderer, "text", 1)
tree.append_column(column)
#Add column for icon
renderer = Gtk.CellRendererPixbuf()
column = Gtk.TreeViewColumn("Show")
column.pack_start(renderer, True)
column.add_attribute(renderer, "stock-id", 2)
tree.append_column(column)
results_box.add(tree)
table.show_all()
tree.show_all()
def on_click_edit(self, button):
print("Editing Player")
def lookup_player(self, pstring):
try:
con = psycopg2.connect(database='Rugby', user='postgres', password = '1234')
cur = con.cursor()
search = "select pl.lastname, pl.firstname, pl.height, pl.weight, to_char(pl.dob, 'DD/MM/YYYY'), cl.name, pl.injury_id, to_char(pl.suspendeduntil, 'DD/MM/YYYY'), pl.photo from player pl inner join club cl on cl.id = pl.currentclub_id where firstname ilike '%s' or lastname ilike '%s'" % (pstring, pstring)
cur.execute(search)
result = cur.fetchall()
return result
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
win = NotebookWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Note This is a follow-up question to
Python (GTK) : Can someone explain the difference between TreeStore, Listmodel and all the rest?
as the original query has been answered and the scope has thus changed (BTW massive thanks to everyone who helped with that!)
You should do everything you can in __init__(). This includes creating the store (as an instance variable so you can use it in the search handler), creating all widgets (ScrolledWindow and TreeView) and also adding the columns to the treeview.
In the search handler you should only call clear() on the ListStore (to remove any old results) and then append new results to the store.