QLineEdit dont want to save changes :( - python

stackoverflow!
It's my first question, I was just a reader before
I'm trying to make an app in python using PyQt5: I need to get data from DB into a table, every row has an EDIT button, when you push it, fields of the row become editable and you can change the data and the EDIT button changes to SAVE button. When you push it , data should be saved and be sent to database(I didn't made a "commit to DB" function yet) but its not saving and comes to previous amounts every time I click SAVE.
When I click EDIT button, it takes a cell text and than replace the widget in a cell by the same , but editable version(just change an option to EDITABLE = TRUE is not working), and it makes it for the whole row.
The save button should make the same, but it makes cells UNEDITABLE again...
tell me why it is so?
my function on SAVE button is
def ButtonSaveClicked(self):
s = self.sender()
roww = int((s.text().split())[1]) - 1
print('SAVE')
# replacing the existing active widgets by inactive with a same text
q = self.ui.tableWidget.item(roww, 0).text()
self.ui.btn_sell = QtWidgets.QLineEdit(q)
self.ui.btn_sell.setEnabled(False)
self.ui.tableWidget.setCellWidget(roww, 0, self.ui.btn_sell)
q = self.ui.tableWidget.item(roww, 1).text()
print(q)
self.ui.btn_sell = QtWidgets.QLineEdit(q)
self.ui.btn_sell.setEnabled(False)
self.ui.tableWidget.setCellWidget(roww, 1, self.ui.btn_sell)
q = self.ui.tableWidget.item(roww, 2).text()
print(q)
self.ui.btn_sell = QtWidgets.QLineEdit(q)
self.ui.btn_sell.setEnabled(False)
self.ui.tableWidget.setCellWidget(roww, 2, self.ui.btn_sell)
self.ui.btn_sell = QtWidgets.QPushButton("Edit " +str(roww+1))
self.ui.btn_sell.setEnabled(True)
self.ui.tableWidget.setCellWidget(roww, 3, self.ui.btn_sell)
self.ui.btn_sell.clicked.connect(self.ButtonEditClicked)
enter image description here

I will attempt to answer your question, but I think you may also want to consider the following alternative:
You can set your table to have Edit Triggers instead of you needing to keep track of the state of a QPushButton and keep replacing items and copying data back and forth between them.
My suggestion would be to use the QAbstractItemView::DoubleClicked edit trigger and you can apply that to your QTableWidget like this:
self.tableWidget.setSelectionBehavior(QAbstractItemView::SelectItems)
self.tableWidget.setSelectionMode(QAbstractItemView::SingleSelection)
self.tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked)
If the user double clicks on a cell, that cell becomes editable.
setSelectionBehavior() lets you choose whether you want each cell, row or column to be selected when clicked.
setSelectionMode() determines whether one (cell,row,column) or many (cells,rows,columns) can be selected at once. I think in your case you want to select one cell at a time.
This way the user can double click the cells they wish to edit and then you can have a "Save" button at the bottom of the widget which saves all the changes.
I will try to reproduce your problem above, but I wanted to bring this functionality to your attention as it may save you a lot of headaches.

Related

How do I communicate between two dash layouts (on Python)? How do I transfer saved/stored data from one layout to the other (main) layout?

(My first question and post here)
Here's my situation:
I have to program a data displaying software on Python dash/plotly. And I am stuck at the part where I have to transfer data from one page of my app.py to the other one (for now offline). Both two Dash layout pages are defined in app.py. The structure is basically the same like the one the third example code in that dash/plotly docu page (https://dash.plotly.com/urls), so I have url_bar_and_content_div defined and assigned to app.layout, and I have layout_page1 and layout_page2, as well as app.validation_layout in which all these layouts are listed in the *html.Div()... *
(I can't show concrete code because it's for my internship)
I am able to redirect from page 1 to page 2, right now I'm coding the Divs and callbacks of page 2. On page 2, I want to submit and store data of any file I work with, preferably in a pd.DataFrame or in a dict. And I'm picturing it more or less, that I use an html.Button() to "Submit", which after being clicked finally saves the data, "transfers" it to page 1 and redirects the user to page 1 too. And so here's where I am stuck now: How do I transfer that saved/submitted data to layout_page_1? How do I even make page 2 store and submit data in a df or smth using callbacks to begin with?? I know that using global variables in callbacks is not possible, and I have also ofc looked at the dash docu page for this matter (https://dash.plotly.com/sharing-data-between-callbacks). It hasn't really helped me though, like I didn't know where I should approach my issue with this information, and I also didn't really understand many things. I have never used the dcc.Store()-component before, I am not a pro/expert at Python programming, and this is my first internship in which I am working with Dash for the first time...
So how do I approach this problem? Do I have to add dcc.Store() to both layout-Divs? Do they have to have the same id, must they have to be named "memory","local" or "session", or is it irrelevant? How would I "connect" those two Store-components then, how can I make these two layouts "communicate" with each other and enable smooth data transition from page 2 to page 1 and vice versa??
I'd be so much thankful if someone here would help me out on this, I hope I'll get a response soon, because I have to finish that task in a few weeks. Thanks in advance and cheers!
Edit: #PeterWood Alright, so again, I'll explain what I have to do and I'll use some code to illustrate my problem better!
I have my main app program which I always execute, and it contains the following layouts:
app = dash.Dash(__name__)
url_bar_and_content_div = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
]) # just like in https://dash.plotly.com/urls
layout_page1 = html.Div([ ...
,html.Div(id="data-display",
children=[],...),
"""this is basically the place where the data from page 2 should be loaded (no plot, just saved text and value information)
"""
])
layout_page2 = html.Div([
...
dcc.Textarea(id,...),
dash_table.DataTable( id=...,... ), # contains values and data which I want to work with/save
html.Button(id,...children='Submit', ....) # the Submit Button
...
])
# index layout
app.layout = url_bar_and_content_div
# complete layout
app.validation_layout = html.Div([
url_bar_and_content_div,
layout_page1,
layout_page2
])
# **Again** , the layout-structure is the **same** as that one in the 3rd code example in https://dash.plotly.com/urls
# callbacks etc.
So page 2 consists of a DataTable which mainly consists of text descriptions and values (of many types, str, float, int, NaN etc.). Whenever I click on a line/row on the DataTable, its text gets displayed on the Textarea-field above. And when I click on the "Submit"-button, all the displayed text and values should then be finally "saved" and somehow redirected to page 1 and displayed on the 'data-display'-component (see code again).
My question: How do I do that? How do I program a temporary df which saves text from layout_page2 and displays it on layout_page1?
Here the callback which does the data display on dcc.Textarea when a not-empty DataTable-cell gets clicked:
#app.callback([Output('textarea-p2','value'), # the Text-block where the text from DataTable gets shown
Output('datatable-p2','selected_cells'),
Output('datatable-p2','active_cell')]
[Input('datatable-p2','active_cell')],
[State('datatable-p2','data'),
State('textarea-p2','value')])
def update_data_display(active_cell, data_cells, displayed_text):
if dash.callback_context.triggered[0]['prop_id'].split('.')[0] == 'datatable-p2':
...
if not pd.isnull(data_cells[row][col]):
content = text on that 'row' of DataTable + '\n' # work with active_cells and a df = pd.DataFrame(data_cells)
...
displayed_text += content
return displayed_text, [], None
#"[], None" so that every time I click on a cell it gets unmarked again, just for clarification
What should I change on that callback update_data_display for the next step of sending the Text-block-data to 'data-display' on page 1?
And also how should my callback on the "Submit"-button look like then?
Should both of my layout_pagex have a dcc.Store()-component? So how do I proceed with it now?

How to refresh or update frame after value changes in text file using Python/Tkinter

So basically I am reading a valuefrom a text file which is displayed on the Profile frame using a label.
def view_value(self):
self.user = self.controller.user
self.view_value()
with open(self.user + '.txt', "r") as f:
value_line = 2
for i, line in enumerate(f):
if i == value_line:
self.value.set(line)
self.value.config(textvariable=line)
When I go to a different frame to calculate this value again, it will update the text file with the newly calculated value. However, when I go back to the previous page using the back button - the old value is still there. To get the new value to appear I need to reopen/re-run the program.
Is it possible to have the newly updated value displayed on the page without restarting the application? I have tried calling my view_value method to try and update the value and also tried configuring the label from the other class but wasn't able to get it working.
I also realise there are probably a million things wrong with my code, I am very new to Python so apologies!
You need to update the StringVar Profile.allowance in order to make the display in Profile page updated. The simple way is adding the following statement before self.controller.show_frame(Profile) in write_to_file() of CalculateAllowance class:
self.controller.frames[Profile].allowance.set(self.user_data[2])
Also you need to fix the following issues in your code:
Remove calling self.view_allowance() inside view_allowance() in Profile class as it will cause infinite recursion problem.
Remove self.holiday_allowance_amount.config(textvariable=line) in view_allowance() as it wrongly reassigns textvariable to a string.

Recovering checkboxes in python Tkinter

I have a situation in which i create a few checkboxes and a 'save' button on a frame. Clicking on the button will save the current 'check status' of the checkboxes and close the frame (the frame has another frame as it's parent). The 'check status' is stored in a list in a separate .py file.
There's another button, clicking on which would i would want to restore those same check values on the check boxes. I am not sure what approach is proper here: whether to save the checkbox objects itself and load them or to create new checkboxes every time and apply the check status values on them.
This issue has taken up quite some time of mine as i am new to the python GUI concept, any help would be much appreciated.
P.S: if any details are required to make the question more clear kindly let me know.
EDIT: here's a small representation of what i have tried:
#file that generates the checkboxes (part of a bigger code)
var_list=[] #list of the variables of the checkbox objects
load_status = savedata.load() #fetch the saved status list from another file, if it exists
if len(load_status)!=0: #if the checkboxes have already been created before
for count in range(len(var_list)):
if load_status[count] == 0:
var_list[count].set(0) #set/apply the values from the status list
else:
var_list[count].set(1)
return
def check(var_list):
check_status_list=[]
for i in range(len(var_list)):
c = var_list[i].get()
check_status_list.append(c) #the status of the checkboxes that is stored in another file
var = IntVar()
var_list.append(var)
poll_check = ttk.Checkbutton(parent,variable=rr,command=lambda:check(var_list))
poll_check.place(x=x1,y=y1)
x1=x1+15
when i click on the save button the status list (check_status_list) is stored in another file. On clicking the third button ('load') i fetch the status list first and (try to) set the values on the already exsting checkbox objects.
Kindly feel free to point out the (obviously) silly mistake that this approach has.

Retrieving cell data from a selected cell in a tablewidget

I am making a stock control program and i have hit a problem with getting the value of a selected cell, i know i need to use "QtGui.QTableWidget.currentRow" and "QtGui.QTableWidget.currentColumn" to get the item's position. However i cannot seem to get this to work because when the functions are called nothing has been selected and so it returns -1,-1
Does anyone know how to get it so it runs the "QtGui.QTableWidget.currentRow" and "QtGui.QTableWidget.currentColumn" everytime the user selects a cell?
i think the code i need to get the actual data once i have the co-ords is QtGui.QTableWidget.item ?
This is the code i am using to get the row and column:
row = self.table.currentRow
column = self.table.currentColumn
self.ID = self.table.item(row, column)
when the user clicks a button to add stock the program should then use the product code it will have just got to make the change to the database after getting the quantity added from the user
I am using python 3.2 and pyqt 4
any help would be appreciated
Thank you
Sam
When the QTableWidget sees that someone has clicked one of it's cells, it will emit a cellClicked event - which you need to connect to. Maybe something like
self.table.cellClicked.connect(self.cell_was_clicked)
could be in your setup code,
and the function cell_was_clicked might be something like
def cell_was_clicked(self, row, column):
print("Row %d and Column %d was clicked" % (row, column))
item = self.table.itemAt(row, column)
self.ID = item.text()
I've not used currentRow and currentColumn as you want a response on the click. This function is documented here (sorry, I prefer pyside - it's pretty much the same as PyQT). Note also itemAt instead of just item - as you will get the item at the cell, not it's contents. Use the .text() function of QTableWidgetItem to get at the contents.
Note - this is using 'slots and signals' and in particular the 'new style'. As you're using PyQT4 and Python 3 you should have no trouble with 'new stuff' :-)
You might consider browsing a slots and signals tutorial - that might straighten a few of these abstract concepts out. Good luck!
here is the code that worked for me:
def get_selected_cell_value():
current_row = self.sold_items_details_table.currentRow()
current_column = self.sold_items_details_table.currentColumn()
cell_value = table.item(current_row, current_column).text()

PyGTK: Doubleclick on CellRenderer

In my PyGTK application I currently use 'editable' to make cells editable. But since my cell contents sometimes are really really large I want to ask the user for changes in a new window when he doubleclicks on a cell. But I could not find out how to hook on double-clicks on specific cellrenderers - I don't want to edit the whole row and I also don't want to set this callback for the whole row, only for columns where too long content can occur. How can I do this with CellRendererText() or something similar.
My currently cell-generating code is:
cols[i] = gtk.TreeViewColumn(coltitle)
cells[i] = gtk.CellRendererText()
cols[i].pack_start(cells[i])
cols[i].add_attribute(cells[i], 'text', i)
cols[i].set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
cols[i].set_fixed_width(100)
cells[i].set_property('editable', True)
cells[i].connect('edited', self.edited, (i, ls))
cols[i].set_resizable(True)
mytreeview.append_column(cols[i])
Thanks!
I believe this is not possible directly. However, you can connect to button-press-event on the gtk.TreeView. Then, when event.type equals to gtk.gdk._2BUTTON_PRESS, convert x and y to tree location using gtk.TreeView.get_path_at_pos(). This will return both a tree path indicating the row and gtk.TreeViewColumn object on which the click was made.

Categories