#!/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()
Page List
▼
Wednesday, January 25, 2012
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.