My question is very similar to this post, Python PyQt - Checkbox to uncheck all other checkboxes. However, I am trying to check all other boxes when main checkbox is selected and at the same time, if any of the other boxes are selected independently, then I would like to deselect the main checkbox. I tried modifying the answer provided, but not able to put my head around the 'self.sender' signal. I am not able to change the selection when I deselect a checkbox. Here is the code that I modified using the solution provided by # eyllanesc.Any help is greatly appreciated, thanks!
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Test(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.checkBoxAll = QCheckBox("Select All")
self.checkBoxA = QCheckBox("Select A")
self.checkBoxB = QCheckBox("Select B")
self.checkBoxAll.setChecked(False)
self.checkBoxAll.stateChanged.connect(self.onStateChange)
self.checkBoxA.stateChanged.connect(self.onStateChange)
self.checkBoxB.stateChanged.connect(self.onStateChange)
grid = QGridLayout(self)
grid.addWidget(self.checkBoxAll, 1, 0)
grid.addWidget(self.checkBoxA, 2, 0)
grid.addWidget(self.checkBoxB, 3, 0)
self.setWindowTitle('Test')
self.show()
#pyqtSlot(int)
def onStateChange(self, state):
if state == Qt.Checked:
if self.sender() == self.checkBoxAll:
self.checkBoxA.setChecked(True)
self.checkBoxB.setChecked(True)
elif self.sender() in (self.checkBoxA, self.checkBoxB):
self.checkBoxAll.setChecked(False)
With the logic that you have you are creating a loop since the change of state of any element to change the state of another element, the idea is to block the emission of signals when the change of state is implemented in the slot with blockSignals():
from PyQt5 import QtCore, QtGui, QtWidgets
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.checkBoxAll = QtWidgets.QCheckBox("Select All")
self.checkBoxAll.setChecked(False)
self.checkBoxAll.stateChanged.connect(self.onStateChangePrincipal)
self.checkBoxA = QtWidgets.QCheckBox("Select A")
self.checkBoxB = QtWidgets.QCheckBox("Select B")
self.checkboxes = [self.checkBoxA, self.checkBoxB]
for checkbox in self.checkboxes:
checkbox.stateChanged.connect(self.onStateChange)
grid = QtWidgets.QGridLayout(self)
grid.addWidget(self.checkBoxAll, 1, 0)
grid.addWidget(self.checkBoxA, 2, 0)
grid.addWidget(self.checkBoxB, 3, 0)
self.setWindowTitle('Test')
#QtCore.pyqtSlot(int)
def onStateChangePrincipal(self, state):
if state == QtCore.Qt.Checked:
for checkbox in self.checkboxes:
checkbox.blockSignals(True)
checkbox.setCheckState(state)
checkbox.blockSignals(False)
#QtCore.pyqtSlot(int)
def onStateChange(self, state):
self.checkBoxAll.blockSignals(True)
self.checkBoxAll.setChecked(QtCore.Qt.Unchecked)
self.checkBoxAll.blockSignals(False)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.show()
sys.exit(app.exec_())
Related
I have a complex program in which I need to connect multiple windows. Unfortunately, I seem to be not fully understanding the concept/steps necessary to do this so bonus points if anyone can explain the steps/process well. In my current program, I have a list of items. Once I select them by moving them over to the right list widget, I need them to go to the third window. The third window should be activated by clicking the dots on the second window. The program runs and shows the second window appropriately but the signal/slot connection of the dots button does not work. However, the rest of the code is working because if I switch the toolkit to show the third window, that part is performing as expected. My code is below, and again, no errors are being returned, but clicking the dots button on the second window does nothing.
Also, a question - do I instantiate the third window within the second class, or only within the main window? Again, struggling to fully understand the process and I will need to do this multiple more times.
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QListWidget, QLineEdit, QTextEdit, QGridLayout, QHBoxLayout, QVBoxLayout, QSizePolicy, QFileDialog, QTabWidget, QCheckBox
import PyQt5.QtGui as qtg
import glob
import os
from PyQt5.QtCore import Qt, QSettings
import inspect
from PyQt5 import QtCore
import pandas as pd
import pathlib
import pyreadstat
import json
class ThirdWindow(QWidget):
def __init__(self):
super().__init__()
self.layout = QGridLayout()
self.setLayout(self.layout)
self.allVariables = QListWidget()
self.variablesSelected = QListWidget()
#self.allVariables.insertItem(0, 'Hello')
self.layout.addWidget(self.allVariables, 1,0)
self.layout.addWidget(self.variablesSelected, 1, 1)
def setItems(self, items):
self.allVariables.clear()
for item in items:
self.allVariables.addItem(item)
class SecondWindow(QWidget):
def __init__(self):
super().__init__()
##not sure if I am supposed to instantiate this here or only in the main window class
self.thirdWindow = ThirdWindow()
self.layout = QGridLayout(self)
self.by = QLabel("By")
self.byVariables = QLineEdit()
self.byButton = QPushButton("...")
self.layout.addWidget(self.by, 1, 0)
self.layout.addWidget(self.byVariables, 2, 0)
self.layout.addWidget(self.byButton, 2, 1)
def seconddWindowConnections(self):
self.byButton.clicked.connect(self.show_third_window)
#self.buttons['Toolkit'].clicked.connect(self.show_new_window)
def show_third_window(self):
self.thirdWindow.show()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# Add a title
self.setWindowTitle("GUI Querying Program")
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.initUI()
self.setButtonConnections()
self.sw = SecondWindow()
self.tw = ThirdWindow()
def initUI(self):
subLayouts = {}
subLayouts['LeftColumn'] = QGridLayout()
self.layout.addLayout(subLayouts['LeftColumn'],1)
# Buttons
self.buttons = {}
self.buttons['addVariable'] = QPushButton('>')
self.buttons['removeVariable'] = QPushButton('<')
self.buttons['Toolkit'] = QPushButton('Toolkit')
self.variables = QListWidget()
self.selectedVariables = QListWidget()
subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
names = ['apple', 'banana', 'Cherry']
self.variables.insertItems(0, names)
def setButtonConnections(self):
self.buttons['addVariable'].clicked.connect(self.add_variable)
self.buttons['Toolkit'].clicked.connect(self.show_new_window)
self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
def add_variable(self):
for item in self.variables.selectedItems():
self.selectedVariables.addItem(item.clone())
def show_new_window(self):
self.sw.show()
def add_selected_variables(self):
items = []
for i in range(self.selectedVariables.count()):
items.append(self.selectedVariables.item(i).clone())
self.tw.setItems(items)
if __name__ == "__main__":
import sys
app = QApplication([])
mw = MainWindow()
mw.show()
app.exec()
The main issue with your code is that secondWindowConnections is never called so the button actually does nothing. I corrected that and fixed a few other issues I found in my example below. I left out the bits where I made no changes and all the changes I did make I made inline notes explaining them:
class SecondWindow(QWidget):
def __init__(self):
super().__init__()
self.thirdWindow = None # dont initialize until neccessary
self.thirdWindowItems = []
self.layout = QGridLayout(self)
self.by = QLabel("By")
self.byVariables = QLineEdit()
self.byButton = QPushButton("...")
self.layout.addWidget(self.by, 1, 0)
self.layout.addWidget(self.byVariables, 2, 0)
self.layout.addWidget(self.byButton, 2, 1)
self.secondWindowConnections() # Run this to setup the
# signal for the third window.
def secondWindowConnections(self): # this had a typo
self.byButton.clicked.connect(self.show_third_window)
def show_third_window(self):
if self.thirdWindow is None: # if window has been created yet
self.thirdWindow = ThirdWindow() # create window
if not self.thirdWindow.isVisible(): # if window is showing
self.thirdWindow.show() # show window
self.thirdWindow.setItems(self.thirdWindowItems) # send items to window
def send_items(self, items): # this is to collect the variable that
self.thirdWindowItems = items # move to the third window
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# Add a title
self.setWindowTitle("GUI Querying Program")
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.initUI()
self.setButtonConnections()
self.sw = None # dont initialize until neccessary.
def initUI(self):
subLayouts = {}
subLayouts['LeftColumn'] = QGridLayout()
self.layout.addLayout(subLayouts['LeftColumn'],1)
self.buttons = {}
self.buttons['addVariable'] = QPushButton('>')
self.buttons['removeVariable'] = QPushButton('<')
self.buttons['Toolkit'] = QPushButton('Toolkit')
self.variables = QListWidget()
self.selectedVariables = QListWidget()
subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
names = ['apple', 'banana', 'Cherry']
self.variables.insertItems(0, names)
def setButtonConnections(self):
self.buttons['addVariable'].clicked.connect(self.add_variable)
self.buttons['Toolkit'].clicked.connect(self.show_new_window)
# self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
# only use one connnect slot
def add_variable(self):
for item in self.variables.selectedItems():
self.selectedVariables.addItem(item.clone())
def show_new_window(self):
if self.sw is None: # check if window has been constructed
self.sw = SecondWindow() # construct window
if not self.sw.isVisible(): # If winow is not showing
self.sw.show() # show window
self.sw.send_items(self.add_selected_variables()) # send selected
# variables to second window
def add_selected_variables(self):
items = []
for i in range(self.selectedVariables.count()):
items.append(self.selectedVariables.item(i).clone())
# self.tw.setItems(items) ... self.tw doesnt exist so return them
return items
In the default behavior of editing a cell in a QtableView, when the user clicks away either to another widget or closes the form, the edits are lost. After a lot of googling, I have found a way to save the edits if the user selects another widget in the form, but if the form is closed, the edits are still lost. The blog post is here.
I attempted to call the closeEditor method from the forms closeEvent, but it requires two parameters: the editor and hint. I can provide QAbstractItemDelegate.NoHint but the editor is expecting the QlineEdit object where the editing is taking place. I am lost on how to provide this for the cell currently being edited.
Here is a gif of the current behaviour:
My question is how do I provide the QlineEdit of the cell being edited?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *
from phones import *
class Main(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.resize(490, 998)
self.layoutWidget = QWidget(self)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.new_phone = QtWidgets.QPushButton(self.layoutWidget)
self.new_phone.setObjectName("new_phone")
self.new_phone.setText("New Phone")
self.horizontalLayout_7.addWidget(self.new_phone)
self.delete_phone = QtWidgets.QPushButton(self.layoutWidget)
self.delete_phone.setObjectName("delete_phone")
self.delete_phone.setText("Delete phone")
self.horizontalLayout_7.addWidget(self.delete_phone)
self.verticalLayout.addLayout(self.horizontalLayout_7)
self.phone_view = Syn_tableview()
self.verticalLayout.addWidget(self.phone_view)
self.cont_id = '9'
self.setCentralWidget(self.layoutWidget)
self.new_phone.clicked.connect(self.add_phone)
self.populate_phones()
def populate_phones(self):
self.phone_model = QSqlTableModel(self)
self.phone_model.setTable("contact_phones")
self.phone_model.setFilter("contact_id='{0}'".format(self.cont_id))
self.phone_model.select()
self.phone_view.setModel(self.phone_model)
self.phone_view.resizeColumnsToContents()
def add_phone(self):
self.phone_model.submitAll()
self.phone_model.setEditStrategy(QSqlTableModel.OnManualSubmit)
row = self.phone_model.rowCount()
record = self.phone_model.record()
record.setGenerated('id', False) #primary key
record.setValue('contact_id', self.cont_id) #foreign key
self.phone_model.insertRecord(row, record)
phone_index_edit = self.phone_model.index(row, self.phone_model.fieldIndex('phone_number'))
self.phone_view.edit(phone_index_edit)
def closeEvent(self, event):
submit = self.phone_model.submitAll()
#This is the problem
self.phone_view.closeEditor("QLineEdit", QAbstractItemDelegate.NoHint)
class Syn_tableview(QTableView):
def __init__(self, *args, **kwargs):
QTableView.__init__(self, *args, **kwargs)
def closeEditor(self, editor, hint):
if hint == QAbstractItemDelegate.NoHint:
QTableView.closeEditor(self, editor,
QAbstractItemDelegate.SubmitModelCache)
if __name__=="__main__":
app=QApplication(sys.argv)
db = QSqlDatabase.addDatabase("QPSQL");
db.setHostName(server)
db.setDatabaseName(database)
db.setUserName(user)
db.setPassword(pword)
myapp = Main()
myapp.show()
sys.exit(app.exec_())
The delegate editors are children of the QTableView so you can use findChildren to get them, to make sure they are not other children you can set an objectName that allows you to filter them:
import sys
from PyQt5 import QtCore, QtSql, QtWidgets
def create_connection():
db = QtSql.QSqlDatabase.addDatabase("QPSQL")
# FIXME
db.setHostName("server")
db.setDatabaseName("database")
db.setUserName("user")
db.setPassword("pword")
if not db.open():
print(db.lastError().text())
return False
return True
class Syn_Delegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(Syn_Delegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QWidget):
editor.setObjectName("syn_editor")
return editor
class Syn_Tableview(QtWidgets.QTableView):
def closeEditor(self, editor, hint):
if hint == QtWidgets.QAbstractItemDelegate.NoHint:
hint = QtWidgets.QAbstractItemDelegate.SubmitModelCache
super(Syn_Tableview, self).closeEditor(editor, hint)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.new_phone = QtWidgets.QPushButton(self.tr("New Phone"))
self.delete_phone = QtWidgets.QPushButton(self.tr("Delete phone"))
self.phone_view = Syn_Tableview()
self.phone_model = QtSql.QSqlTableModel()
self.phone_model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.phone_view.setModel(self.phone_model)
self.phone_view.resizeColumnsToContents()
delegate = Syn_Delegate(self)
self.phone_view.setItemDelegate(delegate)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self.new_phone, 0, 0)
lay.addWidget(self.delete_phone, 0, 1)
lay.addWidget(self.phone_view, 1, 0, 1, 2)
self._contact_id = "9"
self.populate_phones()
self.new_phone.clicked.connect(self.add_phone)
#property
def contact_id(self):
return self._contact_id
def populate_phones(self):
self.phone_model.setTable("contact_phones")
self.phone_model.setFilter("contact_id='{0}'".format(self.contact_id))
self.phone_model.select()
#QtCore.pyqtSlot()
def add_phone(self):
self.phone_model.submitAll()
row = self.phone_model.rowCount()
record = self.phone_model.record()
record.setGenerated("id", False) # primary key
record.setValue("contact_id", self.contact_id) # foreign key
self.phone_model.insertRecord(row, record)
phone_index_edit = self.phone_model.index(
row, self.phone_model.fieldIndex("phone_number")
)
if phone_index_edit.isValid():
self.phone_view.edit(phone_index_edit)
def closeEvent(self, event):
for editor in self.phone_view.findChildren(QtWidgets.QWidget, "syn_editor"):
self.phone_view.commitData(editor)
submit = self.phone_model.submitAll()
super().closeEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
if not create_connection():
sys.exit(-1)
w = MainWindow()
w.show()
w.resize(640, 480)
ret = sys.exit(app.exec_())
sys.exit(ret)
if __name__ == "__main__":
main()
I am trying to understand the way a QScrollArea is working to implement my own MyQScrollArea widget. MyQScrollArea should make use of setViewportMargins. For this I wrote a minimum working example shown below:
from PyQt5 import QtWidgets
import sys
class MyScrollArea(QtWidgets.QAbstractScrollArea):
def __init__(self):
super().__init__()
self.label = QtWidgets.QLabel(", ".join(map(str, range(100))), self)
hScrollBar = self.horizontalScrollBar()
hScrollBar.setRange(0, self.label.sizeHint().width() - self.sizeHint().width())
hScrollBar.valueChanged.connect(self._HScrollBarValueChanged)
self.setViewportMargins(100, 0, 0, 0)
self._HScrollBarValueChanged(0)
def _HScrollBarValueChanged(self, value):
self.label.move(-value + self.viewportMargins().left(), 0)
def main():
app = QtWidgets.QApplication(sys.argv)
scroll = MyScrollArea()
scroll.show()
app.exec_()
if __name__ == "__main__":
main()
The result of the code is shown below:
However, after I scroll the inner widget moves out of the viewport and paints itself in an area I do not want it to be painted:
What am I doing wrong and how can I get the setViewportMargins functionality working?
You have to set it the QLabel as a child of the viewport, in addition to modifying the properties of the QScrollBar every time the geometry of the widgets is modified:
import sys
from PyQt5 import QtWidgets
class MyScrollArea(QtWidgets.QAbstractScrollArea):
def __init__(self):
super().__init__()
self.label = QtWidgets.QLabel(", ".join(map(str, range(100))), self.viewport())
self.setViewportMargins(100, 0, 0, 0)
self.horizontalScrollBar().valueChanged.connect(
self.on_hscrollbar_value_changed
)
self.update_scrollbar()
def on_hscrollbar_value_changed(self, value):
self.label.move(-value, 0)
def update_scrollbar(self):
self.horizontalScrollBar().setRange(
0, self.label.sizeHint().width() - self.viewport().width()
)
self.horizontalScrollBar().setPageStep(self.viewport().width())
def resizeEvent(self, event):
self.update_scrollbar()
super().resizeEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
scroll = MyScrollArea()
scroll.show()
app.exec_()
if __name__ == "__main__":
main()
I am trying to make a list box where a user can enter more items to the list. I have a list box set up with an add button. The add button opens up a user input box where it will direct the user to enter a value. However, I am have issue with passing on the value of user input to the add onto the list. Any suggestions would help. Below is my code:
List box
from input_box import *
class list_form(QtGui.QWidget):
def __init__(self,list_of_items,open_text,parent= None):
super(list_form, self).__init__()
global output_path
output_path = output_path_i
grid = QtGui.QGridLayout()
grid.setSpacing(10)
self.widget = QtGui.QWidget()
self.layout = QtGui.QGridLayout(self.widget)
open_message = QtGui.QLabel(open_text)
grid.addWidget(open_message,0,0,2,4)
self.lst = QtGui.QListWidget()
grid.addWidget(self.lst,3, 0,1,4)
for i in list_of_items:
self.lst.addItem(str(i))
self.setLayout(grid)
add = QtGui.QPushButton('Add')
grid.addWidget(add,50,0)
add.clicked.connect(self.add_button)
def add_button(self):
self.input_box = input_box()
self.input_box.setWindowTitle("Window 2")
self.input_box.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = list_form(list(xrange(100)),"List of Values")
window.setWindowTitle('Window 1')
window.show()
sip.setdestroyonexit(False)
sys.exit(app.exec_())
Input box
import sys
from PyQt4 import QtCore, QtGui
import sip
class input_box(QtGui.QWidget):
def __init__(self,parent= None):
super(input_box, self).__init__()
grid = QtGui.QGridLayout()
grid.setSpacing(10)
self.widget = QtGui.QWidget()
self.layout = QtGui.QGridLayout(self.widget)
open_message = QtGui.QLabel("Enter Value:")
grid.addWidget(open_message,0,0,2,3)
self.txt = QtGui.QLineEdit()
grid.addWidget(self.txt,2, 0,1,2)
self.setLayout(grid)
save = QtGui.QPushButton('Save')
grid.addWidget(save,50,0)
a = save.clicked.connect(self.save)
save.clicked.connect(self.close)
cancel = QtGui.QPushButton('Cancel')
grid.addWidget(cancel,50,1)
cancel.clicked.connect(self.close)
def save(self):
value = self.txt.text()
return value
If you want to get data from a window you should use a QDialog instead of a QWidget, connect the clicked signal of save and cancel to the accept and reject slot, respectively:
input_box.py
from PyQt4 import QtCore, QtGui
class Input_Box(QtGui.QDialog):
def __init__(self,parent= None):
super(Input_Box, self).__init__(parent)
open_message = QtGui.QLabel("Enter Value:")
self.txt = QtGui.QLineEdit()
save = QtGui.QPushButton('Save', clicked=self.accept)
cancel = QtGui.QPushButton('Cancel', clicked=self.reject)
grid = QtGui.QGridLayout(self)
grid.setSpacing(10)
grid.addWidget(open_message, 0, 0)
grid.addWidget(self.txt, 1, 0, 1, 2)
grid.addWidget(save, 2, 0)
grid.addWidget(cancel, 2, 1)
self.setFixedSize(self.sizeHint())
def save(self):
value = self.txt.text()
return value
Then you use the exec_() method that returns a code if it is called accept or reject, and according to that the data must be obtained and added. On the other hand, do not use global variables because they are a headache when debugging.
from PyQt4 import QtCore, QtGui
from input_box import Input_Box
class list_form(QtGui.QWidget):
def __init__(self,list_of_items,open_text,parent= None):
super(list_form, self).__init__()
open_message = QtGui.QLabel(open_text)
self.lst = QtGui.QListWidget()
self.lst.addItems([str(i) for i in list_of_items])
add = QtGui.QPushButton('Add', clicked=self.add_button)
grid = QtGui.QGridLayout(self)
grid.setSpacing(10)
grid.addWidget(open_message)
grid.addWidget(self.lst)
grid.addWidget(add)
#QtCore.pyqtSlot()
def add_button(self):
input_box = Input_Box()
input_box.setWindowTitle("Window 2")
if input_box.exec_() == QtGui.QDialog.Accepted:
val = input_box.save()
it = QtGui.QListWidgetItem(val)
self.lst.addItem(it)
self.lst.scrollToItem(it)
if __name__ == "__main__":
import sys
import sip
app = QtGui.QApplication(sys.argv)
window = list_form(list(range(100)),"List of Values")
window.setWindowTitle('Window 1')
window.show()
sip.setdestroyonexit(False)
sys.exit(app.exec_())
The advantage of using QDialog is the decoupling between the classes, for example there is no need to pass a QListWidget as the other answer suggests making it possible that you can use the same dialog for other purposes.
You need to arrange for the action taken when the save button is pressed to pass information back to the list widget. There's more than one way to do it, but just returning the data won't get it done.
Here's an example of the sort of thing that will work - though other approaches are possible.
Change the input_box constructor so it keeps a reference to the list widget which it expects:
class input_box(QtGui.QWidget):
def __init__(self, list_widget, parent= None):
super(input_box, self).__init__()
self.list_widget = list_widget
...
Change the call to the constructor to provide that information:
def add_button(self):
self.input_box = input_box(self.lst)
self.input_box.setWindowTitle("Window 2")
self.input_box.show()
And then use that information in the save method to add to the list widget:
def save(self):
value = self.txt.text()
self.list_widget.addItem(value)
Bingo!
An alternative approach could be to arrange for the input_box to emit a signal with the new value in it, and connect that to a slot on the list_form, or on the list_widget. Or in the input_box you could navigate via its parent to the list_widget. But I think mine is simple and straightforward.
Here's my code. I'm trying to make it such that as you change the dropdown box, it will dynamically show more or less QLineEdits for input. This is just the latest iteration of testing
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,
QInputDialog, QApplication, QComboBox, QFrame)
import numpy as np
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
#
# Set up GUI
#
self.setGeometry(100, 100, 400, 400)
self.move(300, 300)
combobox = QComboBox(self)
for i in range(1, 10, 1):
combobox.addItem(str(i + 1))
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
frame = QWidget(self)
frame.hide()
for num in range(0, int(text), 1):
QLineEdit(frame).move(60, num * 19)
frame.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())
The problem is that when you pass a parent to a widget it is placed in the 0, 0 position with respect to the parent, in your case QFrame is on top of QComboBox since both are in the 0, 0 position. The proper thing is to use layouts. On the other hand you have to eliminate the widgets before adding new ones for it, we create a function that eliminates those items.
import sys
from PyQt5.QtWidgets import *
def clearLayout(lay):
while lay.count() > 0:
item = lay.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
del item
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
lay = QHBoxLayout(self)
vlay1 = QVBoxLayout()
combobox = QComboBox(self)
combobox.addItems([str(i) for i in range(2, 11)])
vlay1.addWidget(combobox)
vlay1.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
self.vlay2 = QVBoxLayout()
lay.addLayout(vlay1)
lay.addLayout(self.vlay2)
self.comboboxchanged(combobox.currentText())
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
clearLayout(self.vlay2)
for num in range(0, int(text)):
self.vlay2.addWidget(QLineEdit(self))
self.vlay2.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())