Address Book Example#
The address book example shows how to use proxy models to display different views onto data from a single model.
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import Qt, Slot
from PySide6.QtWidgets import (QApplication, QGridLayout,
QHBoxLayout, QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._next_button = QPushButton("&Next")
self._next_button.setEnabled(False)
self._previous_button = QPushButton("&Previous")
self._previous_button.setEnabled(False)
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._cancel_button.clicked.connect(self.cancel)
self._next_button.clicked.connect(self.next)
self._previous_button.clicked.connect(self.previous)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button, Qt.AlignTop)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addStretch()
button_layout_2 = QHBoxLayout()
button_layout_2.addWidget(self._previous_button)
button_layout_2.addWidget(self._next_button)
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
main_layout.addLayout(button_layout_2, 3, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._next_button.setEnabled(False)
self._previous_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
@Slot()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
@Slot()
def cancel(self):
self._name_line.setText(self._old_name)
self._address_text.setText(self._old_address)
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
@Slot()
def next(self):
name = self._name_line.text()
it = iter(self.contacts)
try:
while True:
this_name, _ = it.next()
if this_name == name:
next_name, next_address = it.next()
break
except StopIteration:
next_name, next_address = iter(self.contacts).next()
self._name_line.setText(next_name)
self._address_text.setText(next_address)
@Slot()
def previous(self):
name = self._name_line.text()
prev_name = prev_address = None
for this_name, this_address in self.contacts:
if this_name == name:
break
prev_name = this_name
prev_address = this_address
else:
self._name_line.clear()
self._address_text.clear()
return
if prev_name is None:
for prev_name, prev_address in self.contacts:
pass
self._name_line.setText(prev_name)
self._address_text.setText(prev_address)
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (QApplication, QGridLayout, QLabel, QLineEdit,
QTextEdit, QWidget)
class AddressBook(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
name_label = QLabel("Name:")
self._name_line = QLineEdit()
address_label = QLabel("Address:")
self._address_text = QTextEdit()
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import Qt, Slot
from PySide6.QtWidgets import (QApplication, QDialog, QGridLayout,
QHBoxLayout, QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
NavigationMode, AddingMode, EditingMode = range(3)
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
self._current_mode = self.NavigationMode
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._edit_button = QPushButton("&Edit")
self._edit_button.setEnabled(False)
self._remove_button = QPushButton("&Remove")
self._remove_button.setEnabled(False)
self._find_button = QPushButton("&Find")
self._find_button.setEnabled(False)
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._next_button = QPushButton("&Next")
self._next_button.setEnabled(False)
self._previous_button = QPushButton("&Previous")
self._previous_button.setEnabled(False)
self.dialog = FindDialog()
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._edit_button.clicked.connect(self.edit_contact)
self._remove_button.clicked.connect(self.remove_contact)
self._find_button.clicked.connect(self.find_contact)
self._cancel_button.clicked.connect(self.cancel)
self._next_button.clicked.connect(self.next)
self._previous_button.clicked.connect(self.previous)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button)
button_layout_1.addWidget(self._edit_button)
button_layout_1.addWidget(self._remove_button)
button_layout_1.addWidget(self._find_button)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addStretch()
button_layout_2 = QHBoxLayout()
button_layout_2.addWidget(self._previous_button)
button_layout_2.addWidget(self._next_button)
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
main_layout.addLayout(button_layout_2, 2, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
@Slot()
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self.update_interface(self.AddingMode)
@Slot()
def edit_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self.update_interface(self.EditingMode)
@Slot()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if self._current_mode == self.AddingMode:
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._current_mode == self.EditingMode:
if self._old_name != name:
if name not in self.contacts:
QMessageBox.information(self, "Edit Successful",
f'"{self.oldName}" has been edited in your '
'address book.')
del self.contacts[self._old_name]
self.contacts[name] = address
else:
QMessageBox.information(self, "Edit Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._old_address != address:
QMessageBox.information(self, "Edit Successful",
f'"{name}" has been edited in your address book.')
self.contacts[name] = address
self.update_interface(self.NavigationMode)
@Slot()
def cancel(self):
self._name_line.setText(self._old_name)
self._address_text.setText(self._old_address)
self.update_interface(self.NavigationMode)
@Slot()
def remove_contact(self):
name = self._name_line.text()
if name in self.contacts:
button = QMessageBox.question(self, "Confirm Remove",
f'Are you sure you want to remove "{name}"?',
QMessageBox.Yes | QMessageBox.No)
if button == QMessageBox.Yes:
self.previous()
del self.contacts[name]
QMessageBox.information(self, "Remove Successful",
f'"{name}" has been removed from your address book.')
self.update_interface(self.NavigationMode)
@Slot()
def next(self):
name = self._name_line.text()
it = iter(self.contacts)
try:
while True:
this_name, _ = it.next()
if this_name == name:
next_name, next_address = it.next()
break
except StopIteration:
next_name, next_address = iter(self.contacts).next()
self._name_line.setText(next_name)
self._address_text.setText(next_address)
@Slot()
def previous(self):
name = self._name_line.text()
prev_name = prev_address = None
for this_name, this_address in self.contacts:
if this_name == name:
break
prev_name = this_name
prev_address = this_address
else:
self._name_line.clear()
self._address_text.clear()
return
if prev_name is None:
for prev_name, prev_address in self.contacts:
pass
self._name_line.setText(prev_name)
self._address_text.setText(prev_address)
def find_contact(self):
self.dialog.show()
if self.dialog.exec() == QDialog.Accepted:
contact_name = self.dialog.get_find_text()
if contact_name in self.contacts:
self._name_line.setText(contact_name)
self._address_text.setText(self.contacts[contact_name])
else:
QMessageBox.information(self, "Contact Not Found",
f'Sorry, "{contact_name}" is not in your address book.')
return
self.update_interface(self.NavigationMode)
def update_interface(self, mode):
self._current_mode = mode
if self._current_mode in (self.AddingMode, self.EditingMode):
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._edit_button.setEnabled(False)
self._remove_button.setEnabled(False)
self._next_button.setEnabled(False)
self._previous_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
elif self._current_mode == self.NavigationMode:
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._edit_button.setEnabled(number >= 1)
self._remove_button.setEnabled(number >= 1)
self._find_button.setEnabled(number > 2)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
class FindDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
find_label = QLabel("Enter the name of a contact:")
self._line_edit = QLineEdit()
self._find_button = QPushButton("&Find")
self._find_text = ''
layout = QHBoxLayout()
layout.addWidget(find_label)
layout.addWidget(self._line_edit)
layout.addWidget(self._find_button)
self.setLayout(layout)
self.setWindowTitle("Find a Contact")
self._find_button.clicked.connect(self.find_clicked)
self._find_button.clicked.connect(self.accept)
def find_clicked(self):
text = self._line_edit.text()
if not text:
QMessageBox.information(self, "Empty Field", "Please enter a name.")
return
else:
self._find_text = text
self._line_edit.clear()
self.hide()
def get_find_text(self):
return self._find_text
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (QApplication, QGridLayout,
QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._cancel_button.clicked.connect(self.cancel)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button, Qt.AlignTop)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addStretch()
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
self._submit_button.hide()
self._cancel_button.hide()
def cancel(self):
self._name_line.setText(self._old_name)
self._name_line.setReadOnly(True)
self._address_text.setText(self._old_address)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
self._submit_button.hide()
self._cancel_button.hide()
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import pickle
import sys
from PySide6.QtCore import QFile, QIODevice, QTextStream, Qt, Slot
from PySide6.QtWidgets import (QApplication, QDialog, QFileDialog,
QGridLayout, QHBoxLayout, QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
NavigationMode, AddingMode, EditingMode = range(3)
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
self._current_mode = self.NavigationMode
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._edit_button = QPushButton("&Edit")
self._edit_button.setEnabled(False)
self._remove_button = QPushButton("&Remove")
self._remove_button.setEnabled(False)
self._find_button = QPushButton("&Find")
self._find_button.setEnabled(False)
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._next_button = QPushButton("&Next")
self._next_button.setEnabled(False)
self._previous_button = QPushButton("&Previous")
self._previous_button.setEnabled(False)
self._load_button = QPushButton("&Load...")
self._load_button.setToolTip("Load contacts from a file")
self._save_button = QPushButton("Sa&ve...")
self._save_button.setToolTip("Save contacts to a file")
self._save_button.setEnabled(False)
self._export_button = QPushButton("Ex&port")
self._export_button.setToolTip("Export as vCard")
self._export_button.setEnabled(False)
self.dialog = FindDialog()
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._edit_button.clicked.connect(self.edit_contact)
self._remove_button.clicked.connect(self.remove_contact)
self._find_button.clicked.connect(self.find_contact)
self._cancel_button.clicked.connect(self.cancel)
self._next_button.clicked.connect(self.next)
self._previous_button.clicked.connect(self.previous)
self._load_button.clicked.connect(self.load_from_file)
self._save_button.clicked.connect(self.save_to_file)
self._export_button.clicked.connect(self.export_as_vcard)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button)
button_layout_1.addWidget(self._edit_button)
button_layout_1.addWidget(self._remove_button)
button_layout_1.addWidget(self._find_button)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addWidget(self._load_button)
button_layout_1.addWidget(self._save_button)
button_layout_1.addWidget(self._export_button)
button_layout_1.addStretch()
button_layout_2 = QHBoxLayout()
button_layout_2.addWidget(self._previous_button)
button_layout_2.addWidget(self._next_button)
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
main_layout.addLayout(button_layout_2, 2, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
@Slot()
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self.update_interface(self.AddingMode)
@Slot()
def edit_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self.update_interface(self.EditingMode)
@Slot()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if self._current_mode == self.AddingMode:
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._current_mode == self.EditingMode:
if self._old_name != name:
if name not in self.contacts:
QMessageBox.information(self, "Edit Successful",
f'"{self.oldName}" has been edited in your '
'address book.')
del self.contacts[self._old_name]
self.contacts[name] = address
else:
QMessageBox.information(self, "Edit Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._old_address != address:
QMessageBox.information(self, "Edit Successful",
f'"{name}" has been edited in your address book.')
self.contacts[name] = address
self.update_interface(self.NavigationMode)
@Slot()
def cancel(self):
self._name_line.setText(self._old_name)
self._address_text.setText(self._old_address)
self.update_interface(self.NavigationMode)
@Slot()
def remove_contact(self):
name = self._name_line.text()
if name in self.contacts:
button = QMessageBox.question(self, "Confirm Remove",
f'Are you sure you want to remove "{name}"?',
QMessageBox.Yes | QMessageBox.No)
if button == QMessageBox.Yes:
self.previous()
del self.contacts[name]
QMessageBox.information(self, "Remove Successful",
f'"{name}" has been removed from your address book.')
self.update_interface(self.NavigationMode)
@Slot()
def next(self):
name = self._name_line.text()
it = iter(self.contacts)
try:
while True:
this_name, _ = it.next()
if this_name == name:
next_name, next_address = it.next()
break
except StopIteration:
next_name, next_address = iter(self.contacts).next()
self._name_line.setText(next_name)
self._address_text.setText(next_address)
@Slot()
def previous(self):
name = self._name_line.text()
prev_name = prev_address = None
for this_name, this_address in self.contacts:
if this_name == name:
break
prev_name = this_name
prev_address = this_address
else:
self._name_line.clear()
self._address_text.clear()
return
if prev_name is None:
for prev_name, prev_address in self.contacts:
pass
self._name_line.setText(prev_name)
self._address_text.setText(prev_address)
def find_contact(self):
self.dialog.show()
if self.dialog.exec() == QDialog.Accepted:
contact_name = self.dialog.get_find_text()
if contact_name in self.contacts:
self._name_line.setText(contact_name)
self._address_text.setText(self.contacts[contact_name])
else:
QMessageBox.information(self, "Contact Not Found",
f'Sorry, "{contact_name}" is not in your address book.')
return
self.update_interface(self.NavigationMode)
def update_interface(self, mode):
self._current_mode = mode
if self._current_mode in (self.AddingMode, self.EditingMode):
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._edit_button.setEnabled(False)
self._remove_button.setEnabled(False)
self._next_button.setEnabled(False)
self._previous_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
self._load_button.setEnabled(False)
self._save_button.setEnabled(False)
self._export_button.setEnabled(False)
elif self._current_mode == self.NavigationMode:
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._edit_button.setEnabled(number >= 1)
self._remove_button.setEnabled(number >= 1)
self._find_button.setEnabled(number > 2)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
self._export_button.setEnabled(number >= 1)
self._load_button.setEnabled(True)
self._save_button.setEnabled(number >= 1)
def save_to_file(self):
fileName, _ = QFileDialog.getSaveFileName(self,
"Save Address Book", '',
"Address Book (*.abk);;All Files (*)")
if not fileName:
return
try:
out_file = open(str(fileName), 'wb')
except IOError:
QMessageBox.information(self, "Unable to open file",
f'There was an error opening "{fileName}"')
return
pickle.dump(self.contacts, out_file)
out_file.close()
def load_from_file(self):
fileName, _ = QFileDialog.getOpenFileName(self,
"Open Address Book", '',
"Address Book (*.abk);;All Files (*)")
if not fileName:
return
try:
in_file = open(str(fileName), 'rb')
except IOError:
QMessageBox.information(self, "Unable to open file",
f'There was an error opening "{fileName}"')
return
self.contacts = pickle.load(in_file)
in_file.close()
if len(self.contacts) == 0:
QMessageBox.information(self, "No contacts in file",
"The file you are attempting to open contains no contacts.")
else:
for name, address in self.contacts:
self._name_line.setText(name)
self._address_text.setText(address)
self.update_interface(self.NavigationMode)
def export_as_vcard(self):
name = str(self._name_line.text())
address = self._address_text.toPlainText()
name_list = name.split()
if len(name_list) > 1:
first_name = name_list[0]
last_name = name_list[-1]
else:
first_name = name
last_name = ''
file_name = QFileDialog.getSaveFileName(self, "Export Contact",
'', "vCard Files (*.vcf);;All Files (*)")[0]
if not file_name:
return
out_file = QFile(file_name)
if not out_file.open(QIODevice.WriteOnly):
QMessageBox.information(self, "Unable to open file", out_file.errorString())
return
out_s = QTextStream(out_file)
out_s << 'BEGIN:VCARD' << '\n'
out_s << 'VERSION:2.1' << '\n'
out_s << 'N:' << last_name << ';' << first_name << '\n'
out_s << 'FN:' << ' '.join(name_list) << '\n'
address.replace(';', '\\;')
address.replace('\n', ';')
address.replace(',', ' ')
out_s << 'ADR;HOME:;' << address << '\n'
out_s << 'END:VCARD' << '\n'
QMessageBox.information(self, "Export Successful",
f'"{name}" has been exported as a vCard.')
class FindDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
find_label = QLabel("Enter the name of a contact:")
self._line_edit = QLineEdit()
self._find_button = QPushButton("&Find")
self._find_text = ''
layout = QHBoxLayout()
layout.addWidget(find_label)
layout.addWidget(self._line_edit)
layout.addWidget(self._find_button)
self.setLayout(layout)
self.setWindowTitle("Find a Contact")
self._find_button.clicked.connect(self.find_clicked)
self._find_button.clicked.connect(self.accept)
def find_clicked(self):
text = self._line_edit.text()
if not text:
QMessageBox.information(self, "Empty Field", "Please enter a name.")
return
self._find_text = text
self._line_edit.clear()
self.hide()
def get_find_text(self):
return self._find_text
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import pickle
import sys
from PySide6.QtCore import Qt, Slot
from PySide6.QtWidgets import (QApplication, QDialog, QFileDialog,
QGridLayout, QHBoxLayout, QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
NavigationMode, AddingMode, EditingMode = range(3)
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
self._current_mode = self.NavigationMode
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._edit_button = QPushButton("&Edit")
self._edit_button.setEnabled(False)
self._remove_button = QPushButton("&Remove")
self._remove_button.setEnabled(False)
self._find_button = QPushButton("&Find")
self._find_button.setEnabled(False)
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._next_button = QPushButton("&Next")
self._next_button.setEnabled(False)
self._previous_button = QPushButton("&Previous")
self._previous_button.setEnabled(False)
self._load_button = QPushButton("&Load...")
self._load_button.setToolTip("Load contacts from a file")
self._save_button = QPushButton("Sa&ve...")
self._save_button.setToolTip("Save contacts to a file")
self._save_button.setEnabled(False)
self.dialog = FindDialog()
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._edit_button.clicked.connect(self.edit_contact)
self._remove_button.clicked.connect(self.remove_contact)
self._find_button.clicked.connect(self.find_contact)
self._cancel_button.clicked.connect(self.cancel)
self._next_button.clicked.connect(self.next)
self._previous_button.clicked.connect(self.previous)
self._load_button.clicked.connect(self.load_from_file)
self._save_button.clicked.connect(self.save_to_file)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button)
button_layout_1.addWidget(self._edit_button)
button_layout_1.addWidget(self._remove_button)
button_layout_1.addWidget(self._find_button)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addWidget(self._load_button)
button_layout_1.addWidget(self._save_button)
button_layout_1.addStretch()
button_layout_2 = QHBoxLayout()
button_layout_2.addWidget(self._previous_button)
button_layout_2.addWidget(self._next_button)
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
main_layout.addLayout(button_layout_2, 2, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
@Slot()
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self.update_interface(self.AddingMode)
@Slot()
def edit_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self.update_interface(self.EditingMode)
@Slot()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if self._current_mode == self.AddingMode:
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._current_mode == self.EditingMode:
if self._old_name != name:
if name not in self.contacts:
QMessageBox.information(self, "Edit Successful",
f'"{self.oldName}" has been edited in your '
'address book.')
del self.contacts[self._old_name]
self.contacts[name] = address
else:
QMessageBox.information(self, "Edit Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._old_address != address:
QMessageBox.information(self, "Edit Successful",
f'"{name}" has been edited in your address book.')
self.contacts[name] = address
self.update_interface(self.NavigationMode)
@Slot()
def cancel(self):
self._name_line.setText(self._old_name)
self._address_text.setText(self._old_address)
self.update_interface(self.NavigationMode)
@Slot()
def remove_contact(self):
name = self._name_line.text()
if name in self.contacts:
button = QMessageBox.question(self, "Confirm Remove",
f'Are you sure you want to remove "{name}"?',
QMessageBox.Yes | QMessageBox.No)
if button == QMessageBox.Yes:
self.previous()
del self.contacts[name]
QMessageBox.information(self, "Remove Successful",
f'"{name}" has been removed from your address book.')
self.update_interface(self.NavigationMode)
@Slot()
def next(self):
name = self._name_line.text()
it = iter(self.contacts)
try:
while True:
this_name, _ = it.next()
if this_name == name:
next_name, next_address = it.next()
break
except StopIteration:
next_name, next_address = iter(self.contacts).next()
self._name_line.setText(next_name)
self._address_text.setText(next_address)
@Slot()
def previous(self):
name = self._name_line.text()
prev_name = prev_address = None
for this_name, this_address in self.contacts:
if this_name == name:
break
prev_name = this_name
prev_address = this_address
else:
self._name_line.clear()
self._address_text.clear()
return
if prev_name is None:
for prev_name, prev_address in self.contacts:
pass
self._name_line.setText(prev_name)
self._address_text.setText(prev_address)
def find_contact(self):
self.dialog.show()
if self.dialog.exec() == QDialog.Accepted:
contact_name = self.dialog.get_find_text()
if contact_name in self.contacts:
self._name_line.setText(contact_name)
self._address_text.setText(self.contacts[contact_name])
else:
QMessageBox.information(self, "Contact Not Found",
f'Sorry, "{contact_name}" is not in your address book.')
return
self.update_interface(self.NavigationMode)
def update_interface(self, mode):
self._current_mode = mode
if self._current_mode in (self.AddingMode, self.EditingMode):
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._edit_button.setEnabled(False)
self._remove_button.setEnabled(False)
self._next_button.setEnabled(False)
self._previous_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
self._load_button.setEnabled(False)
self._save_button.setEnabled(False)
elif self._current_mode == self.NavigationMode:
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._edit_button.setEnabled(number >= 1)
self._remove_button.setEnabled(number >= 1)
self._find_button.setEnabled(number > 2)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
self._load_button.setEnabled(True)
self._save_button.setEnabled(number >= 1)
def save_to_file(self):
fileName, _ = QFileDialog.getSaveFileName(self,
"Save Address Book", '',
"Address Book (*.abk);;All Files (*)")
if not fileName:
return
try:
out_file = open(str(fileName), 'wb')
except IOError:
QMessageBox.information(self, "Unable to open file",
f'There was an error opening "{fileName}"')
return
pickle.dump(self.contacts, out_file)
out_file.close()
def load_from_file(self):
fileName, _ = QFileDialog.getOpenFileName(self,
"Open Address Book", '',
"Address Book (*.abk);;All Files (*)")
if not fileName:
return
try:
in_file = open(str(fileName), 'rb')
except IOError:
QMessageBox.information(self, "Unable to open file",
f'There was an error opening "{fileName}"')
return
self.contacts = pickle.load(in_file)
in_file.close()
if len(self.contacts) == 0:
QMessageBox.information(self, "No contacts in file",
"The file you are attempting to open contains no contacts.")
else:
for name, address in self.contacts:
self._name_line.setText(name)
self._address_text.setText(address)
self.update_interface(self.NavigationMode)
class FindDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
find_label = QLabel("Enter the name of a contact:")
self._line_edit = QLineEdit()
self._find_button = QPushButton("&Find")
self._find_text = ''
layout = QHBoxLayout()
layout.addWidget(find_label)
layout.addWidget(self._line_edit)
layout.addWidget(self._find_button)
self.setLayout(layout)
self.setWindowTitle("Find a Contact")
self._find_button.clicked.connect(self.find_clicked)
self._find_button.clicked.connect(self.accept)
def find_clicked(self):
text = self._line_edit.text()
if not text:
QMessageBox.information(self, "Empty Field", "Please enter a name.")
return
self._find_text = text
self._line_edit.clear()
self.hide()
def get_find_text(self):
return self._find_text
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import Qt, Slot
from PySide6.QtWidgets import (QApplication, QGridLayout,
QHBoxLayout, QLabel, QLineEdit,
QMessageBox, QPushButton, QTextEdit,
QVBoxLayout, QWidget)
class SortedDict(dict):
class Iterator(object):
def __init__(self, sorted_dict):
self._dict = sorted_dict
self._keys = sorted(self._dict.keys())
self._nr_items = len(self._keys)
self._idx = 0
def __iter__(self):
return self
def next(self):
if self._idx >= self._nr_items:
raise StopIteration
key = self._keys[self._idx]
value = self._dict[key]
self._idx += 1
return key, value
__next__ = next
def __iter__(self):
return SortedDict.Iterator(self)
iterkeys = __iter__
class AddressBook(QWidget):
NavigationMode, AddingMode, EditingMode = range(3)
def __init__(self, parent=None):
super().__init__(parent)
self.contacts = SortedDict()
self._old_name = ''
self._old_address = ''
self._current_mode = self.NavigationMode
name_label = QLabel("Name:")
self._name_line = QLineEdit()
self._name_line.setReadOnly(True)
address_label = QLabel("Address:")
self._address_text = QTextEdit()
self._address_text.setReadOnly(True)
self._add_button = QPushButton("&Add")
self._edit_button = QPushButton("&Edit")
self._edit_button.setEnabled(False)
self._remove_button = QPushButton("&Remove")
self._remove_button.setEnabled(False)
self._submit_button = QPushButton("&Submit")
self._submit_button.hide()
self._cancel_button = QPushButton("&Cancel")
self._cancel_button.hide()
self._next_button = QPushButton("&Next")
self._next_button.setEnabled(False)
self._previous_button = QPushButton("&Previous")
self._previous_button.setEnabled(False)
self._add_button.clicked.connect(self.add_contact)
self._submit_button.clicked.connect(self.submit_contact)
self._edit_button.clicked.connect(self.edit_contact)
self._remove_button.clicked.connect(self.remove_contact)
self._cancel_button.clicked.connect(self.cancel)
self._next_button.clicked.connect(self.next)
self._previous_button.clicked.connect(self.previous)
button_layout_1 = QVBoxLayout()
button_layout_1.addWidget(self._add_button)
button_layout_1.addWidget(self._edit_button)
button_layout_1.addWidget(self._remove_button)
button_layout_1.addWidget(self._submit_button)
button_layout_1.addWidget(self._cancel_button)
button_layout_1.addStretch()
button_layout_2 = QHBoxLayout()
button_layout_2.addWidget(self._previous_button)
button_layout_2.addWidget(self._next_button)
main_layout = QGridLayout()
main_layout.addWidget(name_label, 0, 0)
main_layout.addWidget(self._name_line, 0, 1)
main_layout.addWidget(address_label, 1, 0, Qt.AlignTop)
main_layout.addWidget(self._address_text, 1, 1)
main_layout.addLayout(button_layout_1, 1, 2)
main_layout.addLayout(button_layout_2, 3, 1)
self.setLayout(main_layout)
self.setWindowTitle("Simple Address Book")
@Slot()
def add_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self._name_line.clear()
self._address_text.clear()
self.update_interface(self.AddingMode)
@Slot()
def edit_contact(self):
self._old_name = self._name_line.text()
self._old_address = self._address_text.toPlainText()
self.update_interface(self.EditingMode)
@Slot()
def submit_contact(self):
name = self._name_line.text()
address = self._address_text.toPlainText()
if name == "" or address == "":
QMessageBox.information(self, "Empty Field", "Please enter a name and address.")
return
if self._current_mode == self.AddingMode:
if name not in self.contacts:
self.contacts[name] = address
QMessageBox.information(self, "Add Successful",
f'"{name}" has been added to your address book.')
else:
QMessageBox.information(self, "Add Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._current_mode == self.EditingMode:
if self._old_name != name:
if name not in self.contacts:
QMessageBox.information(self, "Edit Successful",
f'"{self.oldName}" has been edited in your '
'address book.')
del self.contacts[self._old_name]
self.contacts[name] = address
else:
QMessageBox.information(self, "Edit Unsuccessful",
f'Sorry, "{name}" is already in your address book.')
return
elif self._old_address != address:
QMessageBox.information(self, "Edit Successful",
f'"{name}" has been edited in your address book.')
self.contacts[name] = address
self.update_interface(self.NavigationMode)
@Slot()
def cancel(self):
self._name_line.setText(self._old_name)
self._address_text.setText(self._old_address)
self.update_interface(self.NavigationMode)
@Slot()
def remove_contact(self):
name = self._name_line.text()
if name in self.contacts:
button = QMessageBox.question(self, "Confirm Remove",
f'Are you sure you want to remove "{name}"?',
QMessageBox.Yes | QMessageBox.No)
if button == QMessageBox.Yes:
self.previous()
del self.contacts[name]
QMessageBox.information(self, "Remove Successful",
f'"{name}" has been removed from your address book.')
self.update_interface(self.NavigationMode)
@Slot()
def next(self):
name = self._name_line.text()
it = iter(self.contacts)
try:
while True:
this_name, _ = it.next()
if this_name == name:
next_name, next_address = it.next()
break
except StopIteration:
next_name, next_address = iter(self.contacts).next()
self._name_line.setText(next_name)
self._address_text.setText(next_address)
@Slot()
def previous(self):
name = self._name_line.text()
prev_name = prev_address = None
for this_name, this_address in self.contacts:
if this_name == name:
break
prev_name = this_name
prev_address = this_address
else:
self._name_line.clear()
self._address_text.clear()
return
if prev_name is None:
for prev_name, prev_address in self.contacts:
pass
self._name_line.setText(prev_name)
self._address_text.setText(prev_address)
def update_interface(self, mode):
self._current_mode = mode
if self._current_mode in (self.AddingMode, self.EditingMode):
self._name_line.setReadOnly(False)
self._name_line.setFocus(Qt.OtherFocusReason)
self._address_text.setReadOnly(False)
self._add_button.setEnabled(False)
self._edit_button.setEnabled(False)
self._remove_button.setEnabled(False)
self._next_button.setEnabled(False)
self._previous_button.setEnabled(False)
self._submit_button.show()
self._cancel_button.show()
elif self._current_mode == self.NavigationMode:
if not self.contacts:
self._name_line.clear()
self._address_text.clear()
self._name_line.setReadOnly(True)
self._address_text.setReadOnly(True)
self._add_button.setEnabled(True)
number = len(self.contacts)
self._edit_button.setEnabled(number >= 1)
self._remove_button.setEnabled(number >= 1)
self._next_button.setEnabled(number > 1)
self._previous_button.setEnabled(number > 1)
self._submit_button.hide()
self._cancel_button.hide()
if __name__ == '__main__':
app = QApplication(sys.argv)
address_book = AddressBook()
address_book.show()
sys.exit(app.exec())