#!/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()
Wednesday, January 25, 2012
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.
Labels:
Qt Address Book Tutorial