未验证 提交 33d23eea 编写于 作者: J Jacob Schmitt 提交者: GitHub

Merge branch 'master' into directroy-tree-generator

# RP Contacts
**RP Contacts** is a Contact Book application built with Python, [PyQt5](https://www.riverbankcomputing.com/static/Docs/PyQt5/index.html), and [SQLite](https://www.sqlite.org/docs.html).
## Running the Application
To run **RP Contacts**, you need to download the source code. Then open a terminal or command-line window and run the following steps:
1. Create and activate a Python virtual environment
```sh
$ cd rpcontacts/
$ python -m venv ./venv
$ source venv/bin/activate
(venv) $
```
2. Install the dependencies
```sh
(venv) $ python -m pip install -r requirements.txt
```
3. Run the application
```sh
(venv) $ python rpcontacts.py
```
**Note:** This application was coded and tested using Python 3.8.5 and PyQt 5.15.2.
## Release History
- 0.1.0
- A work in progress
## About the Author
Leodanis Pozo Ramos – [@lpozo78](https://twitter.com/lpozo78) – leodanis@realpython.com
## License
Distributed under the MIT license.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides a database connection."""
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
"""Create and open a database connection."""
connection = QSqlDatabase.addDatabase("QSQLITE")
connection.setDatabaseName(databaseName)
if not connection.open():
QMessageBox.warning(
None,
"RP Contact",
f"Database Error: {connection.lastError().text()}",
)
return False
_createContactsTable()
return True
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""This module provides a model to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlTableModel
class ContactsModel:
def __init__(self):
self.model = self._createModel()
@staticmethod
def _createModel():
"""Create and set up the model."""
tableModel = QSqlTableModel()
tableModel.setTable("contacts")
tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
tableModel.select()
headers = ("ID", "Name", "Job", "Email")
for columnIndex, header in enumerate(headers):
tableModel.setHeaderData(columnIndex, Qt.Horizontal, header)
return tableModel
def addContact(self, data):
"""Add a contact to the database."""
rows = self.model.rowCount()
self.model.insertRows(rows, 1)
for column_index, field in enumerate(data):
self.model.setData(self.model.index(rows, column_index + 1), field)
self.model.submitAll()
self.model.select()
def deleteContact(self, row):
"""Remove a contact from the database."""
self.model.removeRow(row)
self.model.submitAll()
self.model.select()
def clearContacts(self):
"""Remove all contacts in the database."""
self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
self.model.removeRows(0, self.model.rowCount())
self.model.submitAll()
self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.model.select()
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QAbstractItemView,
QDialog,
QDialogButtonBox,
QFormLayout,
QHBoxLayout,
QLineEdit,
QMainWindow,
QMessageBox,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
from .model import ContactsModel
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.contactsModel = ContactsModel()
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setModel(self.contactsModel.model)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.addButton.clicked.connect(self.openAddDialog)
self.deleteButton = QPushButton("Delete")
self.deleteButton.clicked.connect(self.deleteContact)
self.clearAllButton = QPushButton("Clear All")
self.clearAllButton.clicked.connect(self.clearContacts)
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
def openAddDialog(self):
"""Open the Add Contact dialog."""
dialog = AddDialog(self)
if dialog.exec() == QDialog.Accepted:
self.contactsModel.addContact(dialog.data)
self.table.resizeColumnsToContents()
def deleteContact(self):
"""Delete the selected contact from the database."""
row = self.table.currentIndex().row()
if row < 0:
return
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove the selected contact?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.deleteContact(row)
def clearContacts(self):
"""Remove all contacts from the database."""
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove all your contacts?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.clearContacts()
class AddDialog(QDialog):
"""Add Contact dialog."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent=parent)
self.setWindowTitle("Add Contact")
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.data = None
self.setupUI()
def setupUI(self):
"""Setup the Add Contact dialog's GUI."""
# Create line edits for data fields
self.nameField = QLineEdit()
self.nameField.setObjectName("Name")
self.jobField = QLineEdit()
self.jobField.setObjectName("Job")
self.emailField = QLineEdit()
self.emailField.setObjectName("Email")
# Lay out the data fields
layout = QFormLayout()
layout.addRow("Name:", self.nameField)
layout.addRow("Job:", self.jobField)
layout.addRow("Email:", self.emailField)
self.layout.addLayout(layout)
# Add standard buttons to the dialog and connect them
self.buttonsBox = QDialogButtonBox(self)
self.buttonsBox.setOrientation(Qt.Horizontal)
self.buttonsBox.setStandardButtons(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel
)
self.buttonsBox.accepted.connect(self.accept)
self.buttonsBox.rejected.connect(self.reject)
self.layout.addWidget(self.buttonsBox)
def accept(self):
"""Accept the data provided through the dialog."""
self.data = []
for field in (self.nameField, self.jobField, self.emailField):
if not field.text():
QMessageBox.critical(
self,
"Error!",
f"You must provide a contact's {field.objectName()}",
)
self.data = None # Reset .data
return
self.data.append(field.text())
if not self.data:
return
super().accept()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Create the main window
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec())
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QHBoxLayout,
QMainWindow,
QWidget,
)
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Create the main window
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec())
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QAbstractItemView,
QHBoxLayout,
QMainWindow,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.deleteButton = QPushButton("Delete")
self.clearAllButton = QPushButton("Clear All")
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides a database connection."""
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
"""Create and open a database connection."""
connection = QSqlDatabase.addDatabase("QSQLITE")
connection.setDatabaseName(databaseName)
if not connection.open():
QMessageBox.warning(
None,
"RP Contact",
f"Database Error: {connection.lastError().text()}",
)
return False
_createContactsTable()
return True
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QAbstractItemView,
QHBoxLayout,
QMainWindow,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.deleteButton = QPushButton("Delete")
self.clearAllButton = QPushButton("Clear All")
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides a database connection."""
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
"""Create and open a database connection."""
connection = QSqlDatabase.addDatabase("QSQLITE")
connection.setDatabaseName(databaseName)
if not connection.open():
QMessageBox.warning(
None,
"RP Contact",
f"Database Error: {connection.lastError().text()}",
)
return False
_createContactsTable()
return True
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""This module provides a model to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlTableModel
class ContactsModel:
def __init__(self):
self.model = self._createModel()
@staticmethod
def _createModel():
"""Create and set up the model."""
tableModel = QSqlTableModel()
tableModel.setTable("contacts")
tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
tableModel.select()
headers = ("ID", "Name", "Job", "Email")
for columnIndex, header in enumerate(headers):
tableModel.setHeaderData(columnIndex, Qt.Horizontal, header)
return tableModel
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QAbstractItemView,
QHBoxLayout,
QMainWindow,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
from .model import ContactsModel
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.contactsModel = ContactsModel()
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setModel(self.contactsModel.model)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.deleteButton = QPushButton("Delete")
self.clearAllButton = QPushButton("Clear All")
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides a database connection."""
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
"""Create and open a database connection."""
connection = QSqlDatabase.addDatabase("QSQLITE")
connection.setDatabaseName(databaseName)
if not connection.open():
QMessageBox.warning(
None,
"RP Contact",
f"Database Error: {connection.lastError().text()}",
)
return False
_createContactsTable()
return True
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""This module provides a model to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlTableModel
class ContactsModel:
def __init__(self):
self.model = self._createModel()
@staticmethod
def _createModel():
"""Create and set up the model."""
tableModel = QSqlTableModel()
tableModel.setTable("contacts")
tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
tableModel.select()
headers = ("ID", "Name", "Job", "Email")
for columnIndex, header in enumerate(headers):
tableModel.setHeaderData(columnIndex, Qt.Horizontal, header)
return tableModel
def addContact(self, data):
"""Add a contact to the database."""
rows = self.model.rowCount()
self.model.insertRows(rows, 1)
for column_index, field in enumerate(data):
self.model.setData(self.model.index(rows, column_index + 1), field)
self.model.submitAll()
self.model.select()
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QAbstractItemView,
QDialog,
QDialogButtonBox,
QFormLayout,
QHBoxLayout,
QLineEdit,
QMainWindow,
QMessageBox,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
from .model import ContactsModel
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.contactsModel = ContactsModel()
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setModel(self.contactsModel.model)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.addButton.clicked.connect(self.openAddDialog)
self.deleteButton = QPushButton("Delete")
self.clearAllButton = QPushButton("Clear All")
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
def openAddDialog(self):
"""Open the Add Contact dialog."""
dialog = AddDialog(self)
if dialog.exec() == QDialog.Accepted:
self.contactsModel.addContact(dialog.data)
self.table.resizeColumnsToContents()
class AddDialog(QDialog):
"""Add Contact dialog."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent=parent)
self.setWindowTitle("Add Contact")
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.data = None
self.setupUI()
def setupUI(self):
"""Setup the Add Contact dialog's GUI."""
# Create line edits for data fields
self.nameField = QLineEdit()
self.nameField.setObjectName("Name")
self.jobField = QLineEdit()
self.jobField.setObjectName("Job")
self.emailField = QLineEdit()
self.emailField.setObjectName("Email")
# Lay out the data fields
layout = QFormLayout()
layout.addRow("Name:", self.nameField)
layout.addRow("Job:", self.jobField)
layout.addRow("Email:", self.emailField)
self.layout.addLayout(layout)
# Add standard buttons to the dialog and connect them
self.buttonsBox = QDialogButtonBox(self)
self.buttonsBox.setOrientation(Qt.Horizontal)
self.buttonsBox.setStandardButtons(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel
)
self.buttonsBox.accepted.connect(self.accept)
self.buttonsBox.rejected.connect(self.reject)
self.layout.addWidget(self.buttonsBox)
def accept(self):
"""Accept the data provided through the dialog."""
self.data = []
for field in (self.nameField, self.jobField, self.emailField):
if not field.text():
QMessageBox.critical(
self,
"Error!",
f"You must provide a contact's {field.objectName()}",
)
self.data = None # Reset .data
return
self.data.append(field.text())
if not self.data:
return
super().accept()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
# -*- coding: utf-8 -*-
"""This module provides a database connection."""
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
"""Create and open a database connection."""
connection = QSqlDatabase.addDatabase("QSQLITE")
connection.setDatabaseName(databaseName)
if not connection.open():
QMessageBox.warning(
None,
"RP Contact",
f"Database Error: {connection.lastError().text()}",
)
return False
_createContactsTable()
return True
# -*- coding: utf-8 -*-
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""This module provides a model to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlTableModel
class ContactsModel:
def __init__(self):
self.model = self._createModel()
@staticmethod
def _createModel():
"""Create and set up the model."""
tableModel = QSqlTableModel()
tableModel.setTable("contacts")
tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
tableModel.select()
headers = ("ID", "Name", "Job", "Email")
for columnIndex, header in enumerate(headers):
tableModel.setHeaderData(columnIndex, Qt.Horizontal, header)
return tableModel
def addContact(self, data):
"""Add a contact to the database."""
rows = self.model.rowCount()
self.model.insertRows(rows, 1)
for column_index, field in enumerate(data):
self.model.setData(self.model.index(rows, column_index + 1), field)
self.model.submitAll()
self.model.select()
def deleteContact(self, row):
"""Remove a contact from the database."""
self.model.removeRow(row)
self.model.submitAll()
self.model.select()
def clearContacts(self):
"""Remove all contacts in the database."""
self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
self.model.removeRows(0, self.model.rowCount())
self.model.submitAll()
self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.model.select()
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QAbstractItemView,
QDialog,
QDialogButtonBox,
QFormLayout,
QHBoxLayout,
QLineEdit,
QMainWindow,
QMessageBox,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
from .model import ContactsModel
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
self.contactsModel = ContactsModel()
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setModel(self.contactsModel.model)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.resizeColumnsToContents()
# Create buttons
self.addButton = QPushButton("Add...")
self.addButton.clicked.connect(self.openAddDialog)
self.deleteButton = QPushButton("Delete")
self.deleteButton.clicked.connect(self.deleteContact)
self.clearAllButton = QPushButton("Clear All")
self.clearAllButton.clicked.connect(self.clearContacts)
# Lay out the GUI
layout = QVBoxLayout()
layout.addWidget(self.addButton)
layout.addWidget(self.deleteButton)
layout.addStretch()
layout.addWidget(self.clearAllButton)
self.layout.addWidget(self.table)
self.layout.addLayout(layout)
def openAddDialog(self):
"""Open the Add Contact dialog."""
dialog = AddDialog(self)
if dialog.exec() == QDialog.Accepted:
self.contactsModel.addContact(dialog.data)
self.table.resizeColumnsToContents()
def deleteContact(self):
"""Delete the selected contact from the database."""
row = self.table.currentIndex().row()
if row < 0:
return
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove the selected contact?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.deleteContact(row)
def clearContacts(self):
"""Remove all contacts from the database."""
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove all your contacts?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.clearContacts()
class AddDialog(QDialog):
"""Add Contact dialog."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent=parent)
self.setWindowTitle("Add Contact")
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.data = None
self.setupUI()
def setupUI(self):
"""Setup the Add Contact dialog's GUI."""
# Create line edits for data fields
self.nameField = QLineEdit()
self.nameField.setObjectName("Name")
self.jobField = QLineEdit()
self.jobField.setObjectName("Job")
self.emailField = QLineEdit()
self.emailField.setObjectName("Email")
# Lay out the data fields
layout = QFormLayout()
layout.addRow("Name:", self.nameField)
layout.addRow("Job:", self.jobField)
layout.addRow("Email:", self.emailField)
self.layout.addLayout(layout)
# Add standard buttons to the dialog and connect them
self.buttonsBox = QDialogButtonBox(self)
self.buttonsBox.setOrientation(Qt.Horizontal)
self.buttonsBox.setStandardButtons(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel
)
self.buttonsBox.accepted.connect(self.accept)
self.buttonsBox.rejected.connect(self.reject)
self.layout.addWidget(self.buttonsBox)
def accept(self):
"""Accept the data provided through the dialog."""
self.data = []
for field in (self.nameField, self.jobField, self.emailField):
if not field.text():
QMessageBox.critical(
self,
"Error!",
f"You must provide a contact's {field.objectName()}",
)
self.data = None # Reset .data
return
self.data.append(field.text())
if not self.data:
return
super().accept()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册