Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #70: add methods to remove widgets from forms #93

Merged
merged 29 commits into from
Oct 30, 2023
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2d4672f
Add function to hide widgets
DanicaSTFC Oct 11, 2023
d629b40
Add function to remove widgets
DanicaSTFC Oct 11, 2023
00f5793
Remove widgets with name and getWidget
DanicaSTFC Oct 11, 2023
b4c7402
Example shows 3 widgets and they are removed by the user
DanicaSTFC Oct 11, 2023
f8b6715
RemoveWidget added to class FormDockWidget and UIFormWidget
DanicaSTFC Oct 12, 2023
cbd2341
Remove spanning widget functionality
DanicaSTFC Oct 13, 2023
241775c
Fix dictionary and add example for FormDockWidget
DanicaSTFC Oct 13, 2023
9c21e2c
Add title to FormDockWidget
DanicaSTFC Oct 13, 2023
50faf7f
Remove function substitute from deleteLater to removeRow
DanicaSTFC Oct 16, 2023
224ffe3
Add unit test remove every widget
DanicaSTFC Oct 16, 2023
538006e
Add unit test to remove widget with layout input
DanicaSTFC Oct 16, 2023
eb778a1
Fix total number of widgets in the form after widget is removed
DanicaSTFC Oct 17, 2023
bc243ee
Add method extract number of widgets in the forms
DanicaSTFC Oct 17, 2023
a8d3e6b
Layout add in the setup and unit test accomodated for layout and widg…
DanicaSTFC Oct 17, 2023
8b5cfa2
Add layout's number of rows assertion in the unit test
DanicaSTFC Oct 17, 2023
7145548
Merge branch 'main' of github.com:TomographicImaging/eqt into remove-…
DanicaSTFC Oct 17, 2023
c60c400
Change some comments
DanicaSTFC Oct 17, 2023
d52886b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 17, 2023
da4a3ff
Change some comments
DanicaSTFC Oct 17, 2023
5d6f16d
Automatic changes merged
DanicaSTFC Oct 17, 2023
d178dcb
Implement suggestions from pre-commit
DanicaSTFC Oct 17, 2023
9cc30b7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 17, 2023
dd08bba
Resolve failures in pre-commit
DanicaSTFC Oct 17, 2023
5f18d2d
Resolve failures in pre-commit
DanicaSTFC Oct 17, 2023
5aad99a
Changes for review 1 --- partial --- extra file for example method
DanicaSTFC Oct 27, 2023
2dbb657
Buttons in example grey when widgets removed
DanicaSTFC Oct 27, 2023
3bd2de7
Improve comments editing
DanicaSTFC Oct 27, 2023
3a5add0
Changes from pre-commit run
DanicaSTFC Oct 27, 2023
4ce5d53
Add text for Ok and Cancel and run pre-commit
DanicaSTFC Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions eqt/ui/FormDialog.py
Original file line number Diff line number Diff line change
@@ -74,6 +74,14 @@ def addWidget(self, qwidget, qlabel=None, name=None, layout='form'):
else:
raise ValueError(f"layout '{layout}' unrecognised: expected 'form' or 'vertical'")

def removeWidget(self, name):
'''
Removes a widget (and its label if present) from the layout.
Decreases the counter for the number of widgets in the layout.
Deletes the field (and label) from the dictionary.
'''
self.formWidget.removeWidget(name)

def addSpanningWidget(self, qwidget, name=None, layout='form'):
'''
Adds a spanning widget to the layout.
@@ -93,6 +101,12 @@ def addSpanningWidget(self, qwidget, name=None, layout='form'):
raise ValueError(
f"layout {layout} is not recognised, must be set to 'form' or 'vertical'")

def getNumWidgets(self):
'''
Returns the number of widgets in the form.
'''
return self.formWidget.getNumWidgets()

def insertWidget(self, index, qwidget):
'''inserts a widget to the vertical layout at the specific index'''
self.formWidget.uiElements['verticalLayout'].insertWidget(index, qwidget)
41 changes: 41 additions & 0 deletions eqt/ui/UIFormWidget.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from PySide2 import QtWidgets

from .UISliderWidget import UISliderWidget
@@ -55,6 +57,28 @@ def addSpanningWidget(self, qwidget, name):
def addWidget(self, qwidget, qlabel, name):
self._addWidget(name, qwidget, qlabel)

def removeWidget(self, name):
'''
Removes a widget (and its label if present) from the layout.
Decreases the counter for the number of widgets in the layout.
Deletes the field (and label) from the dictionary.
'''
formLayout = self.uiElements['groupBoxFormLayout']
qwidget = self.getWidget(name, role='field') # retrieves the widget from its name
formLayout.removeRow(qwidget) # removes the whole row from the layout
self.num_widgets -= 1 # updates total number of widgets
self.getWidgets().pop(name + '_field') # removes field from the dictionary
try:
self.getWidgets().pop(name + '_label')
except KeyError:
logging.info('Widget ' + name + ' does not have a label.')

def getNumWidgets(self):
'''
Returns the number of widgets in the form.
'''
return self.num_widgets

def getWidget(self, name, role='field'):
'''returns the Widget by the name with which it has been added

@@ -322,6 +346,23 @@ def __init__(self, parent=None, title=None):
def addWidget(self, qwidget, qlabel, name):
self.widget().addWidget(qwidget, qlabel, name)

def addSpanningWidget(self, qwidget, name):
self.widget().addSpanningWidget(qwidget, name)

def removeWidget(self, name):
'''
Removes a widget (and its label if present) from the layout.
Decreases the counter for the number of widgets in the layout.
Deletes the field (and label) from the dictionary.
'''
self.widget().removeWidget(name)

def getNumWidgets(self):
'''
Returns the number of widgets in the form.
'''
return self.widget().getNumWidgets()

def getWidget(self, name, role='field'):
'''returns the Widget by the name with which it has been added

130 changes: 130 additions & 0 deletions examples/remove_widgets_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import sys

from PySide2 import QtWidgets

from eqt.ui import FormDialog, UIFormWidget


class MainUI(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)

# create a FormDockWidget
dock = UIFormWidget.FormDockWidget(parent=self)
dock.setWindowTitle('Example remove widget')
self.addWidgetsToExampleForm(dock)

# add a button to dock to remove user selected widget
buttonuser = QtWidgets.QPushButton(dock)
buttonuser.setText("Remove user selected widget")
dock.addSpanningWidget(buttonuser, 'Button Remove User')
buttonuser.clicked.connect(lambda: self.remove(dock, buttonuser))

# create button for Form Dialog
pb = QtWidgets.QPushButton(self)
pb.setText("Open Form Dialog")
pb.clicked.connect(lambda: self.openFormDialog())

# create window layout
layout = QtWidgets.QHBoxLayout()
layout.addWidget(pb)
layout.addWidget(dock)
widg = QtWidgets.QWidget()
widg.setLayout(layout)
self.setCentralWidget(widg)

# print dictionary of all widgets in dock
print("\nDictionary of widgets in the Form Dock Widget:\n" + str(dock.getWidgets()))

self.show()

def openFormDialog(self):
dialog = FormDialog(parent=self, title='Example remove widget')
dialog.Ok.clicked.connect(lambda: self.remove(dialog, dialog.Ok))
self.addWidgetsToExampleForm(dialog)
dialog.addSpanningWidget(
QtWidgets.QLabel(
"Press `Ok` to remove the user selected widget and `Cancel` to close the dialog:"),
'ok_cancel_instructions')

# store a reference
self.dialog = dialog
self.dialog.onCancel = self.rejected

# print dictionary of all widgets in dialog
print("Dictionary of widgets in Form Dialog:\n" + str(self.dialog.getWidgets()))

dialog.open()

def addWidgetsToExampleForm(self, form):

# add widget 1 as QLineEdit
qlabel = QtWidgets.QLabel(form)
qlabel.setText("Widget 1: ")
qwidget = QtWidgets.QLineEdit(form)
qwidget.setClearButtonEnabled(True)
form.addWidget(qwidget, qlabel, 'Widget 1')

# add widget 2 as QLineEdit
qlabel = QtWidgets.QLabel(form)
qlabel.setText("Widget 2: ")
qwidget = QtWidgets.QLineEdit(form)
qwidget.setClearButtonEnabled(True)
form.addWidget(qwidget, qlabel, 'Widget 2')

# add widget 3 as QLineEdit
qlabel = QtWidgets.QLabel(form)
qlabel.setText("Widget 3: ")
qwidget = QtWidgets.QLineEdit(form)
qwidget.setClearButtonEnabled(True)
form.addWidget(qwidget, qlabel, 'Widget 3')

# add input as QComboBox
form.addSpanningWidget(QtWidgets.QLabel("Pick the widget you want to remove:"),
'input_title')
qlabel = QtWidgets.QLabel(form)
qlabel.setText("User input: ")
qwidget = QtWidgets.QComboBox(form)
qwidget.addItem("Widget 2")
qwidget.addItem("Widget 3")
qwidget.setCurrentIndex(0)
qwidget.setEnabled(True)
form.addWidget(qwidget, qlabel, 'userinput')

# add a button to remove widget 1
button1 = QtWidgets.QPushButton(form)
button1.setText("Remove widget 1")
form.addSpanningWidget(button1, 'Button Remove w1')
button1.clicked.connect(lambda: self.remove(form, button1, 'Widget 1'))

# add a button to remove spanning widget
buttonspanning = QtWidgets.QPushButton(form)
buttonspanning.setText("Remove spanning widget")
form.addSpanningWidget(buttonspanning, 'Button Remove Spanning')
buttonspanning.clicked.connect(lambda: self.remove(form, buttonspanning, 'input_title'))

def rejected(self):
print("\nDialog closed.")

def remove(self, form, button, userselection=False):
if userselection is False:
userselection = form.getWidget('userinput').currentText()
form.getWidget('userinput').removeItem(form.getWidget('userinput').currentIndex())
print("\nRemove " + userselection)
form.removeWidget(userselection)
if form.getWidget('userinput').currentIndex() == -1:
button.setEnabled(False)
if button == form.getWidget('Button Remove w1') or button == form.getWidget(
'Button Remove Spanning'):
button.setEnabled(False)

print("\nDictionary of widgets after deletion of " + userselection + ":\n" +
str(form.getWidgets()))


if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)

window = MainUI()

sys.exit(app.exec_())
34 changes: 34 additions & 0 deletions test/test__formUI_status_test.py
Original file line number Diff line number Diff line change
@@ -39,6 +39,37 @@ def add_two_widgets(self):
form.addWidget(QtWidgets.QLabel('test label'), 'Label: ', 'label')
form.addWidget(QtWidgets.QCheckBox('test checkbox'), 'CheckBox: ', 'checkBox')

def _test_remove_one_widget(self, name):
"""
Remove one widget.
Checks the number of widgets in the form before and after deletion are consistent.
Checks the number of rows in the layout and number of widgets in the form are
consistent.

name: name in the dictionary of the widget to be removed
"""
qwidget = self.form.getWidget(name, role='field')
rowpre, role = self.layout.getWidgetPosition(qwidget) # checks the widget exists
prerowcount = self.layout.rowCount()
predictionary = self.form.getWidgets().copy()
prenumwidgets = self.form.getNumWidgets()
self.form.removeWidget(name)
postrowcount = self.layout.rowCount()
postdictionary = self.form.getWidgets()
postnumwidgets = self.form.getNumWidgets()
self.assertNotEqual(predictionary, postdictionary)
self.assertEqual(prenumwidgets, postnumwidgets + 1)
self.assertEqual(prerowcount, postrowcount + 1)
self.assertEqual(postrowcount, postnumwidgets)

def test_remove_every_widget(self):
"""Remove every widget from `self.form`"""
list_widgets = [
'label', 'checkBox', 'comboBox', 'doubleSpinBox', 'spinBox', 'slider',
'uiSliderWidget', 'radioButton', 'textEdit', 'plainTextEdit', 'lineEdit', 'button']
for name in list_widgets:
self._test_remove_one_widget(name)

def test_getWidgetState_returns_visibility(self):
"""
Check that the visibility of the widget is saved to the state
@@ -295,6 +326,7 @@ def setUp(self):
self.add_every_widget()
self.simple_form = FormDialog()
self.add_two_widgets()
self.layout = self.form.formWidget.uiElements['groupBoxFormLayout']

def test_getWidgetState_returns_QLabel_value(self):
"""Check that the value of the QLabel is saved to the state"""
@@ -369,6 +401,7 @@ def setUp(self):
self.add_every_widget()
self.simple_form = FormWidget()
self.add_two_widgets()
self.layout = self.form.uiElements['groupBoxFormLayout']

def test_getWidgetState_returns_QLabel_value(self):
"""Check that the value of the QLabel is saved to the state"""
@@ -443,6 +476,7 @@ def setUp(self):
self.add_every_widget()
self.simple_form = FormDockWidget()
self.add_two_widgets()
self.layout = self.form.widget().uiElements['groupBoxFormLayout']

def test_getWidgetState_returns_QLabel_value(self):
"""Check that the value of the QLabel is saved to the state"""