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