#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book'
This first part covers the design of the basic graphical user interface (GUI)
for our address book application. The first step in creating a GUI program is
to design the user interface. Here the our goal is to set up the labels and
input fields to implement a basic address book.
last modified: 2012-01-23 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part1.html
'''
import sys
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout)
from PyQt4.QtCore import (Qt)
class AddressBook(QWidget): # subclass QWidget
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent) # initialise the base class
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
nameLine = QLineEdit(self)
addrLabel = QLabel(self.tr("Address:"))
addrText = QTextEdit(self)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(addrText, 1, 1)
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Showing posts with label Qt Address Book Tutorial. Show all posts
Showing posts with label Qt Address Book Tutorial. Show all posts
Wednesday, January 25, 2012
Qt 4.8 Address Book Tutorial - Part 1
The following code is based on the Qt Address Book Tutorial. It consists of seven parts. To see an alternative Python version of the code from this tutorial check your PyQt4 install directory under examples/tutorials/addressbook. The code below is from Part 1 - Designing the User Interface.
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 2
This code is based on the Qt 4.8 Address Book Tutorial Part 2, Adding Addresses.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 2
The next step in creating the address book is to implement some user
interactions. We will provide a push button that the user can click to
add a new contact. Also, some form of data structure is needed to store
these contacts in an organised way.
NOTE:
====
The original C++ code uses a QMap to hold the contact names and addresses.
PyQt4 does not include QMap, a Python 'dictionary' which holds 'keys'
and 'values' was used instead.
Extracted button panel creation to it's own 'init' method to make
the code easier to read
last modified: 2012-01-23 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part2.html
'''
import sys
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox)
from PyQt4.QtCore import (Qt, pyqtSlot)
class AddressBook(QWidget):
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictonary to hold contacts
self._contacts = {}
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addStretch() # force additional space to bottom
return layout
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddr = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.setEnabled(False)
self._submitBtn.show()
self._cancelBtn.show()
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
addr = self._addrText.toPlainText()
if not (name or addr):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if name not in self._contacts:
self._contacts[name] = addr
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
# restore buttons
if len(self._contacts) == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._submitBtn.hide()
self._cancelBtn.hide()
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddr)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._submitBtn.hide()
self._cancelBtn.hide()
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 3
This code is based on the Qt 4.8 Address Book Tutorial Part 3, Navigating Between Entries.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 3
Add the ability to navigate backwards and forwards through
the contacts.
NOTES:
=====
The method name for 'next()' has been changed to 'next_()' as
'next' is a reserved word in Python.
The 'next_()' and 'prev()' methods are implemented using sorted
lists of the contacts names (keys). As lists in Python
use 'pointers' (memory addresses) to objects and not the actual objects
themselves the methods should scale reasonably well.
last modified: 2012-01-24 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part3.html
'''
import sys
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox,
QHBoxLayout)
from PyQt4.QtCore import (Qt, pyqtSlot)
class AddressBook(QWidget):
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictonary to hold contacts
self._contacts = {}
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
mainLayout.addLayout(self._initNavPanel(), 2, 1)
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initNavPanel(self):
self._nextBtn = QPushButton(self.tr("&Next"))
self._prevBtn = QPushButton(self.tr("&Previous"))
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._nextBtn.clicked.connect(self.next_)
self._prevBtn.clicked.connect(self.previous)
layout = QHBoxLayout()
layout.addWidget(self._prevBtn)
layout.addWidget(self._nextBtn)
return layout
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addStretch() # force additional space to bottom
return layout
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.setEnabled(False)
self._submitBtn.show()
self._cancelBtn.show()
self._nextBtn.setEnabled(False) # disable navigationd during 'Add'
self._prevBtn.setEnabled(False)
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
addr = self._addrText.toPlainText()
if not (name or addr):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if name not in self._contacts:
self._contacts[name] = addr
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
# restore buttons
num = len(self._contacts)
if num == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._submitBtn.hide()
self._cancelBtn.hide()
# enable navigation if more than one contact
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddress)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._submitBtn.hide()
self._cancelBtn.hide()
# enable navigation if more than one contact
num = len(self._contacts)
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
@pyqtSlot()
def next_(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) + 1 # get index for next name in sorted list
if i >= len(sKeys): i = 0 # if we're past the end, go to the beginning
nextKey = sKeys[i] # name at new index is key we want
self._nameLine.setText(nextKey)
self._addrText.setText(self._contacts[nextKey])
@pyqtSlot()
def previous(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) - 1 # index for previous name in sorted list
if i < 0: i = len(sKeys) - 1 # if below the beginning, go to the end
prevKey = sKeys[i] # name at the new index is the key we want
self._nameLine.setText(prevKey)
self._addrText.setText(self._contacts[prevKey])
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 4
This code is based on the Qt 4.8 Address Book Tutorial Part 4, Editing and Removing Addresses.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 4
We now have an address book that not only holds contacts in an organized manner,
but also allows navigation. It would be convenient to include edit and remove
functions so that a contact's details can be changed when needed.
However, this requires a little improvement, added through implementing:
enum: AddMode, EditMode, NavMode
updateInteface(mode)
editBtn, removeBtn
editContact()
removeContact()
NOTE:
====
The code to handle the enabling/disabling, hiding/showing of the
various buttons has been extracted to the single method, 'updateInterface()'
last modified: 2012-01-24 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part4.html
'''
import sys
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox,
QHBoxLayout)
from PyQt4.QtCore import (Qt, pyqtSlot)
class AddressBook(QWidget):
# application operation 'modes'
# assigns values such that NavMode = 0, AddMode = 1 and EditMode = 2
NavMode, AddMode, EditMode = range(3)
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictionary to hold contacts
self._contacts = {}
# create attributes to represent object state
self._currentMode = '' # user actions
self._oldName = '' # entry value at mode change
self._oldAddress = '' # entry value at mode change
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
mainLayout.addLayout(self._initNavPanel(), 2, 1)
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initNavPanel(self):
self._nextBtn = QPushButton(self.tr("&Next"))
self._prevBtn = QPushButton(self.tr("&Previous"))
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._nextBtn.clicked.connect(self.next_)
self._prevBtn.clicked.connect(self.previous)
layout = QHBoxLayout()
layout.addWidget(self._prevBtn)
layout.addWidget(self._nextBtn)
return layout
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
self._editBtn = QPushButton(self.tr("&Edit"))
self._removeBtn = QPushButton(self.tr("&Remove"))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
self._editBtn.setEnabled(False)
self._removeBtn.setEnabled(False)
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
self._editBtn.clicked.connect(self._editContact)
self._removeBtn.clicked.connect(self._removeContact)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addWidget(self._editBtn)
layout.addWidget(self._removeBtn)
layout.addStretch() # force additional space to bottom
return layout
# private slots -----------------------------------------------------------
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self.updateInterface(self.AddMode)
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
address = self._addrText.toPlainText()
if not (name or address):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if self._currentMode == self.AddMode:
if name not in self._contacts:
self._contacts[name] = address
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._currentMode == self.EditMode:
if self._oldName != name:
if name not in self._contacts:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
del self._contacts[self._oldName]
self._contacts[name] = address
else:
QMessageBox.information(self,
self.tr("Edit Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._oldAddress != address:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
self._contacts[name] = address
self.updateInterface(self.NavMode)
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddress)
self.updateInterface(self.NavMode)
@pyqtSlot()
def _editContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self.updateInterface(self.EditMode)
@pyqtSlot()
def _removeContact(self):
name = self._nameLine.text()
if name in self._contacts:
ans = QMessageBox.question(
self,
self.tr("Confirm Remove"),
self.tr("Are you sure you want to remove {0}?").format(name),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if ans == QMessageBox.Yes:
self.previous()
del self._contacts[name]
QMessageBox.information(
self,
self.tr("Remove successful"),
self.tr("{0} has been removed from your address book.").format(name),
QMessageBox.Ok)
self.updateInterface(self.NavMode)
# public slots ------------------------------------------------------------
@pyqtSlot()
def next_(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) + 1 # get index for next name in sorted list
if i >= len(sKeys): i = 0 # if we're past the end, go to the beginning
nextKey = sKeys[i] # name at new index is key we want
self._nameLine.setText(nextKey)
self._addrText.setText(self._contacts[nextKey])
@pyqtSlot()
def previous(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) - 1 # index for previous name in sorted list
if i < 0: i = len(sKeys) - 1 # if below the beginning, go to the end
prevKey = sKeys[i] # name at the new index is the key we want
self._nameLine.setText(prevKey)
self._addrText.setText(self._contacts[prevKey])
# public methods ---------------------------------------------------------
def updateInterface(self, mode):
'''
Enable/disable buttons based on whether the user is adding,
editing or navigating Address Book entries.
'''
self._currentMode = mode
if mode != self.NavMode:
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.setEnabled(False)
self._editBtn.setEnabled(False)
self._removeBtn.setEnabled(False)
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._submitBtn.show()
self._cancelBtn.show()
else:
num = len(self._contacts)
if num == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._editBtn.setEnabled(num >= 1)
self._removeBtn.setEnabled(num >= 1)
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
self._submitBtn.hide()
self._cancelBtn.hide()
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 5
This code is based on the Qt 4.8 Address Book Tutorial Part 5, Adding a Find Function.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 5
Here we look at ways to locate contacts and addresses in the address book.
NOTES:
=====
In the original C++ code, the FindDialog class is written
in a separate file (finddialog.cpp); here it's defined
in the same module as the AddressBook class.
last modified: 2012-01-24 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part5.html
'''
import sys
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox,
QHBoxLayout, QDialog)
from PyQt4.QtCore import (Qt, pyqtSlot)
class FindDialog(QDialog):
def __init__(self, parent=None):
super(FindDialog, self).__init__(parent)
findLabel = QLabel(self.tr("Enter the name of a contact:"))
self.lineEdit = QLineEdit()
findBtn = QPushButton(self.tr("&Find"))
self.findText = ''
layout = QHBoxLayout(self)
layout.addWidget(findLabel)
layout.addWidget(self.lineEdit)
layout.addWidget(findBtn)
self.setLayout(layout)
self.setWindowTitle(self.tr("Find a Contact"))
findBtn.clicked.connect(self.findClicked)
findBtn.clicked.connect(self.accept)
def findClicked(self):
text = self.lineEdit.text()
if text:
self.findText = text
self.lineEdit.clear()
self.hide()
else:
QMessageBox.information(
self,
self.tr("Empty Field"),
self.tr("Please enter a name."))
def getFindText(self):
return self.findText
class AddressBook(QWidget):
# application operation 'modes'
# assigns values such that NavMode = 0, AddMode = 1 and EditMode = 2
NavMode, AddMode, EditMode = range(3)
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictionary to hold contacts
self._contacts = {}
# create attributes to represent object state
self._currentMode = '' # user actions
self._oldName = '' # key (name) at mode change
self._oldAddress = '' # key value (address) at mode change
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
mainLayout.addLayout(self._initNavPanel(), 2, 1)
# create find dialog
self._dialog = FindDialog()
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initNavPanel(self):
self._nextBtn = QPushButton(self.tr("&Next"))
self._prevBtn = QPushButton(self.tr("&Previous"))
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._nextBtn.clicked.connect(self.next_)
self._prevBtn.clicked.connect(self.previous)
layout = QHBoxLayout()
layout.addWidget(self._prevBtn)
layout.addWidget(self._nextBtn)
return layout
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
self._editBtn = QPushButton(self.tr("&Edit"))
self._removeBtn = QPushButton(self.tr("&Remove"))
self._findBtn = QPushButton(self.tr("&Find"))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
self._editBtn.setEnabled(False)
self._removeBtn.setEnabled(False)
self._findBtn.setEnabled(False)
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
self._editBtn.clicked.connect(self._editContact)
self._removeBtn.clicked.connect(self._removeContact)
self._findBtn.clicked.connect(self.findContact)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addWidget(self._editBtn)
layout.addWidget(self._removeBtn)
layout.addWidget(self._findBtn)
layout.addStretch() # force additional space to bottom
return layout
# private slots -----------------------------------------------------------
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self.updateInterface(self.AddMode)
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
address = self._addrText.toPlainText()
if not (name or address):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if self._currentMode == self.AddMode:
if name not in self._contacts:
self._contacts[name] = address
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._currentMode == self.EditMode:
if self._oldName != name:
if name not in self._contacts:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
del self._contacts[self._oldName]
self._contacts[name] = address
else:
QMessageBox.information(self,
self.tr("Edit Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._oldAddress != address:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
self._contacts[name] = address
self.updateInterface(self.NavMode)
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddress)
self.updateInterface(self.NavMode)
@pyqtSlot()
def _editContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self.updateInterface(self.EditMode)
@pyqtSlot()
def _removeContact(self):
name = self._nameLine.text()
if name in self._contacts:
ans = QMessageBox.question(
self,
self.tr("Confirm Remove"),
self.tr("Are you sure you want to remove {0}?").format(name),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if ans == QMessageBox.Yes:
self.previous()
del self._contacts[name]
QMessageBox.information(
self,
self.tr("Remove successful"),
self.tr("{0} has been removed from your address book.").format(name),
QMessageBox.Ok)
self.updateInterface(self.NavMode)
# public slots ------------------------------------------------------------
@pyqtSlot()
def next_(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) + 1 # get index for next name in sorted list
if i >= len(sKeys): i = 0 # if we're past the end, go to the beginning
nextKey = sKeys[i] # name at new index is key we want
self._nameLine.setText(nextKey)
self._addrText.setText(self._contacts[nextKey])
@pyqtSlot()
def previous(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) - 1 # index for previous name in sorted list
if i < 0: i = len(sKeys) - 1 # if below the beginning, go to the end
prevKey = sKeys[i] # name at the new index is the key we want
self._nameLine.setText(prevKey)
self._addrText.setText(self._contacts[prevKey])
@pyqtSlot()
def findContact(self):
self._dialog.show()
if self._dialog.exec() == QDialog.Accepted:
contactName = self._dialog.getFindText()
if contactName in self._contacts:
self._nameLine.setText(contactName)
self._addrText.setText(self._contacts[contactName])
else:
QMessageBox.information(
self,
self.tr("Contact Not Found"),
self.tr("{0} is not in your Address Book").format(contactName))
return
self.updateInterface(self.NavMode)
# public methods ---------------------------------------------------------
def updateInterface(self, mode):
'''
Enable/disable buttons based on whether the user is adding,
editing or navigating Address Book entries.
'''
self._currentMode = mode
if mode != self.NavMode:
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.hide()
self._editBtn.hide()
self._removeBtn.hide()
self._findBtn.hide()
self._submitBtn.show()
self._cancelBtn.show()
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
else:
num = len(self._contacts)
if num == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._editBtn.setEnabled(num >= 1)
self._removeBtn.setEnabled(num >= 1)
self._findBtn.setEnabled(num > 2)
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
self._addBtn.show()
self._editBtn.show()
self._removeBtn.show()
self._findBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 6
This code is based on the Qt 4.8 Address Book Tutorial Part 6, Loading and Saving.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 6
This part covers the Qt file handling features we use to write loading
and saving routines for the address book.
NOTES:
=====
Python's 'pickle' is used to save and load the file.
The 'Save' button is disabled if there are no contacts.
The QFileDialog handles normal errors e.g. asks if you
want to overwrite an existing file when saving or
if you want to select another file when trying to load a
non-existant file.
last modified: 2012-01-24 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part6.html
'''
import sys, pickle
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox,
QHBoxLayout, QDialog, QFileDialog)
from PyQt4.QtCore import (Qt, pyqtSlot)
class FindDialog(QDialog):
def __init__(self, parent=None):
super(FindDialog, self).__init__(parent)
findLabel = QLabel(self.tr("Enter the name of a contact:"))
self.lineEdit = QLineEdit()
findBtn = QPushButton(self.tr("&Find"))
self.findText = ''
layout = QHBoxLayout(self)
layout.addWidget(findLabel)
layout.addWidget(self.lineEdit)
layout.addWidget(findBtn)
self.setLayout(layout)
self.setWindowTitle(self.tr("Find a Contact"))
findBtn.clicked.connect(self.findClicked)
findBtn.clicked.connect(self.accept)
def findClicked(self):
text = self.lineEdit.text()
if text:
self.findText = text
self.lineEdit.clear()
self.hide()
else:
QMessageBox.information(
self,
self.tr("Empty Field"),
self.tr("Please enter a name."))
def getFindText(self):
return self.findText
class AddressBook(QWidget):
# application operation 'modes'
# assigns values such that NavMode = 0, AddMode = 1 and EditMode = 2
NavMode, AddMode, EditMode = range(3)
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictionary to hold contacts
self._contacts = {}
# create attributes to represent object state
self._currentMode = '' # user actions
self._oldName = '' # key (name) at mode change
self._oldAddress = '' # key value (address) at mode change
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
mainLayout.addLayout(self._initNavPanel(), 2, 1)
# create find dialog
self._dialog = FindDialog()
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initNavPanel(self):
self._nextBtn = QPushButton(self.tr("&Next"))
self._prevBtn = QPushButton(self.tr("&Previous"))
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._nextBtn.clicked.connect(self.next_)
self._prevBtn.clicked.connect(self.previous)
layout = QHBoxLayout()
layout.addWidget(self._prevBtn)
layout.addWidget(self._nextBtn)
return layout
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
self._editBtn = QPushButton(self.tr("&Edit"))
self._removeBtn = QPushButton(self.tr("&Remove"))
self._findBtn = QPushButton(self.tr("&Find"))
self._loadBtn = QPushButton(self.tr("&Load..."))
self._loadBtn.setToolTip(self.tr("Load contacts from a file."))
self._saveBtn = QPushButton(self.tr("Sa&ve..."))
self._saveBtn.setToolTip(self.tr("Save contacts to a file."))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
self._editBtn.setEnabled(False)
self._removeBtn.setEnabled(False)
self._findBtn.setEnabled(False)
self._saveBtn.setEnabled((False))
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
self._editBtn.clicked.connect(self._editContact)
self._removeBtn.clicked.connect(self._removeContact)
self._findBtn.clicked.connect(self.findContact)
self._loadBtn.clicked.connect(self.loadFromFile)
self._saveBtn.clicked.connect(self.saveToFile)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addWidget(self._editBtn)
layout.addWidget(self._removeBtn)
layout.addWidget(self._findBtn)
layout.addWidget(self._loadBtn)
layout.addWidget(self._saveBtn)
layout.addStretch() # force additional space to bottom
return layout
# private slots -----------------------------------------------------------
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self.updateInterface(self.AddMode)
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
address = self._addrText.toPlainText()
if not (name or address):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if self._currentMode == self.AddMode:
if name not in self._contacts:
self._contacts[name] = address
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._currentMode == self.EditMode:
if self._oldName != name:
if name not in self._contacts:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
del self._contacts[self._oldName]
self._contacts[name] = address
else:
QMessageBox.information(self,
self.tr("Edit Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._oldAddress != address:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
self._contacts[name] = address
self.updateInterface(self.NavMode)
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddress)
self.updateInterface(self.NavMode)
@pyqtSlot()
def _editContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self.updateInterface(self.EditMode)
@pyqtSlot()
def _removeContact(self):
name = self._nameLine.text()
if name in self._contacts:
ans = QMessageBox.question(
self,
self.tr("Confirm Remove"),
self.tr("Are you sure you want to remove {0}?").format(name),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if ans == QMessageBox.Yes:
self.previous()
del self._contacts[name]
QMessageBox.information(
self,
self.tr("Remove successful"),
self.tr("{0} has been removed from your address book.").format(name),
QMessageBox.Ok)
self.updateInterface(self.NavMode)
# public slots ------------------------------------------------------------
@pyqtSlot()
def next_(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) + 1 # get index for next name in sorted list
if i >= len(sKeys): i = 0 # if we're past the end, go to the beginning
nextKey = sKeys[i] # name at new index is key we want
self._nameLine.setText(nextKey)
self._addrText.setText(self._contacts[nextKey])
@pyqtSlot()
def previous(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) - 1 # index for previous name in sorted list
if i < 0: i = len(sKeys) - 1 # if below the beginning, go to the end
prevKey = sKeys[i] # name at the new index is the key we want
self._nameLine.setText(prevKey)
self._addrText.setText(self._contacts[prevKey])
@pyqtSlot()
def findContact(self):
self._dialog.show()
if self._dialog.exec() == QDialog.Accepted:
contactName = self._dialog.getFindText()
if contactName in self._contacts:
self._nameLine.setText(contactName)
self._addrText.setText(self._contacts[contactName])
else:
QMessageBox.information(
self,
self.tr("Contact Not Found"),
self.tr("{0} is not in your Address Book").format(contactName))
return
self.updateInterface(self.NavMode)
@pyqtSlot()
def loadFromFile(self):
fname = QFileDialog.getOpenFileName(
self,
self.tr("Open Address Book"), "",
self.tr("Address Book (*.abk);;All Files (*)"))
if not fname:
return
with open(fname, 'rb') as f:
self._contacts = pickle.load(f)
# sort the contacts and display the first name
sKeys = sorted(self._contacts.keys())
name = sKeys[0]
self._nameLine.setText(name)
self._addrText.setText(self._contacts[name])
self.updateInterface(self.NavMode)
@pyqtSlot()
def saveToFile(self):
fname = QFileDialog.getSaveFileName(
self,
self.tr("Save Address Book"), "",
self.tr("Address Book (*.abk);;All Files (*)"))
if not fname:
return
with open(fname, 'wb') as f:
pickle.dump(self._contacts, f, pickle.HIGHEST_PROTOCOL)
self.updateInterface(self.NavMode)
# public methods ---------------------------------------------------------
def updateInterface(self, mode):
'''
Enable/disable buttons based on whether the user is adding,
editing or navigating Address Book entries.
'''
self._currentMode = mode
if mode != self.NavMode:
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.hide()
self._editBtn.hide()
self._removeBtn.hide()
self._findBtn.hide()
self._loadBtn.hide()
self._saveBtn.hide()
self._submitBtn.show()
self._cancelBtn.show()
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
else:
num = len(self._contacts)
if num == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._editBtn.setEnabled(num >= 1)
self._removeBtn.setEnabled(num >= 1)
self._findBtn.setEnabled(num > 2)
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
self._loadBtn.setEnabled(True)
self._saveBtn.setEnabled(num >= 1)
self._addBtn.show()
self._editBtn.show()
self._removeBtn.show()
self._findBtn.show()
self._loadBtn.show()
self._saveBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Qt 4.8 Address Book Tutorial - Part 7
This code is based on the Qt 4.8 Address Book Tutorial Part 7, Additional Features.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
PyQt4 conversion of Qt Tutorial 'Address Book' - Part 7
This part covers some additional features that make the address book
more convenient for the frequent user.
Although our address book is useful in isolation, it would be better if
we could exchange contact data with other applications. The vCard format
is a popular file format that can be used for this purpose. Here we extend
our address book client to allow contacts to be exported to vCard .vcf files.
NOTES:
=====
Used QFile, QIODevice and QTextStream to create the vCard file.
last modified: 2012-01-25 jg
ref:
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook.html
http://developer.qt.nokia.com/doc/qt-4.8/tutorials-addressbook-part7.html
'''
import sys, pickle
from PyQt4.QtGui import (QApplication, QWidget, QLabel, QTextEdit, QLineEdit,
QGridLayout, QPushButton, QVBoxLayout, QMessageBox,
QHBoxLayout, QDialog, QFileDialog)
from PyQt4.QtCore import (Qt, pyqtSlot, QFile, QIODevice, QTextStream)
class FindDialog(QDialog):
def __init__(self, parent=None):
super(FindDialog, self).__init__(parent)
findLabel = QLabel(self.tr("Enter the name of a contact:"))
self.lineEdit = QLineEdit()
findBtn = QPushButton(self.tr("&Find"))
self.findText = ''
layout = QHBoxLayout(self)
layout.addWidget(findLabel)
layout.addWidget(self.lineEdit)
layout.addWidget(findBtn)
self.setLayout(layout)
self.setWindowTitle(self.tr("Find a Contact"))
findBtn.clicked.connect(self.findClicked)
findBtn.clicked.connect(self.accept)
def findClicked(self):
text = self.lineEdit.text()
if text:
self.findText = text
self.lineEdit.clear()
self.hide()
else:
QMessageBox.information(
self,
self.tr("Empty Field"),
self.tr("Please enter a name."))
def getFindText(self):
return self.findText
class AddressBook(QWidget):
# application operation 'modes'
# assigns values such that NavMode = 0, AddMode = 1 and EditMode = 2
NavMode, AddMode, EditMode = range(3)
def __init__(self, parent=None):
super(AddressBook, self).__init__(parent)
# create a dictionary to hold contacts
self._contacts = {}
# create attributes to represent object state
self._currentMode = '' # user actions
self._oldName = '' # key (name) at mode change
self._oldAddress = '' # key value (address) at mode change
# create input labels and fields
nameLabel = QLabel(self.tr("Name:"))
self._nameLine = QLineEdit(self)
self._nameLine.setReadOnly(True)
addrLabel = QLabel(self.tr("Address:"))
self._addrText = QTextEdit(self)
self._addrText.setReadOnly(True)
# create and populate layout
mainLayout = QGridLayout()
mainLayout.addWidget(nameLabel, 0, 0)
mainLayout.addWidget(self._nameLine, 0, 1)
mainLayout.addWidget(addrLabel, 1, 0, Qt.AlignTop)
mainLayout.addWidget(self._addrText, 1, 1)
mainLayout.addLayout(self._initButtonPanel(), 1, 2)
mainLayout.addLayout(self._initNavPanel(), 2, 1)
# create find dialog
self._dialog = FindDialog()
# set this objects layout and window title
self.setLayout(mainLayout)
self.setWindowTitle(self.tr("Simple Address Book"))
def _initNavPanel(self):
self._nextBtn = QPushButton(self.tr("&Next"))
self._prevBtn = QPushButton(self.tr("&Previous"))
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
self._nextBtn.clicked.connect(self.next_)
self._prevBtn.clicked.connect(self.previous)
layout = QHBoxLayout()
layout.addWidget(self._prevBtn)
layout.addWidget(self._nextBtn)
return layout
def _initButtonPanel(self):
# create buttons
self._addBtn = QPushButton(self.tr("&Add"))
self._submitBtn = QPushButton(self.tr("&Submit"))
self._cancelBtn = QPushButton(self.tr("&Cancel"))
self._editBtn = QPushButton(self.tr("&Edit"))
self._removeBtn = QPushButton(self.tr("&Remove"))
self._findBtn = QPushButton(self.tr("&Find"))
self._loadBtn = QPushButton(self.tr("&Load..."))
self._loadBtn.setToolTip(self.tr("Load contacts from a file."))
self._saveBtn = QPushButton(self.tr("Sa&ve..."))
self._saveBtn.setToolTip(self.tr("Save contacts to a file."))
self._exportBtn = QPushButton(self.tr("E&xport"))
# set button visibility
self._addBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
self._editBtn.setEnabled(False)
self._removeBtn.setEnabled(False)
self._findBtn.setEnabled(False)
self._saveBtn.setEnabled((False))
self._exportBtn.setEnabled((False))
# define signal/slot connections for event handling
self._addBtn.clicked.connect(self._addContact)
self._submitBtn.clicked.connect(self._submitContact)
self._cancelBtn.clicked.connect(self._cancel)
self._editBtn.clicked.connect(self._editContact)
self._removeBtn.clicked.connect(self._removeContact)
self._findBtn.clicked.connect(self.findContact)
self._loadBtn.clicked.connect(self.loadFromFile)
self._saveBtn.clicked.connect(self.saveToFile)
self._exportBtn.clicked.connect(self.exportAsVCard)
# layout buttons
layout = QVBoxLayout()
layout.addWidget(self._addBtn, Qt.AlignTop)
layout.addWidget(self._submitBtn)
layout.addWidget(self._cancelBtn)
layout.addWidget(self._editBtn)
layout.addWidget(self._removeBtn)
layout.addWidget(self._findBtn)
layout.addWidget(self._loadBtn)
layout.addWidget(self._saveBtn)
layout.addWidget(self._exportBtn)
layout.addStretch() # force additional space to bottom
return layout
# private slots -----------------------------------------------------------
@pyqtSlot()
def _addContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self._nameLine.clear()
self._addrText.clear()
self.updateInterface(self.AddMode)
@pyqtSlot()
def _submitContact(self):
name = self._nameLine.text()
address = self._addrText.toPlainText()
if not (name or address):
QMessageBox.information(self,
self.tr("Empty Field"),
self.tr("Please enter a name and address."))
return
if self._currentMode == self.AddMode:
if name not in self._contacts:
self._contacts[name] = address
QMessageBox.information(self,
self.tr("Add Successful"),
self.tr("{0} has been added to your address book.").format(name))
else:
QMessageBox.information(self,
self.tr("Add Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._currentMode == self.EditMode:
if self._oldName != name:
if name not in self._contacts:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
del self._contacts[self._oldName]
self._contacts[name] = address
else:
QMessageBox.information(self,
self.tr("Edit Unsuccessful"),
self.tr("Sorry, {0} is already in your address book.").format(name))
elif self._oldAddress != address:
QMessageBox.information(self,
self.tr("Edit Successful"),
self.tr("{0} has been edited in your address book.").format(name))
self._contacts[name] = address
self.updateInterface(self.NavMode)
@pyqtSlot()
def _cancel(self):
self._nameLine.setText(self._oldName)
self._nameLine.setReadOnly(True)
self._addrText.setText(self._oldAddress)
self.updateInterface(self.NavMode)
@pyqtSlot()
def _editContact(self):
self._oldName = self._nameLine.text()
self._oldAddress = self._addrText.toPlainText()
self.updateInterface(self.EditMode)
@pyqtSlot()
def _removeContact(self):
name = self._nameLine.text()
if name in self._contacts:
ans = QMessageBox.question(
self,
self.tr("Confirm Remove"),
self.tr("Are you sure you want to remove {0}?").format(name),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if ans == QMessageBox.Yes:
self.previous()
del self._contacts[name]
QMessageBox.information(
self,
self.tr("Remove successful"),
self.tr("{0} has been removed from your address book.").format(name),
QMessageBox.Ok)
self.updateInterface(self.NavMode)
# public slots ------------------------------------------------------------
@pyqtSlot()
def next_(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) + 1 # get index for next name in sorted list
if i >= len(sKeys): i = 0 # if we're past the end, go to the beginning
nextKey = sKeys[i] # name at new index is key we want
self._nameLine.setText(nextKey)
self._addrText.setText(self._contacts[nextKey])
@pyqtSlot()
def previous(self):
name = self._nameLine.text() # current contact's name
sKeys = sorted(self._contacts.keys()) # sort names
i = sKeys.index(name) - 1 # index for previous name in sorted list
if i < 0: i = len(sKeys) - 1 # if below the beginning, go to the end
prevKey = sKeys[i] # name at the new index is the key we want
self._nameLine.setText(prevKey)
self._addrText.setText(self._contacts[prevKey])
@pyqtSlot()
def findContact(self):
self._dialog.show()
if self._dialog.exec() == QDialog.Accepted:
contactName = self._dialog.getFindText()
if contactName in self._contacts:
self._nameLine.setText(contactName)
self._addrText.setText(self._contacts[contactName])
else:
QMessageBox.information(
self,
self.tr("Contact Not Found"),
self.tr("{0} is not in your Address Book").format(contactName))
return
self.updateInterface(self.NavMode)
@pyqtSlot()
def loadFromFile(self):
fname = QFileDialog.getOpenFileName(
self,
self.tr("Open Address Book"), "",
self.tr("Address Book (*.abk);;All Files (*)"))
if not fname:
return
with open(fname, 'rb') as f:
self._contacts = pickle.load(f)
# sort the contacts and display the first name
sKeys = sorted(self._contacts.keys())
name = sKeys[0]
self._nameLine.setText(name)
self._addrText.setText(self._contacts[name])
self.updateInterface(self.NavMode)
@pyqtSlot()
def saveToFile(self):
fname = QFileDialog.getSaveFileName(
self,
self.tr("Save Address Book"), "",
self.tr("Address Book (*.abk);;All Files (*)"))
if not fname:
return
with open(fname, 'wb') as f:
pickle.dump(self._contacts, f, pickle.HIGHEST_PROTOCOL)
self.updateInterface(self.NavMode)
@pyqtSlot()
def exportAsVCard(self):
name = self._nameLine.text()
address = self._addrText.toPlainText()
nameList = name.split()
firstName = ''
lastName = ''
if len(nameList) > 0:
firstName = nameList[0]
if len(nameList) >= 2:
lastName = nameList[-1]
fileName = QFileDialog.getSaveFileName(
self,
self.tr("Export Contacts"),
'',
self.tr("vCard Files (*.vcf);;All Files(*)"))
if not fileName:
return
file = QFile(fileName)
if not file.open(QIODevice.WriteOnly):
QMessageBox.information(
self,
self.tr("Unable to open file"),
file.errorString())
return
# write the file
outFile = QTextStream(file)
outFile << "BEGIN:VCARD" << "\n"
outFile << "VERSION:2.1" << "\n"
outFile << "N:" << lastName << ";" << firstName << "\n"
if lastName:
outFile << "FN:" << " ".join(nameList) << "\n"
else:
outFile << "FN:" << firstName << "\n"
address.replace(";", "\\")
address.replace("\n", ";")
address.replace(",", " ")
outFile << "ADR;HOME:;" << address << "\n"
outFile << "END:VCARD" << "\n"
QMessageBox.information(
self,
self.tr("Export Successful"),
self.tr("{0} has been exported to a vCard").format(name))
self.updateInterface(self.NavMode)
# public methods ---------------------------------------------------------
def updateInterface(self, mode):
'''
Enable/disable buttons based on whether the user is adding,
editing or navigating Address Book entries.
'''
self._currentMode = mode
if mode != self.NavMode:
self._nameLine.setReadOnly(False)
self._nameLine.setFocus(Qt.OtherFocusReason)
self._addrText.setReadOnly(False)
self._addBtn.hide()
self._editBtn.hide()
self._removeBtn.hide()
self._findBtn.hide()
self._loadBtn.hide()
self._saveBtn.hide()
self._exportBtn.hide()
self._submitBtn.show()
self._cancelBtn.show()
self._nextBtn.setEnabled(False)
self._prevBtn.setEnabled(False)
else:
num = len(self._contacts)
if num == 0:
self._nameLine.clear()
self._addrText.clear()
self._nameLine.setReadOnly(True)
self._addrText.setReadOnly(True)
self._addBtn.setEnabled(True)
self._editBtn.setEnabled(num >= 1)
self._removeBtn.setEnabled(num >= 1)
self._findBtn.setEnabled(num > 2)
self._nextBtn.setEnabled(num > 1)
self._prevBtn.setEnabled(num > 1)
self._loadBtn.setEnabled(True)
self._saveBtn.setEnabled(num >= 1)
self._exportBtn.setEnabled(num >= 1)
self._addBtn.show()
self._editBtn.show()
self._removeBtn.show()
self._findBtn.show()
self._loadBtn.show()
self._saveBtn.show()
self._exportBtn.show()
self._submitBtn.hide()
self._cancelBtn.hide()
def main():
app = QApplication(sys.argv) # required for all GUI applications
ab = AddressBook()
ab.show() # make me visible
sys.exit(app.exec_()) # start main event thread
if __name__ == '__main__':
main()
Labels:
Qt Address Book Tutorial
Subscribe to:
Posts (Atom)