Pyqt - How to change combobox data because of another combobox data? - python

I have a table, with 4 columns.
Two of this 4 columns are about features. One is Feature, another is subfeature.
in each column, there are comboboxes for all cells.
I can open txt in these cells.
I want to: when I choose cinema for feature, I want to see only name of films in subfeature comboboxes and no every subfeature that I have in my "data"... and when I choose Food in feature, I want to see only types of food in my subfeature comboboxes...
.. I dont know how to do it... there is a way to do it?
Here there is my def to put combobox in table and open the text file into these comboboxes:
def createEd(self, parent, option, index):
if index.column() == POLARITY:
combobox = QComboBox(parent)
combobox.addItems(sorted(index.model().TPolarities))
combobox.setEditable(True)
arquivo = codecs.open("ln2.txt",encoding='utf-8',mode="r")
conTWordsdo = arquivo.readlines()
lista =[]
for i in conTWordsdo:
lista.append(i.replace("\n",""))
combobox.addItems(sorted(lista))
return combobox
elif index.column() == FEATURE:
combobox = QComboBox(parent)
combobox.addItems(sorted(index.model().TFeatures))
combobox.setEditable(True)
arquivo = codecs.open("ln1.txt",encoding='utf-8',mode="r")
conTWordsdo = arquivo.readlines()
lista = []
for i in conTWordsdo:
lista.append(i.replace("\n",""))
combobox.addItems(sorted(lista))
return combobox
elif index.column() == SUBFEATURE:
combobox = QComboBox(parent)
combobox.addItems(sorted(index.model().TSubFeatures))
combobox.setEditable(True)
arquivo = codecs.open("ln3.txt",encoding='utf-8',mode="r")
conTWordsdo = arquivo.readlines()
lista = []
for i in conTWordsdo:
lista.append(i.replace("\n",""))
combobox.addItems(sorted(lista))
return combobox
elif index.column() == SENTENCE:
editor = QLineEdit(parent)
self.connect(editor, SIGNAL("returnPressed()"), self.commitAndCloseEditor)
return editor
else:
return QItemDelegate.createEditor(self, parent, option, index)

You'll be using the currentIndexChanged signal, something like this:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.items = dict(zip(
[ "Parent {0}".format(x)
for x in range(3)
],
[
[ "Child {0} - {1}".format(x, y)
for y in range(3)
]
for x in range(3)
]
))
self.comboBoxChild = QtGui.QComboBox(self)
self.comboBoxParent = QtGui.QComboBox(self)
self.comboBoxParent.addItems(self.items.keys())
self.comboBoxParent.currentIndexChanged[str].connect(self.on_comboBoxParent_currentIndexChanged)
self.comboBoxParent.setCurrentIndex(1)
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.comboBoxParent)
self.layoutVertical.addWidget(self.comboBoxChild)
#QtCore.pyqtSlot(str)
def on_comboBoxParent_currentIndexChanged(self, index):
items = self.items[str(index)]
self.comboBoxChild.clear()
self.comboBoxChild.addItems(items)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
main.resize(222, 111)
sys.exit(app.exec_())

Related

How to select rows on QTableWidget and return the value to the QLineEdit

I want to make that when i click on particular cell on the QTableWidget it will block the corresponding rows and I want to return the value of each row selected into the QLineEdit.
I couldnt seem to find the solution my code only return when i click it will block the rows but not getting the value.
def click_inventorytable(self):
self.tableInventory.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
index = (self.tableInventory.selectionModel().currentIndex())
value = index.row()
list = [value]
if(len(list)==6):
self.lineproductnameinv.setText((list[1]))
self.linedescinv.setText((list[2]))
self.combocateinv.setText((list[3]))
self.linepriceinv.setText((list[4]))
self.linecurrentstock.setText((list[5]))
self.addstock.setText('')
Since the OP does not provide an MRE then I will create a simple demo of how you can implement the functionality of mapping the elements of the selected row of a table in various widgets.
The appropriate widgets must be chosen so that the user does not enter incorrect values, for example in the case of stock if a QLineEdit is used the user could enter a word which does not make sense since a number is expected so it is better to use a QSpinBox.
Also when the data is saved in the table it is not good to convert it to a string since it loses the way to differentiate them, it is better to save the value through setData() associated with the Qt::DisplayRole role.
Finally, the key to the solution is to use a QDataWidgetMapper that allows mapping parts of a model in widgets, so each time a row is selected the currentIndex of the mapper is updated and it sends the information to the editors.
from functools import cached_property
import random
import sys
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
LABELS = (
"Product ID",
"Product Name",
"Description",
"Category",
"Price",
"Stock",
)
CATEGORY_OPTIONS = (
"OPTION1",
"OPTION2",
"OPTION3",
"OPTION4",
)
def __init__(self, parent=None):
super().__init__(parent)
self.mapper.setModel(self.tableWidget.model())
self.tableWidget.selectionModel().currentChanged.connect(
self.mapper.setCurrentModelIndex
)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QHBoxLayout(central_widget)
flay = QtWidgets.QFormLayout()
lay.addLayout(flay)
lay.addWidget(self.tableWidget, stretch=1)
editors = (
self.name_edit,
self.description_edit,
self.category_combo,
self.price_edit,
self.stock_edit,
)
for i, (label, widget) in enumerate(zip(self.LABELS[1:], editors)):
flay.addRow(label, widget)
self.mapper.addMapping(widget, i)
self.fillTable()
self.resize(960, 480)
#cached_property
def tableWidget(self):
table = QtWidgets.QTableWidget(
0,
len(self.LABELS),
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
selectionMode=QtWidgets.QAbstractItemView.SingleSelection,
)
table.setHorizontalHeaderLabels(self.LABELS)
return table
#cached_property
def name_edit(self):
return QtWidgets.QLineEdit()
#cached_property
def description_edit(self):
return QtWidgets.QLineEdit()
#cached_property
def category_combo(self):
combo = QtWidgets.QComboBox()
combo.addItems(["--Null--"] + list(self.CATEGORY_OPTIONS))
combo.setCurrentIndex(0)
return combo
#cached_property
def price_edit(self):
return QtWidgets.QDoubleSpinBox(maximum=2147483647)
#cached_property
def stock_edit(self):
return QtWidgets.QSpinBox(maximum=2147483647)
#cached_property
def mapper(self):
return QtWidgets.QDataWidgetMapper()
def fillTable(self):
self.tableWidget.setRowCount(0)
for i in range(30):
self.tableWidget.insertRow(self.tableWidget.rowCount())
values = (
i,
f"name-{i}",
f"Description-{i}",
random.choice(self.CATEGORY_OPTIONS),
random.uniform(100, 2000),
random.randint(0, 100),
)
for j, value in enumerate(values):
it = QtWidgets.QTableWidgetItem()
it.setData(QtCore.Qt.DisplayRole, value)
it.setFlags(it.flags() & ~QtCore.Qt.ItemIsEditable)
self.tableWidget.setItem(i, j, it)
def main():
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()

How can I check or uncheck QStandrdItem's check box in "PySide2 QStandardItemModel" with mouse click and drag?

what I need in this case is "uncheck or check" the items in QListView with mouse hold and press
I've added Items with check boxes , I need to change the state of the items (check or uncheck) for multi items with just press and hold , like making multi selection .
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class items_List(QListView):
clicked = pyqtSignal()
def __init__(self,items):
QListView.__init__(self)
#self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.model = QStandardItemModel()
self.setModel(self.model)
self.model.itemChanged.connect(self.on_itemChanged)
self.items = items
self.add_items_(self.items)
self.show()
def add_items_(self,all_items=None):
self.active_items = []
if all_items == None:
return
for item in all_items:
#self.model.appendRow(str(i))
self.item = QStandardItem(str(item))
self.item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)
self.item.setData(QVariant(Qt.Checked), Qt.CheckStateRole)
self.model.appendRow(self.item)
self.active_items.append(str(item))
def selected_item(self):
print "Selected "
#pyqtSlot(QStandardItem)
def on_itemChanged(self, item):
state = ['UNCHECKED', 'TRISTATE', 'CHECKED'][item.checkState()]
if state == 'UNCHECKED':
self.active_items.remove(item.text())
else:
if item.text() not in self.active_items:
self.active_items.append(str(item.text()))
print self.active_items
def main():
app = QApplication(sys.argv)
items = [1001,1002,1003,1004,1005]
win = items_List(items)
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Expanding QTreeView Item From ModelIndex [duplicate]

This question already has an answer here:
How to expand top-level QTreeview items
(1 answer)
Closed 3 years ago.
How can I expand a QTreeView item knowing it's modelIndex. I'm trying to call the following piece of code and it doesn't throw any errors but it does not expand the treeview item...
parentIndex = self.categoryModel.indexFromItem(parent)
if parentIndex.isValid():
self.uiTreeView.setExpanded(parentIndex, True)
To test, select the first item in the list and click the Add button. When a user adds a new category i want it to expand the item it's being added to.
import os, sys
from Qt import QtWidgets, QtGui, QtCore
################################################################################
# Widgets
################################################################################
class CategoryView(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.resize(250,400)
self.uiAdd = QtWidgets.QPushButton('Add')
self.categoryModel = QtGui.QStandardItemModel()
self.categoryModel.setHorizontalHeaderLabels(['Items'])
self.categoryProxyModel = QtCore.QSortFilterProxyModel()
self.categoryProxyModel.setSourceModel(self.categoryModel)
self.categoryProxyModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.categoryProxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.categoryProxyModel.setDynamicSortFilter(True)
self.uiTreeView = QtWidgets.QTreeView()
self.uiTreeView.setModel(self.categoryProxyModel)
self.uiTreeView.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.uiTreeView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.layout = QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.layout.setSpacing(0)
self.layout.addWidget(self.uiAdd)
self.layout.addWidget(self.uiTreeView)
self.setLayout(self.layout)
# Selections
self.categorySelection = self.uiTreeView.selectionModel()
# Signals
self.uiAdd.clicked.connect(self.slotAddNewCategory)
parent = self.categoryModel.invisibleRootItem()
parent.appendRow(QtGui.QStandardItem('Fruit'))
# Methods
def getSelectedItems(self):
items = []
for proxyIndex in self.categorySelection.selectedIndexes():
sourceIndex = self.categoryProxyModel.mapToSource(proxyIndex)
item = self.categoryModel.itemFromIndex(sourceIndex)
items.append(item)
return items
def slotAddNewCategory(self):
text, ok = QtWidgets.QInputDialog.getText(self, 'Input Dialog', 'Enter your name:')
if ok:
item = QtGui.QStandardItem(text)
parent = self.categoryModel.invisibleRootItem()
items = self.getSelectedItems()
if len(items) == 1:
parent = items[0]
parent.appendRow(item)
parentIndex = self.categoryModel.indexFromItem(parent)
print parentIndex.data()
if parentIndex.isValid():
self.uiTreeView.setExpanded(parentIndex, True)
################################################################################
# Unit Testing
################################################################################
def test_CategoryView():
app = QtWidgets.QApplication(sys.argv)
ex = CategoryView()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
pass
test_CategoryView()
# test_PainterSettingsDialog()
Answer found here... How to expand top-level QTreeview items
parentIndex = self.categoryModel.indexFromItem(parent)
px = self.categoryProxyModel.mapFromSource(parentIndex)
if parentIndex.isValid():
self.uiTreeView.setExpanded(px, True)

PyQt working with wizard and radio button

I made this wizard containing a radio button. When it is clicked, the finish button should return a list of radio buttons that were checked as text!
The input (it's virtual input for readability)
data=[['a','b','c'],['e','f'],['g','f']]
data1 = ['one','two','three']
this is my code
from PyQt4 import QtGui, QtCore
def page3arg(x, n):
page = QtGui.QWizardPage()
page.setTitle("{}".format(x))
page.setSubTitle("Please choose one of these state.")
rd1 = QtGui.QRadioButton(page)
rd2 = QtGui.QRadioButton(page)
rd3 = QtGui.QRadioButton(page)
layout = QtGui.QGridLayout()
layout.addWidget(rd1, 2, 0)
layout.addWidget(rd2, 2, 1)
layout.addWidget(rd3, 2, 2)
rd1.setText(' {}'.format(n[0]))
rd2.setText(' {}'.format(n[1]))
rd3.setText(' {}'.format(n[2]))
page.setLayout(layout)
return page
def page2arg(x, n):
page = QtGui.QWizardPage()
page.setTitle("{}".format(x))
page.setSubTitle("Please choose one of these state.")
rd1 = QtGui.QRadioButton(page)
rd2 = QtGui.QRadioButton(page)
layout = QtGui.QGridLayout()
layout.addWidget(rd1, 2, 0)
layout.addWidget(rd2, 2, 1)
rd1.setText(' {}'.format(n[0]))
rd2.setText(' {} .'.format(n[1]))
page.setLayout(layout)
return page
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
wizard = QtGui.QWizard()
wizard.setStyleSheet(("font:50 10pt \"MS Shell Dlg 2\";"))
for m in range(len(data1) - 1):
x = data1[m]
n= data[m]
if len(n) == 3:
page3 = page3arg(x, n)
wizard.addPage(page3)
elif len(n) == 2:
page2 = page2arg(x, n)
wizard.addPage(page2)
wizard.show()
sys.exit(wizard.exec_())
How do I write a function that will get the selections of the radio buttons in the end as list.
The list of radio button selections should look like this:
output = ['a','e','g']
If you want to get radiobutton checked, then a simple solution is to associate it with a QButtonGroup for each page and use the checkedButton() function to get the option checked. And to know when you press the finish button you must use the button() function of QWizard and connect it to a slot.
Also it is not necessary to have 2 functions that do the same as page3arg and page2arg, I have reduced it in a generalized function for n arguments
from PyQt4 import QtCore, QtGui
class Wizard(QtGui.QWizard):
def __init__(self, parent=None):
super(Wizard, self).__init__(parent)
datas = [["a", "b", "c"], ["e", "f"], ["g", "f"]]
titles = ["one", "two", "three"]
self.setStyleSheet(('font:50 10pt "MS Shell Dlg 2";'))
self.groups = []
for title, options in zip(titles, datas):
page, group = Wizard.create_page(title, options)
self.addPage(page)
self.groups.append(group)
self.button(QtGui.QWizard.FinishButton).clicked.connect(
self.on_finished
)
self._results = []
#property
def results(self):
self.get_options()
return self._results
def get_options(self):
self._results = []
for group in self.groups:
button = group.checkedButton()
if button is not None:
self._results.append(button.text())
#QtCore.pyqtSlot()
def on_finished(self):
print("finished", self.results)
#staticmethod
def create_page(title, options):
page = QtGui.QWizardPage()
group = QtGui.QButtonGroup(page)
page.setTitle(title)
page.setSubTitle("Please choose one of these state.")
hlay = QtGui.QHBoxLayout(page)
for option in options:
radiobutton = QtGui.QRadioButton(text=option)
group.addButton(radiobutton)
hlay.addWidget(radiobutton)
return page, group
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
wizard = Wizard()
wizard.show()
ret = app.exec_()
print("outside clas", wizard.results)
sys.exit(ret)
Try to put all radio buttons in a list, and for each radio button in the list, get it's text and insert it to your output list.
For example,
lst = []
lst.append(rd1)
lst.append(rd2)
lst.append(rd3)
output = []
for val in lst:
output.append(val.text())

PyQt5 managing a cluster of buttons without having to write cases for each individual one

I'm trying to create a layout where the user can click a combination of buttons, each button's click will add a 1 or a 0 to a certain position in a list which is the actual input I'd like to get out of it.
However, I don't know how to manage a cluster of buttons, there are 48 buttons and managing them all individually is the antithesis of DRY.
Here's an example attempt:
num_buttons = 48
press_list = [None]*len(num_buttons)
button_list = list()
for button in range(num_buttons):
some_btn = QtWidgets.QPushButton(SomeDialog)
some_btn.setGeometry(QtCore.QRect(70, 90, 141, 28))
some_btn.setObjectName("button_%s" % (button,))
some_btn.clicked.connect(self.button_pressed(button))
def button_pressed(self, button_num):
if press_list[button_num] == 1:
press_list[button_num] = 0
else:
press_list[button_num] = 1
(clicks turn buttons blue), is it possible to have a set geometry through the Qt designer and still do something like this, or will I have to calculate the setGeometry positions and add the buttons through the code?
If you want to pass an additional argument to the slots you can use partial as shown below:
import sys
from functools import partial
from PyQt5 import QtWidgets
QSS = """
QToolButton::checked{
background-color: blue
}
"""
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.listA = [0 for _ in range(24)]
self.listB = [0 for _ in range(24)]
lay = QtWidgets.QVBoxLayout(self)
hlay1 = QtWidgets.QHBoxLayout()
hlay2 = QtWidgets.QHBoxLayout()
lay.addLayout(hlay1)
lay.addLayout(hlay2)
for i, val in enumerate(self.listA):
button = QtWidgets.QToolButton()
button.setCheckable(True)
hlay1.addWidget(button)
button.clicked.connect(partial(self.callbackA, i))
button.setStyleSheet(QSS)
for i, val in enumerate(self.listB):
button = QtWidgets.QToolButton()
button.setCheckable(True)
hlay2.addWidget(button)
button.clicked.connect(partial(self.callbackB, i))
button.setStyleSheet(QSS)
def callbackA(self, index, state):
self.listA[index] = 1 if state else 0
print("listA: ")
print(self.listA)
def callbackB(self, index, state):
self.listB[index] = 1 if state else 0
print("listB: ")
print(self.listB)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Categories

Resources