I set the number of spinboxes in the previous window and then, according to the code below, they are added in the next window, but when I click the button, I need to pick up the value from each generated spinbox, but at the moment the value is transmitted only from the last one.
How do I get the value from each spinbox?
Thank you!
class CreateSpuWindow(QMainWindow):
def __init__(self, value):
super().__init__()
uic.loadUi('ui/statement_spu_1.ui', self)
self.value = value # Quantity pf spinBoxes
for i in range(value):
self.spu_label = QLabel(self)
self.spu_label.setText(f"SPU №{i+1}. PP:")
self.quantity_pp = QSpinBox(self)
self.quantity_pp.setValue(1)
self.quantity_pp.setMinimum(1)
self.gridLayout_2.addWidget(self.spu_label, 2 * i, 0)
self.gridLayout_2.addWidget(self.quantity_pp, 2 * i, 1)
self.next_tu_spu_2Button.clicked.connect(self.next_wind_spu_btn)
self.back_btn.clicked.connect(self.back_btn_cl)
def next_wind_spu_btn(self):
data = []
# Get a value from spinbox
for i in str(self.quantity_pp.value()):
data.append(i)
print(data)
quantity_spu = self.value
self.ReadyTableSpuWindow = ReadyTableSpuWindow(quantity_spu)
self.ReadyTableSpuWindow.show()
self.close()
def back_btn_cl(self):
self.close()
self.QuantitySpuWindow = QuantitySpuWindow()
self.QuantitySpuWindow.show()
Related
I've seen questions similar to this one but they are aimed at QTableView. This is not using that,, this is just for a dropdown (QComboBox) with a custom QAbstractTableModel, which needs to have 2 columns.
BIG UPDATE
(Note: Legacy code has been deleted as this is a better approach on the same question, and legacy code was confusing as hell).
Okay, so trying to catch up with what #eyllanesc explained, I changed this from a QAbstractListModel to a QAbstractTableModel. The result is:
class ModelForComboboxesWithID(QAbstractTableModel):
"""Create our basic model"""
def __init__(self, program, records):
super(ModelForComboboxesWithID, self).__init__()
self._data = records
self.program = program
self.path_images = program.PATH_IMAGES
def rowCount(self, index: int = 0) -> int:
"""The length of the outer list. Structure: [row, row, row]"""
if not self._data:
return 0 # Doubt: Do we need to return this if self._data is empty?
return len(self._data)
def columnCount(self, index: int = 0) -> int:
"""The length of the sub-list inside the outer list. Meaning that Columns are inside rows
Structure: [row [column], row [column], row [column]]"""
if not self._data:
return 0 # Doubt: Do we need to return this if self._data is empty?
return len(self._data[0])
def data(self, index, role=None):
"""return the data on this index as data[row][column]"""
# 1 - Display data based on its content (this edits the text that you visually see)
if role == Qt.DisplayRole:
value = self._data[index.row()][index.column()]
return value
# 2 - Tooltip displayed when hovering on it
elif role == Qt.ToolTipRole:
return f"ID: {self._data[index.row()][1]}"
Which I set this way:
def eventFilter(self, target, event: QEvent):
if event.type() == QEvent.MouseButtonPress:
if target == self.Buscadorcombo_cliente:
records = ... # my query to the database
set_combo_records_with_ids(self.program, target, records)
target.currentIndexChanged.connect(self.test)
def set_combo_records_with_ids(program, combobox: QComboBox, records):
"""Clear combobox, set model/data and sort it"""
combobox.clear()
model = ModelForComboboxesWithID(program, records)
combobox.setModel(model)
combobox.model().sort(0, Qt.AscendingOrder)
combobox.setModelColumn(0)
The result of this works almost perfect:
On the dropdown(Combobox) it displays the name.
If you hover on an item, it displays the ID.
Now I am able to get any data of it this way.
def test(self, index):
data_id = self.Buscadorcombo_cliente.model().index(index, 1).data()
data_name = self.Buscadorcombo_cliente.model().index(index, 0).data()
print(data_id)
print(data_name)
You have to set a QTableView as a view:
from PySide2 import QtGui, QtWidgets
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
combo = QtWidgets.QComboBox()
model = QtGui.QStandardItemModel(0, 2)
for i in range(10):
items = []
for j in range(model.columnCount()):
it = QtGui.QStandardItem(f"it-{i}{j}")
items.append(it)
model.appendRow(items)
combo.setModel(model)
view = QtWidgets.QTableView(
combo, selectionBehavior=QtWidgets.QAbstractItemView.SelectRows
)
combo.setView(view)
view.verticalHeader().hide()
view.horizontalHeader().hide()
header = view.horizontalHeader()
for i in range(header.count()):
header.setSectionResizeMode(i, QtWidgets.QHeaderView.Stretch)
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(combo)
lay.addStretch()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I am having issues with .deleter where the values I am trying to delete only works for the first try.
To replicate:
Checked 'GrpB-Alice' and hit 'Click Me' (Do not close the window yet)
i.myDict returns {u'GrpB': set([u'Alice'])}) which is correct
Checked 'GrpB-Phan' and hit 'Click Me'
i.myDict returns {u'GrpB': set([u'Alice', 'Phan])}) which is correct
Checked 'GrpB-Alice' and hit 'Click Me'
i.myDict returns {u'GrpB': set([u'Alice', 'Phan])}) which is incorrect where I am expecting {u'GrpB': set([u'Alice'])})
If I close the tool, and redo the last step, only will i.myDict returns correctly, but should I checked on new options, at the third time, i.myDict will returns incorrect result again.
The deleter is definitely being called but it only seems to execute the real deletion once though. Am I missing something here?
class SubMenuWindow(QtGui.QWidget):
def __init__(self, menu_items, parent=None, callback=None):
super(SubMenuWindow, self).__init__(parent)
self.callback = callback
self.my_lyt = QtGui.QVBoxLayout()
self.checked_options = []
self.sel = defaultdict(set)
for menu_name, submenu_name in menu_items.items():
# Set the main menu item name
self.groupbox = QtGui.QGroupBox(self)
self.groupbox.setTitle(menu_name)
self.groupbox.setLayout(QtGui.QVBoxLayout())
self.my_lyt.addWidget(self.groupbox)
if submenu_name:
sub_txt = [action for action in submenu_name]
for s in sub_txt:
sub_chk = QtGui.QCheckBox(s)
self.checked_options.append(sub_chk)
self.groupbox.layout().addWidget(sub_chk)
apply_tag_btn = QtGui.QPushButton('Apply to selected item')
apply_tag_btn.clicked.connect(self.get_checked_options)
self.my_lyt.addWidget(apply_tag_btn)
self.my_lyt.addStretch()
self.setLayout(self.my_lyt)
self.show()
def get_checked_options(self):
for chk in self.checked_options:
if chk.isChecked():
print 'Checked - {0}, Parent - {1}'.format(chk.text(), chk.parent().title())
self.sel[chk.parent().title()].add(chk.text())
if self.callback:
self.callback()
class MainWin(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWin, self).__init__(parent)
self.my_dict = {}
btnA = QtGui.QPushButton('Click Me')
btnA.clicked.connect(self.get_options)
btnB = QtGui.QPushButton('Get results')
btnB.clicked.connect(self.get_results)
layout = QtGui.QVBoxLayout()
layout.addWidget(btnA)
layout.addWidget(btnB)
self.setLayout(layout)
def get_options(self):
sample_dict = {'GrpA' : ['John', 'Zack'], 'GrpB' : ['Alice', 'Phan']}
self.subWin = SubMenuWindow(sample_dict, callback=self.get_results)
def get_results(self):
i = MyDict()
# delete any existing values
del (i.myDict)
# append the new values
i.myDict = self.subWin.sel
print 'current myDict values : ', i.myDict
# If I select 'GrpB - Alice'
# i.myDict is `{u'GrpB': set([u'Alice'])})` # correct
# If I select 'GrpB - Alice' and 'GrpB - Phan'
# i.myDict is `{u'GrpB': set([u'Alice', 'Phan'])})` # correct
# If I re-select 'GrpB - Alice'
# i.myDict is `{u'GrpB': set([u'Alice', 'Phan'])})` # in-correct
class MyDict(QtCore.QObject):
def __init__(self):
self._myDict = None
#property
def myDict(self):
return self._myDict
#myDict.setter
def myDict(self, value):
self._myDict = value
#myDict.deleter
def myDict(self):
del(self._myDict)
Code:
class Example(QtGui.QWidget):
def __init__(self, parent):
super(Accounts, self).__init__()
self.initUI()
def initUI(self):
self.table = QtGui.QTableWidget()
self.table.setColumnCount(5)
database = 'Setting.db'
connection = sqlite3.connect(database)
cursor = connection.cursor()
cursor.execute('''
SELECT ID, User, Text
FROM Data ''')
data = cursor.fetchall()
num = 0
for row in data:
self.table.setRowCount(num+2)
self.table.setItem(num, 0, QtGui.QTableWidgetItem(str(row[0])))
self.table.setItem(num, 1, QtGui.QTableWidgetItem(str(row[1])))
self.table.setItem(num, 2, QtGui.QTableWidgetItem(str(row[2])))
self.table.setCellWidget(num, 3, Perms(self, row[0]))
save_user = QtGui.QPushButton("Save")
save_user.clicked.connect(self.save)
self.table.setCellWidget(num, 5, save_user)
num= num+1
main_layout = QtGui.QGridLayout()
main_layout.addWidget(self.table)
self.setLayout(main_layout)
def save(self):
button = self.sender()
index = self.table.indexAt(button.pos())
row = index.row()
a_id = str(self.table.item(row, 0).text())
data = Permissions(self, a_id).update_database()
class Perms(QtGui.QWidget):
def __init__(self, parent, a_id):
super(Perms, self).__init__()
self.a_id = a_id
self.init_ui()
def init_ui(self):
database = 'Settings.db'
conn = sqlite3.connect(database)
cursor = conn.cursor()
cursor.execute('''
SELECT control, sub
FROM Perms
WHERE ID= ?''', (self.a_id,))
row = cursor.fetchone()
control_label = QtGui.QLabel("Control")
sub_label = QtGui.QLabel("Sub")
self.control_options = QtGui.QComboBox()
self.control_options.addItem("Y")
self.control_options.addItem("N")
if str(row[0]) == "Y":
self.control_options.setCurrentIndex(0)
else:
self.control_options.setCurrentIndex(1)
self.sub_options = QtGui.QComboBox()
self.sub_options.addItem("Y")
self.sub_options.addItem("N")
if str(row[1]) == "Y":
self.sub_options.setCurrentIndex(0)
else:
self.sub_options.setCurrentIndex(1)
layout = QtGui.QGridLayout()
layout.addWidget(full_control_label, 1, 1)
layout.addWidget(self.full_control_options, 1, 2)
layout.addWidget(tills_label, 2, 1)
layout.addWidget(self.tills_options, 2, 2)
self.setLayout(layout)
def update_database(self):
control = str(self.control_options.currentText())
sub = str(self.sub_options.currentText())
return (control, sub)
Ignore any errors I don't specify because I wrote this quickly just for an example. The problem I'm facing is: the save button is created within the loop in order to be used multiple times. It connects to a function that gets the current text of the combo-boxes. But the problem is, if you change the current text in the combo-boxes and then click Save, it gets the text from the combo-boxes, but not the right text - you always get the same result.
For example:
QComboBox1: Y
QComboBox2: N
If we click Save, it'll return ('Y', 'N')
If we change the combobox values:
QComboBox1: N
QComboBox2: N
and click save, it'll return ('Y', 'N')
But it never returns the new values from the combo-boxes.
How can I fix it so I get the updated values rather than the old values?
The save method doesn't currently make much sense. Surely you need to get the Perm widget from the table, not make a new one every time:
def save(self):
button = self.sender()
index = self.table.indexAt(button.pos())
row = index.row()
# get the new values from the table
data = self.table.cellWidget(row, 3).update_database()
I've built a class for item selection with Tkinter Spinbox. I'd like to return the index of the selected item. Is that possible?
from Tkinter import *
class TestSpin():
def __init__(self, i_root, i_friendlist):
self.root = i_root
self.root.friend = Spinbox(self.root, values = i_friendlist)
self.root.friend.pack()
self.root.okbutton = Button(self.root, text='Ok', command = lambda: self.ack())
self.root.okbutton.pack()
def ack(self):
# here I'd like to have the index of selected item in friendlist
print "Index of "+self.root.friend.get()+" is [0 or 1 or 2]:", self.root.friend
# here I'd like to have the index of selected item in friendlist
self.root.destroy()
root = Tk()
list = ['Emma','Sarah','James']
app = TestSpin(root, list)
root.mainloop()
Thanks a lot for your advice. I tried self.root.friend.index(), but that method wants an argument which I do not understand.
There's no way to directly get the value from the widget, but it's just one line of python code:
index = i_fiendlist.index(self.root.friend.get())
Using your code, you need to save the value of the list:
class TestSpin():
def __init__(self, i_root,i_friendlist):
self._list = i_list
...
def ack(self):
value = self.root.friend.get()
index = self._list.index(value)
print "Index of " + value + " is " + str(index)
self.root.destroy()
Background:
I have two separate QTableWidgets on my Main Window. Both of which are dynamically added in python. I have implemented pyqt code, which can be found under three_pineapples solution here.
My Problem
I want to be able to drag and drop table rows from one table, to another. For example:
If I attempt to drag Item B from the Left Table into the Right Table
This would be the outcome
Any suggestions on how to get this desired behavior?
I took a look at the #three_pineapples' code, didn't understand a half and deleted that half. Works with multiple row selection.
import sys
from PyQt4.QtGui import *
class TableWidgetDragRows(QTableWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setDragDropOverwriteMode(False)
# self.setSelectionMode(QAbstractItemView.SingleSelection)
self.last_drop_row = None
# Override this method to get the correct row index for insertion
def dropMimeData(self, row, col, mimeData, action):
self.last_drop_row = row
return True
def dropEvent(self, event):
# The QTableWidget from which selected rows will be moved
sender = event.source()
# Default dropEvent method fires dropMimeData with appropriate parameters (we're interested in the row index).
super().dropEvent(event)
# Now we know where to insert selected row(s)
dropRow = self.last_drop_row
selectedRows = sender.getselectedRowsFast()
# Allocate space for transfer
for _ in selectedRows:
self.insertRow(dropRow)
# if sender == receiver (self), after creating new empty rows selected rows might change their locations
sel_rows_offsets = [0 if self != sender or srow < dropRow else len(selectedRows) for srow in selectedRows]
selectedRows = [row + offset for row, offset in zip(selectedRows, sel_rows_offsets)]
# copy content of selected rows into empty ones
for i, srow in enumerate(selectedRows):
for j in range(self.columnCount()):
item = sender.item(srow, j)
if item:
source = QTableWidgetItem(item)
self.setItem(dropRow + i, j, source)
# delete selected rows
for srow in reversed(selectedRows):
sender.removeRow(srow)
event.accept()
def getselectedRowsFast(self):
selectedRows = []
for item in self.selectedItems():
if item.row() not in selectedRows:
selectedRows.append(item.row())
selectedRows.sort()
return selectedRows
class Window(QWidget):
def __init__(self):
super().__init__()
layout = QHBoxLayout()
self.setLayout(layout)
self.table_widgets = []
for _ in range(3):
tw = TableWidgetDragRows()
tw.setColumnCount(2)
tw.setHorizontalHeaderLabels(['Colour', 'Model'])
self.table_widgets.append(tw)
layout.addWidget(tw)
filled_widget = self.table_widgets[0]
items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle')]
for i, (colour, model) in enumerate(items):
c = QTableWidgetItem(colour)
m = QTableWidgetItem(model)
filled_widget.insertRow(filled_widget.rowCount())
filled_widget.setItem(i, 0, c)
filled_widget.setItem(i, 1, m)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())