鱼C论坛

 找回密码
 立即注册
查看: 3733|回复: 6

[技术交流] PyQT5急速入门2

[复制链接]
发表于 2016-4-18 21:12:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
原文链接

上一篇 -> PyQT5急速入门1

引言

这篇文章是前作的续篇(part 2), 为了达到最好的教学效果, 请务必先阅读前作.

在这篇续作当中, 我们依旧是通过实例代码来学习PyQt5, 我会涉及到下一篇教程(part 3)的一些内容.

代码


  1. from PyQt5.QtCore import Qt
  2. from PyQt5.QtWidgets import (QGridLayout, QHBoxLayout, QLabel, QLineEdit,
  3.         QMessageBox, QPushButton, QTextEdit, QVBoxLayout, QWidget)

  4. class SortedDict(dict):
  5.     class Iterator(object):
  6.         def __init__(self, sorted_dict):
  7.             self._dict = sorted_dict
  8.             self._keys = sorted(self._dict.keys())
  9.             self._nr_items = len(self._keys)
  10.             self._idx = 0

  11.         def __iter__(self):
  12.             return self

  13.         def next(self):
  14.             if self._idx >= self._nr_items:
  15.                 raise StopIteration

  16.             key = self._keys[self._idx]
  17.             value = self._dict[key]
  18.             self._idx += 1

  19.             return key, value

  20.         __next__ = next

  21.     def __iter__(self):
  22.         return SortedDict.Iterator(self)

  23.     iterkeys = __iter__

  24. class AddressBook(QWidget):
  25.     def __init__(self, parent=None):
  26.         super(AddressBook, self).__init__(parent)

  27.         self.contacts = SortedDict()
  28.         self.oldName = ''
  29.         self.oldAddress = ''

  30.         nameLabel = QLabel("Name:")
  31.         self.nameLine = QLineEdit()
  32.         self.nameLine.setReadOnly(True)

  33.         addressLabel = QLabel("Address:")
  34.         self.addressText = QTextEdit()
  35.         self.addressText.setReadOnly(True)

  36.         self.addButton = QPushButton("&Add")
  37.         self.addButton.show()
  38.         self.submitButton = QPushButton("&Submit")
  39.         self.submitButton.hide()
  40.         self.cancelButton = QPushButton("&Cancel")
  41.         self.cancelButton.hide()
  42.         self.nextButton = QPushButton("&Next")
  43.         self.nextButton.setEnabled(False)
  44.         self.previousButton = QPushButton("&Previous")
  45.         self.previousButton.setEnabled(False)

  46.         self.addButton.clicked.connect(self.addContact)
  47.         self.submitButton.clicked.connect(self.submitContact)
  48.         self.cancelButton.clicked.connect(self.cancel)
  49.         self.nextButton.clicked.connect(self.next)
  50.         self.previousButton.clicked.connect(self.previous)

  51.         buttonLayout1 = QVBoxLayout()
  52.         buttonLayout1.addWidget(self.addButton, Qt.AlignTop)
  53.         buttonLayout1.addWidget(self.submitButton)
  54.         buttonLayout1.addWidget(self.cancelButton)
  55.         buttonLayout1.addStretch()

  56.         buttonLayout2 = QHBoxLayout()
  57.         buttonLayout2.addWidget(self.previousButton)
  58.         buttonLayout2.addWidget(self.nextButton)

  59.         mainLayout = QGridLayout()
  60.         mainLayout.addWidget(nameLabel, 0, 0)
  61.         mainLayout.addWidget(self.nameLine, 0, 1)
  62.         mainLayout.addWidget(addressLabel, 1, 0, Qt.AlignTop)
  63.         mainLayout.addWidget(self.addressText, 1, 1)
  64.         mainLayout.addLayout(buttonLayout1, 1, 2)
  65.         mainLayout.addLayout(buttonLayout2, 3, 1)

  66.         self.setLayout(mainLayout)
  67.         self.setWindowTitle("Simple Address Book")

  68.     def addContact(self):
  69.         self.oldName = self.nameLine.text()
  70.         self.oldAddress = self.addressText.toPlainText()

  71.         self.nameLine.clear()
  72.         self.addressText.clear()

  73.         self.nameLine.setReadOnly(False)
  74.         self.nameLine.setFocus(Qt.OtherFocusReason)
  75.         self.addressText.setReadOnly(False)

  76.         self.addButton.setEnabled(False)
  77.         self.nextButton.setEnabled(False)
  78.         self.previousButton.setEnabled(False)
  79.         self.submitButton.show()
  80.         self.cancelButton.show()

  81.     def submitContact(self):
  82.         name = self.nameLine.text()
  83.         address = self.addressText.toPlainText()

  84.         if name == "" or address == "":
  85.             QMessageBox.information(self, "Empty Field",
  86.                     "Please enter a name and address.")
  87.             return

  88.         if name not in self.contacts:
  89.             self.contacts[name] = address
  90.             QMessageBox.information(self, "Add Successful",
  91.                     ""%s" has been added to your address book." % name)
  92.         else:
  93.             QMessageBox.information(self, "Add Unsuccessful",
  94.                     "Sorry, "%s" is already in your address book." % name)
  95.             return

  96.         if not self.contacts:
  97.             self.nameLine.clear()
  98.             self.addressText.clear()

  99.         self.nameLine.setReadOnly(True)
  100.         self.addressText.setReadOnly(True)
  101.         self.addButton.setEnabled(True)

  102.         number = len(self.contacts)
  103.         self.nextButton.setEnabled(number > 1)
  104.         self.previousButton.setEnabled(number > 1)

  105.         self.submitButton.hide()
  106.         self.cancelButton.hide()

  107.     def cancel(self):
  108.         self.nameLine.setText(self.oldName)
  109.         self.addressText.setText(self.oldAddress)

  110.         if not self.contacts:
  111.             self.nameLine.clear()
  112.             self.addressText.clear()

  113.         self.nameLine.setReadOnly(True)
  114.         self.addressText.setReadOnly(True)
  115.         self.addButton.setEnabled(True)

  116.         number = len(self.contacts)
  117.         self.nextButton.setEnabled(number > 1)
  118.         self.previousButton.setEnabled(number > 1)

  119.         self.submitButton.hide()
  120.         self.cancelButton.hide()

  121.     def next(self):
  122.         name = self.nameLine.text()
  123.         it = iter(self.contacts)

  124.         try:
  125.             while True:
  126.                 this_name, _ = it.next()

  127.                 if this_name == name:
  128.                     next_name, next_address = it.next()
  129.                     break
  130.         except StopIteration:
  131.             next_name, next_address = iter(self.contacts).next()

  132.         self.nameLine.setText(next_name)
  133.         self.addressText.setText(next_address)

  134.     def previous(self):
  135.         name = self.nameLine.text()

  136.         prev_name = prev_address = None
  137.         for this_name, this_address in self.contacts:
  138.             if this_name == name:
  139.                 break

  140.             prev_name = this_name
  141.             prev_address = this_address
  142.         else:
  143.             self.nameLine.clear()
  144.             self.addressText.clear()
  145.             return

  146.         if prev_name is None:
  147.             for prev_name, prev_address in self.contacts:
  148.                 pass

  149.         self.nameLine.setText(prev_name)
  150.         self.addressText.setText(prev_address)

  151. if __name__ == '__main__':
  152.     import sys

  153.     from PyQt5.QtWidgets import QApplication

  154.     app = QApplication(sys.argv)

  155.     addressBook = AddressBook()
  156.     addressBook.show()

  157.     sys.exit(app.exec_())
复制代码


代码分析

我将会从第33行 Addressbook 这个类开始讲解, 因为大部分代码我在前作有讲解过, 我只会讲解前作没有涉及到的地方.

38-39行: 预先声明两个变量 oldName 和 oldAddress 以便后续代码调用.

42-43行: 我们声明一个文本编辑控件, 并且设置其只读属性为真, 当我们点击这个文本框的时候, 是无论如何都无法输入任何内容的.

49-58行: 我们为窗体添加一些按钮控件, 在第50行, show()方法会使 addButton 可见. 另外, submitButton 和 cancelButton 将会被我们隐式的创建. nextButton 和 previousButton 将会在窗体中显示出来, 但是他俩是灰色不可用的状态, 用户不能点击.

60-64行: 我们为控件添加点击触发的事件.

对于学习过前作的你来说, 看懂剩下的类简直是易如反掌了.

当我们第一次运行这个程序, 只有 Add 按钮是可以点击的, 这个按钮触发事件的代码在第87行.

1.png

88-89行: 还记得我们在38-39行定义的俩变量吗? 现在把 nameLine 和 addressText 的值赋给他俩.

91-96行: 我们把 nameLine 和 addressText 的文本框内容清空, 并且使用setReadOnly(false) 来让这俩变成可输入的状态, 最后把输入光标聚焦到nameLine 这里.

98-102行: 我们把 Add , Previous 和 Next 这三个按钮禁用掉, 然后吧 Submit 和 Cancel 按钮设置为可见状态. 其中 cancel 按钮的出发事件代码从第137行开始.

2.png

138-139行: 还记得88-89行的那俩变量吗? 现在把 nameLine 和 addressText 的值赋回去.

141-143行: 但如果这些变量并没有存放任何数据, 我们便相应的设置文本框为空.

149-151行: self.contacts 是一个包含了我们的 address book 输入值的字典, 我们获取这个字典的大小并且赋给一个叫做 number 的变量, 如果输入的变量大于2个的话, 我们就把 nextButton 和 previousButton 设置为可用. 其中, Submit 按钮的触发事件代码在第104行开始.

105-106行: 把 name 和 address 这俩变量的值赋给文本框.

108-110行: 只要这些变量其中有为空值的, 我们就会报错.

113-120行: 这个字典的一个属性必须是唯一的键值对, 如果这个键值对不在我们的字典里面, 我们将会加到字典里并且显示一个 "success" 对话框. 同样的, 如果这个键值对存在于这个字典了, 我们就会显示错误. 其中, 字典的触发事件代码从第5行开始, 这个类会生成一个有序字典, 在代码的第36行被调用了.

7-11行: 初始化一些私有变量, _idx 是字典的索引, _nr_items 存放着字典的大小.

16-24行: 把列表进行排序, 当 _idx 比 _nr_items 大的时候, 将会触发一个exception, 而正常情况我们会步进字典, 这个方法返回以index为索引, 自增长为1的键值对.

如果你想了解更多关于Python字典的内容, [see this page](http://www.tutorialspoint.com/python/python_dictionary.htm)

157-158行: 这个方法会在我们点击 next 按钮的时候触发, 输入框的值会赋给 name 变量, iter() 方法会给字典存在的变量赋值, 返回不在字典的键.

160-168行: 我们同样准备了 try-catch 代码, 在第162行的try语句里, 我们给键值对赋值.

170-171行: 我们把 next_name , next_address 的值赋给 nameLine 和 addressText. 其中 previous 按钮的触发事件代码从第173行开始.

第176行: 初始化 prev_name , prev_address 这两个变量, 并赋值为None.

177-182行: 我们迭代字典来储存 this_name , this_address 这两个变量的值, 如果 this_name 等于 nameLine 里面的值, 我们就退出迭代, 反之则把 prev_name , prev_address 赋给我们得到的变量.

189-190行: pass 这条语句本身毫无意义, 只是确保语法正确, 所以当 prev_name 为空时, 我们默认设置其值为空字符串.

总结

希望你能喜欢这篇文章 :-)

请接着学习 -> PyQT5急速入门3


评分

参与人数 1荣誉 +10 鱼币 +10 贡献 +10 收起 理由
冬雪雪冬 + 10 + 10 + 10 感谢楼主无私奉献!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2016-4-18 21:14:01 | 显示全部楼层
用习惯了MD, 来用dz排版真是头疼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-19 10:35:30 | 显示全部楼层
支持楼主,已收藏~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-19 12:22:10 | 显示全部楼层
hldh214 发表于 2016-4-18 21:14
用习惯了MD, 来用dz排版真是头疼

如果有需求的话,我会先在Cmd Markdown里面写好,然后直接复制到网页上,例如点击打开
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-19 16:48:09 | 显示全部楼层
~风介~ 发表于 2016-4-19 12:22
如果有需求的话,我会先在Cmd Markdown里面写好,然后直接复制到网页上,例如点击打开

dz的标题字体格式和md的不一样吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-19 16:54:58 | 显示全部楼层
hldh214 发表于 2016-4-19 16:48
dz的标题字体格式和md的不一样吧

不知道,反正我要的效果达到了~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-22 11:02:57 | 显示全部楼层
谢谢楼主的分析哇
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-4 15:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表