【概览】
本文实现如下的程序:(在窗体中绘画出文字)
主要步骤如下:
1、在eric6中新建项目,新建窗体
2、(自动打开)进入PyQt5 Desinger,编辑图形界面,保存
3、回到eric 6,对上一步得到的界面文件 drawing.ui 文件右击,编译窗体,得到 Ui_drawing.py 文件
4、然后再对 drawing.ui 文件右击,生成对话框代码,得到 drawing.py 文件。(在drawing.py中添加自己的程序逻辑)
5、py2exe打包成exe文件(此步略)
【正文】
接【概览】第4步:
在 drawing.py 中,先准备要绘画的文本(self.text):
def __init__(self, parent=None): # ... self.text = '\u041b\u0435\u0432 \u041d\u0438\u043a\u043e\u043b\u0430\\u0435\u0432\u0438\u0447 \u0422\u043e\u043b\u0441\u0442\u043e\u0439: \n\\u0410\u043d\u043d\u0430 \u041a\u0430\u0440\u0435\u043d\u0438\u043d\u0430'
然后定义一个绘画事件:
def paintEvent(self, event): ...
所有的绘画都发生在此绘画事件内。给此绘画事件添加四行代码!
qp = QtGui.QPainter() qp.begin(self) self.drawText(event, qp)#自定义的绘画方法 qp.end()
QtGui.QPainter
类负责所有低级别的绘画。
所有的绘画方法要放在 begin()
和 end() 方法之间。当然,这里我们放的是自定义的drawText()方法
上面代码合起来是这样的:
def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawText(event, qp)#自定义的绘画方法 qp.end()
后面的几篇关于绘画的文章中,上面这一坨代码几乎就不变了。
当然了,变的是自定义的drawText方法:
def drawText(self, event, qp): qp.setPen(QtGui.QColor(168, 34, 3))#设置笔的颜色 qp.setFont(QtGui.QFont('Decorative', 20))#设置字体 qp.drawText(event.rect(), QtCore.Qt.AlignCenter, self.text)#画出文本
最终的 drawing.py 是这样的:
# -*- coding: utf-8 -*-'''Module implementing Drawing.'''import sysfrom PyQt5 import QtGui, QtCorefrom PyQt5.QtWidgets import QDialog, QApplicationfrom Ui_drawing import Ui_drawingclass Drawing(QDialog, Ui_Drawing): def __init__(self, parent=None): super(Drawing, self).__init__(parent) self.setupUi(self) self.text = '\u041b\u0435\u0432 \u041d\u0438\u043a\u043e\u043b\u0430\\u0435\u0432\u0438\u0447 \u0422\u043e\u043b\u0441\u0442\u043e\u0439: \n\\u0410\u043d\u043d\u0430 \u041a\u0430\u0440\u0435\u043d\u0438\u043d\u0430' def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawText(event, qp) qp.end() def drawText(self, event, qp): qp.setPen(QtGui.QColor(168, 34, 3)) qp.setFont(QtGui.QFont('Decorative', 20)) qp.drawText(event.rect(), QtCore.Qt.AlignCenter, self.text)if __name__ == '__main__': app = QApplication(sys.argv) dlg = Drawing() dlg.show() sys.exit(app.exec_())
【概览】
本文实现如下的程序:(在窗体中绘画出[-100, 100]两个周期的正弦函数图像)
主要步骤如下:
1、在eric6中新建项目,新建窗体
2、(自动打开)进入PyQt5 Desinger,编辑图形界面,保存
3、回到eric 6,对上一步得到的界面文件 drawing.ui 文件右击,编译窗体,得到 Ui_drawing.py 文件
4、然后再对 drawing.ui 文件右击,生成对话框代码,得到 drawing.py 文件。(在drawing.py中添加自己的程序逻辑)
5、py2exe打包成exe文件(此步略)
【正文】
接【概览】第4步:
在 drawing.py 中,先定义绘画事件:
def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawPoints(qp) #自定义画点方法 qp.end()
然后,自定义画点方法:
def drawPoints(self, qp): qp.setPen(QtCore.Qt.red) size = self.size() for i in range(1000): # [-100, 100]两个周期的正弦函数图像 x = 100 *(-1 2.0*i/1000) size.width()/2.0 y = -50*math.sin((x - size.width()/2.0)*math.pi/50) size.height()/2.0 qp.drawPoint(x, y)
合起来,drawing.py 是这个样子:
# -*- coding: utf-8 -*-'''Module implementing Drawing.'''import sys, mathfrom PyQt5 import QtGui, QtCorefrom PyQt5.QtWidgets import QDialog, QApplicationfrom Ui_drawing import Ui_Drawingclass Drawing(QDialog, Ui_Drawing): def __init__(self, parent=None): super(Drawing, self).__init__(parent) self.setupUi(self) def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawPoints(qp)#自定义画点方法 qp.end() def drawPoints(self, qp): qp.setPen(QtCore.Qt.red) size = self.size() for i in range(1000): # [-100, 100]两个周期的正弦函数图像 x = 100 *(-1 2.0*i/1000) size.width()/2.0 y = -50*math.sin((x - size.width()/2.0)*math.pi/50) size.height()/2.0 qp.drawPoint(x, y)if __name__ == '__main__': app = QApplication(sys.argv) dlg = Drawing() dlg.show() sys.exit(app.exec_())
【概览】
本文实现如下的程序:(在窗体中绘画出各种不同风格的线条)
主要步骤如下:
1、在eric6中新建项目,新建窗体
2、(自动打开)进入PyQt5 Desinger,编辑图形界面,保存
3、回到eric 6,对上一步得到的界面文件 drawing.ui 文件右击,编译窗体,得到 Ui_drawing.py 文件
4、然后再对 drawing.ui 文件右击,生成对话框代码,得到 drawing.py 文件。(在drawing.py中添加自己的程序逻辑)
5、py2exe打包成exe文件(此步略)
【正文】
接【概览】第4步:
在 drawing.py 中,先定义绘画事件:
def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawLines(qp) #自定义的画线方法 qp.end()
然后,自定义画线方法:
def drawLines(self, qp): pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(20, 40, 250, 40) pen.setStyle(QtCore.Qt.DashLine) qp.setPen(pen) qp.drawLine(20, 80, 250, 80) pen.setStyle(QtCore.Qt.DashDotLine) qp.setPen(pen) qp.drawLine(20, 120, 250, 120) pen.setStyle(QtCore.Qt.DotLine) qp.setPen(pen) qp.drawLine(20, 160, 250, 160) pen.setStyle(QtCore.Qt.DashDotDotLine) qp.setPen(pen) qp.drawLine(20, 200, 250, 200) pen.setStyle(QtCore.Qt.CustomDashLine) pen.setDashPattern([1, 4, 5, 4]) qp.setPen(pen) qp.drawLine(20, 240, 250, 240)
合起来,drawing.py 是这个样子:
# -*- coding: utf-8 -*-'''Module implementing Drawing.'''import sysfrom PyQt5 import QtGui, QtCorefrom PyQt5.QtWidgets import QDialog, QApplicationfrom Ui_drawing import Ui_Drawingclass Drawing(QDialog, Ui_Drawing): def __init__(self, parent=None): super(Drawing, self).__init__(parent) self.setupUi(self) def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawLines(qp) qp.end() def drawLines(self, qp): pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(20, 40, 250, 40) pen.setStyle(QtCore.Qt.DashLine) qp.setPen(pen) qp.drawLine(20, 80, 250, 80) pen.setStyle(QtCore.Qt.DashDotLine) qp.setPen(pen) qp.drawLine(20, 120, 250, 120) pen.setStyle(QtCore.Qt.DotLine) qp.setPen(pen) qp.drawLine(20, 160, 250, 160) pen.setStyle(QtCore.Qt.DashDotDotLine) qp.setPen(pen) qp.drawLine(20, 200, 250, 200) pen.setStyle(QtCore.Qt.CustomDashLine) pen.setDashPattern([1, 4, 5, 4]) qp.setPen(pen) qp.drawLine(20, 240, 250, 240)if __name__ == '__main__': app = QApplication(sys.argv) dlg = Drawing() dlg.show() sys.exit(app.exec_())
【引子】
在PyQt5自带教程中,地址簿(address book)程序没有完全实现界面与业务逻辑分离。
本文我打算用eric6 PyQt5对其进行改写,以实现界面与逻辑完全分离。
【概览】
1、界面:
2、功能简介:
程序有三种操作模式:浏览模式、添加模式、编辑模式。 其实现的功能都显式的体现在各个按钮上
3、主要步骤:
1)、在eric6中新建项目,新建窗体,取名为 addressbook.ui 文件
2)、(自动打开)进入PyQt5 Desinger,编辑图形界面,保存
3)、回到eric 6,对上一步得到的界面文件 addressbook.ui 文件右击,编译窗体,得到 Ui_addressbook.py 文件
4)、然后再对 addressbook.ui 文件右击,生成对话框代码,得到 addressbook.py 文件。(在addressbook.py中添加自己的程序逻辑)
5)、py2exe打包成exe文件(此步略)
4、涉及的知识点:
import sys, pickle
from PyQt5.QtCore import pyqtSlot, QFile, QIODevice, Qt, QTextStream
from PyQt5.QtWidgets import QWidget, QDialog, QLabel, QLineEdit, QPushButton, QHBoxLayout, QMessageBox, QFileDialog, QApplication
【正文】
1、一般的步骤省略不表,接上面主要步骤第二步:
在Qt设计师中,将行编辑框(lineEdit)、文本编辑框(textEdit)、及十一个按钮(pushButton)的对象名(objectName)分别设置如下:
lineEdit_name(姓名输入框)
textEdit_address(地址输入框)
pushButton_add(添加 按钮)
pushButton_edit(编辑 按钮)
pushButton_remove(删除 按钮)
pushButton_find(查找 按钮)
pushButton_submit(提交 按钮)
pushButton_cancel(取消 按钮)
pushButton_load(导入 按钮)
pushButton_save(保存 按钮)
pushButton_export(导出 按钮)
pushButton_previous(前一个 按钮)
pushButton_next(后一个 按钮)
2、关闭Qt设计师,回到eric6
先右击addressbook.ui 文件,编译窗体,得到 Ui_addressbook.py 文件
然后再次右击addressbook.ui 文件,生成对话框代码,
在弹窗中勾选十一个按钮的 on_x_clicked() 事件,确定,得到 addressbook.py 文件。
3、对addressbook.py 文件执行下面四步处理:
1)、清空所有注释
2)、去掉一个多余的点,将
from .Ui_addressbook import Ui_Form
变成:
from Ui_addressbook import Ui_Form
3)、将所有clicked()下的代码改写为pass
@pyqtSlot() def on_pushButton_add_clicked(self): pass @pyqtSlot() def on_pushButton_edit_clicked(self): pass # ...
4)、在 addressbook.py 文件最后面加上下面几句代码:
if __name__ == '__main__': import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) dlg = Dialog() dlg.show() sys.exit(app.exec_())
最后,addressbook.py 看起来是这个样子:
1 # -*- coding: utf-8 -*- 2 3 from PyQt5.QtCore import pyqtSlot 4 from PyQt5.QtWidgets import QDialog 5 6 from Ui_addressbook import Ui_Dialog 7 8 9 class Dialog(QDialog, Ui_Dialog):10 def __init__(self, parent=None):11 super(Dialog, self).__init__(parent)12 self.setupUi(self)13 14 @pyqtSlot()15 def on_pushButton_add_clicked(self):16 pass17 18 @pyqtSlot()19 def on_pushButton_edit_clicked(self):20 pass21 22 @pyqtSlot()23 def on_pushButton_remove_clicked(self):24 pass25 26 @pyqtSlot()27 def on_pushButton_find_clicked(self):28 pass29 30 @pyqtSlot()31 def on_pushButton_submit_clicked(self):32 pass33 34 @pyqtSlot()35 def on_pushButton_cancel_clicked(self):36 pass37 38 @pyqtSlot()39 def on_pushButton_load_clicked(self):40 pass41 42 @pyqtSlot()43 def on_pushButton_save_clicked(self):44 pass45 46 @pyqtSlot()47 def on_pushButton_export_clicked(self):48 pass49 50 @pyqtSlot()51 def on_pushButton_previous_clicked(self):52 pass53 54 @pyqtSlot()55 def on_pushButton_next_clicked(self):56 pass57 58 if __name__ == '__main__':59 import sys60 from PyQt5.QtWidgets import QApplication61 62 app = QApplication(sys.argv)63 dlg = Dialog()64 dlg.show()65 sys.exit(app.exec_())
View Code
4、下面添加逻辑代码
# -*- coding: utf-8 -*-import picklefrom PyQt5.QtCore import pyqtSlot, QFile, QIODevice, Qt, QTextStreamfrom PyQt5.QtWidgets import QWidget, QDialog, QLabel, QLineEdit, QPushButton, QHBoxLayout, QMessageBox, QFileDialogfrom Ui_addressbook import Ui_Dialogclass SortedDict(dict): class Iterator(object): def __init__(self, sorted_dict): self._dict = sorted_dict self._keys = sorted(self._dict.keys()) self._nr_items = len(self._keys) self._idx = 0 def __iter__(self): return self def next(self): if self._idx >= self._nr_items: raise StopIteration key = self._keys[self._idx] value = self._dict[key] self._idx = 1 return key, value __next__ = next def __iter__(self): return SortedDict.Iterator(self) iterkeys = __iter__class FindDialog(QDialog): def __init__(self, parent=None): super(FindDialog, self).__init__(parent) findLabel = QLabel('输入要查找的联系人姓名:') self.lineEdit = QLineEdit() self.findButton = QPushButton('查找') self.findText = '' layout = QHBoxLayout() layout.addWidget(findLabel) layout.addWidget(self.lineEdit) layout.addWidget(self.findButton) self.setLayout(layout) self.setWindowTitle('查找联系人') self.findButton.clicked.connect(self.findClicked) self.findButton.clicked.connect(self.accept) def findClicked(self): text = self.lineEdit.text() if not text: QMessageBox.information(self, '姓名不能为空', '请输入一个姓名') return self.findText = text self.lineEdit.clear() self.hide() def getFindText(self): return self.findTextclass Dialog(QDialog, Ui_Dialog): NavigationMode, AddingMode, EditingMode = range(3) def __init__(self, parent=None): super(Dialog, self).__init__(parent) self.setupUi(self) self.pushButton_submit.hide() self.pushButton_cancel.hide() self.contacts = SortedDict() self.oldName = '' self.oldAddress = '' self.currentMode = self.NavigationMode self.dialog = FindDialog() @pyqtSlot() def on_pushButton_add_clicked(self): self.oldName = self.lineEdit_name.text() self.oldAddress = self.textEdit_address.toPlainText() self.lineEdit_name.clear() self.textEdit_address.clear() self.updateInterface(self.AddingMode) @pyqtSlot() def on_pushButton_edit_clicked(self): self.oldName = self.lineEdit_name.text() self.oldAddress = self.textEdit_address.toPlainText() self.updateInterface(self.EditingMode) @pyqtSlot() def on_pushButton_remove_clicked(self): name = self.lineEdit_name.text() address = self.textEdit_address.toPlainText() if name in self.contacts: button = QMessageBox.question(self, '确定删除','你真的确定要删除 {} 吗?'.format(name), QMessageBox.Yes | QMessageBox.No) if button == QMessageBox.Yes: self.on_pushButton_previous_clicked() del self.contacts[name] QMessageBox.information(self, '删除成功','{}已经从你的地址簿删除了!'.format(name)) self.updateInterface(self.NavigationMode) @pyqtSlot() def on_pushButton_find_clicked(self): self.dialog.show() if self.dialog.exec_() == QDialog.Accepted: contactName = self.dialog.getFindText() if contactName in self.contacts: self.lineEdit_name.setText(contactName) self.textEdit_address.setText(self.contacts[contactName]) else: QMessageBox.information(self, '找不到','抱歉,{}不在你的地址簿内!'.format(contactName)) return self.updateInterface(self.NavigationMode) @pyqtSlot() def on_pushButton_submit_clicked(self): name = self.lineEdit_name.text() address = self.textEdit_address.toPlainText() if name == '' or address == '': QMessageBox.information(self, '不能为空', '请输入姓名及地址!') return if self.currentMode == self.AddingMode: if name not in self.contacts: self.contacts[name] = address QMessageBox.information(self, '添加成功', '{} 已经添加到你的地址簿!'.format(name)) else: QMessageBox.information(self, '添加失败', '{} 已经存在于你的地址簿!'.format(name)) return elif self.currentMode == self.EditingMode: if self.oldName != name: if name not in self.contacts: QMessageBox.information(self, '编辑成功','{} 已经被编辑到你的地址簿!'.format(self.oldName)) del self.contacts[self.oldName] self.contacts[name] = address else: QMessageBox.information(self, '编辑失败','抱歉,{} 已经存在于你的地址簿!'.format(name)) return elif self.oldAddress != address: QMessageBox.information(self, '编辑成功','{} 已经被编辑到你的地址簿!'.format(name)) self.contacts[name] = address self.updateInterface(self.NavigationMode) @pyqtSlot() def on_pushButton_cancel_clicked(self): self.lineEdit_name.setText(self.oldName) self.textEdit_address.setText(self.oldAddress) self.updateInterface(self.NavigationMode) @pyqtSlot() def on_pushButton_load_clicked(self): fileName, _ = QFileDialog.getOpenFileName(self, '打开地址簿', '', '地址簿文件 (*.abk);;所有文件 (*)') if not fileName: return try: in_file = open(str(fileName), 'rb') except IOError: QMessageBox.information(self, '不能打开文件','打开文件 {} 时发生错误!'.format(fileName)) return self.contacts = pickle.load(in_file) in_file.close() if len(self.contacts) == 0: QMessageBox.information(self, '文件中无联系人','你打开的文件中无联系人!') else: for name, address in self.contacts: self.lineEdit_name.setText(name) self.textEdit_address.setText(address) self.updateInterface(self.NavigationMode) @pyqtSlot() def on_pushButton_save_clicked(self): fileName, _ = QFileDialog.getSaveFileName(self, '保存地址簿', '', '地址簿文件 (*.abk);;所有文件 (*)') if not fileName: return try: out_file = open(str(fileName), 'wb') except IOError: QMessageBox.information(self, '不能打开文件','打开文件 {} 时发生错误!'.format(fileName)) return pickle.dump(self.contacts, out_file) out_file.close() @pyqtSlot() def on_pushButton_export_clicked(self): name = str(self.lineEdit_name.text()) address = self.textEdit_address.toPlainText() nameList = name.split() if len(nameList) > 1: firstName = nameList[0] lastName = nameList[-1] else: firstName = name lastName = '' fileName, _ = QFileDialog.getSaveFileName(self, '导出联系', '', 'vCard 文件 (*.vcf);;所有文件 (*)') if not fileName: return out_file = QFile(fileName) if not out_file.open(QIODevice.WriteOnly): QMessageBox.information(self, '不能打开文件', out_file.errorString()) return out_s = QTextStream(out_file) out_s << 'BEGIN:VCARD' << '\n' out_s << 'VERSION:2.1' << '\n' out_s << 'N:' << lastName << ';' << firstName << '\n' out_s << 'FN:' << ' '.join(nameList) << '\n' address.replace(';', '\\;') address.replace('\n', ';') address.replace(',', ' ') out_s << 'ADR;HOME:;' << address << '\n' out_s << 'END:VCARD' << '\n' QMessageBox.information(self, '导出成功','{} 已经被导出为 vCard !'.format(name)) @pyqtSlot() def on_pushButton_previous_clicked(self): name = self.lineEdit_name.text() prev_name = prev_address = None for this_name, this_address in self.contacts: if this_name == name: break prev_name = this_name prev_address = this_address else: self.lineEdit_name.clear() self.textEdit_address.clear() return if prev_name is None: for prev_name, prev_address in self.contacts: pass self.lineEdit_name.setText(prev_name) self.textEdit_address.setText(prev_address) @pyqtSlot() def on_pushButton_next_clicked(self): name = self.lineEdit_name.text() it = iter(self.contacts) try: while True: this_name, _ = it.next() if this_name == name: next_name, next_address = it.next() break except StopIteration: next_name, next_address = iter(self.contacts).next() self.lineEdit_name.setText(next_name) self.textEdit_address.setText(next_address) def updateInterface(self, mode): self.currentMode = mode if self.currentMode in (self.AddingMode, self.EditingMode): self.lineEdit_name.setReadOnly(False) self.lineEdit_name.setFocus(Qt.OtherFocusReason) self.textEdit_address.setReadOnly(False) self.pushButton_add.setEnabled(False) self.pushButton_edit.setEnabled(False) self.pushButton_remove.setEnabled(False) self.pushButton_next.setEnabled(False) self.pushButton_previous.setEnabled(False) self.pushButton_submit.show() self.pushButton_cancel.show() self.pushButton_load.setEnabled(False) self.pushButton_save.setEnabled(False) self.pushButton_export.setEnabled(False) elif self.currentMode == self.NavigationMode: if not self.contacts: self.lineEdit_name.clear() self.textEdit_address.clear() self.lineEdit_name.setReadOnly(True) self.textEdit_address.setReadOnly(True) self.pushButton_add.setEnabled(True) number = len(self.contacts) self.pushButton_edit.setEnabled(number >= 1) self.pushButton_remove.setEnabled(number >= 1) self.pushButton_find.setEnabled(number > 2) self.pushButton_next.setEnabled(number > 1) self.pushButton_previous.setEnabled(number >1 ) self.pushButton_submit.hide() self.pushButton_cancel.hide() self.pushButton_export.setEnabled(number >= 1) self.pushButton_load.setEnabled(True) self.pushButton_save.setEnabled(number >= 1)if __name__ == '__main__': import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) dlg = Dialog() dlg.show() sys.exit(app.exec_())
View Code
5、程序运行界面
联系客服