赞
踩
下面直接使用pip来安装PyQt5,此处可能是pip/pip3,或者两者皆可,后面不再重复
直接pip安装PyQt5,当然也可以加镜像加快安装
pip install PyQt5
由于Qt Designer已经在Python3.5版本从PyQt5转移到了tools,因此我们还需要安装pyqt5-tools
pip install pyqt5-tools
然后键盘按下Win+S呼出Cornata主面板(搜索框),输入designer,如果看到跟下图类似的结果说明PyQt Designer已经被安装。
在cmd中输入pyuic5,如果返回“Error: one input ui-file must be specified”也能够说明安装成功。
C:\Users\16204>pyuic5
Error: one input ui-file must be specified
使用Pycharm,做简单的测试,创建Widget窗口对象,进行展示
import sys from PyQt5.QtWidgets import QApplication, QWidget if __name__ == '__main__': app = QApplication(sys.argv) widget = QWidget() # create the obj of widget widget.resize(400, 200) # the size of widget window widget.move(300, 300) # the position of widget window widget.setWindowTitle("第一个唤醒手腕桌面应用程序") # the title of widget window widget.show() # show widget window sys.exit(app.exec_()) # 进入程序的主循环、并通过exit函数确保主循环安全结束
运行的结果展示如下所示:
在使用PyQT5创建GUI图形用户界面程序时,会生成扩展名为.ui的文件,该文件需要转换为.py文件后才可以被Python识别,所以需要配置Pycharm。
名称(Name):Qt Designer [外部工具的名称 可自定义]
组(Group):使用默认值
程序(Program):C:\\Python\Python38\Lib\site-packages\QtDesigner\designer.exe [输入自己的PyQt5开发工具安装路径]
工作目录(Working directory):$ProjectFileDir$ [表示自己文件所在的项目路径]
图示操作:
当然将ui文件转换成py文件也可以采用如下命令:
xxx.ui所在目录 > pyuic5 -o XXX.py xxx.ui
使用Qt Designer创建English.ui,首先将English.ui文件转换成English.py文件,在main进行调用,展示如下:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
import English
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = QWidget()
ui = English.Ui_Form() # 加载ui对象
ui.setupUi(widget)
widget.show() # 窗口展示
sys.exit(app.exec_())
自定义继承QWidget的子类,进行调用测试,也可以进行窗口logo的设置,展示如下:
import sys from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QWidget class UsingTest(QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setWindowTitle("唤醒手腕") self.setGeometry(300, 300, 350, 150) if __name__ == '__main__': # 程序的入口 app = QApplication(sys.argv) win = UsingTest() win.setWindowIcon(QIcon("./excel_wrist.ico")) win.show() sys.exit(app.exec_())
如何设置窗口的居中显示:
def setCenterPosition(self):
# 获取屏幕坐标系
screen = QDesktopWidget().screenGeometry()
# 获取自身的窗口坐标系
size = self.geometry()
newLeft = (screen.width() - size.width()) / 2
newTop = (screen.height() - size.height()) / 2
self.move(newLeft, newTop)
首先我们设计好ui,转换成py文件:
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(500, 300) MainWindow.setMinimumSize(QtCore.QSize(500, 300)) MainWindow.setMaximumSize(QtCore.QSize(500, 300)) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(30, 30, 240, 240)) self.label_2.setText("") self.label_2.setPixmap(QtGui.QPixmap("apple.webp")) self.label_2.setObjectName("label_2") self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setGeometry(QtCore.QRect(310, 220, 151, 51)) font = QtGui.QFont() font.setPointSize(13) self.pushButton_2.setFont(font) self.pushButton_2.setObjectName("pushButton_2") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton_2.setText(_translate("MainWindow", "Choose Image"))
然后进行设计主main调用,展示如下所示:
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog from chooseMyImage import * class MyClass(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyClass, self).__init__(parent) self.setupUi(self) self.pushButton_2.clicked.connect(self.openimage) def openimage(self): imgName, imgType = QFileDialog.getOpenFileName(self, "打开图片", "", "*.jpg;;*.png;;All Files(*)") jpg = QtGui.QPixmap(imgName).scaled(240, 240) self.label_2.setPixmap(jpg) if __name__ == '__main__': app = QApplication(sys.argv) myWin = MyClass() myWin.show() sys.exit(app.exec_())
运行结果展示如下:
调整图片显示尺寸的函数scaled():
从源码可以看出,我们也可以根据高度与宽度进行自适应的尺寸表示。
需要使用PyQt5、numpy、cv2等第三方库,代码展示:
import sys import cv2 import numpy as np from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QGridLayout, QLabel, QPushButton class Window(QDialog): def __init__(self): # 初始化一个img的ndarry,用于存储图像 self.img = np.ndarray(()) super().__init__() self.initUI() def initUI(self): self.resize(500, 400) self.btnOpen = QPushButton('Open', self) self.btnSave = QPushButton('Save', self) self.btnProcess = QPushButton('Process', self) self.btnQuit = QPushButton('Quit', self) self.label = QLabel() # 布局设定 layout = QGridLayout(self) layout.addWidget(self.label, 0, 1, 3, 4) layout.addWidget(self.btnOpen, 4, 1, 1, 1) layout.addWidget(self.btnSave, 4, 2, 1, 1) layout.addWidget(self.btnProcess, 4, 3, 1, 1) layout.addWidget(self.btnQuit, 4, 4, 1, 1) # 信号与槽进行连接,信号可绑定普通成员函数 self.btnOpen.clicked.connect(self.openSlot) self.btnSave.clicked.connect(self.saveSlot) self.btnProcess.clicked.connect(self.processSlot) self.btnQuit.clicked.connect(self.close) def openSlot(self): # 调用存储文件 fileName, tmp = QFileDialog.getOpenFileName(self, 'Open Image', 'Image', '*.png *.jpg *.bmp') # 采用OpenCV函数读取数据 self.img = cv2.imread(fileName, -1) self.refreshShow() def saveSlot(self): # 调用存储文件dialog fileName, tmp = QFileDialog.getSaveFileName(self, 'Save Image', 'Image', '*.png *.jpg *.bmp') # 调用OpenCV写入函数 cv2.imwrite(fileName, self.img) def processSlot(self): # 对图像做模糊处理,窗口设定为5*5 self.img = cv2.blur(self.img, (5, 5)) self.refreshShow() def refreshShow(self): # 提取图像的通道和尺寸,用于将OpenCV下的image转换成Qimage height, width, channel = self.img.shape bytesPerline = 3 * width self.qImg = QImage(self.img.data, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped() # 将QImage显示出来 self.label.setPixmap(QPixmap.fromImage(self.qImg).scaledToHeight(400)) if __name__ == '__main__': app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec_())
运行展示如下所示:
首先是建立ui文件:
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 400) MainWindow.setMinimumSize(QtCore.QSize(800, 400)) MainWindow.setMaximumSize(QtCore.QSize(800, 400)) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.SaveButton = QtWidgets.QPushButton(self.centralwidget) self.SaveButton.setGeometry(QtCore.QRect(570, 160, 200, 51)) font = QtGui.QFont() font.setPointSize(11) self.SaveButton.setFont(font) self.SaveButton.setObjectName("SaveButton") self.VideoLabel = QtWidgets.QLabel(self.centralwidget) self.VideoLabel.setText("监控展示区域") self.VideoLabel.setGeometry(QtCore.QRect(30, 20, 500, 360)) self.VideoLabel.setMinimumSize(QtCore.QSize(480, 360)) self.VideoLabel.setObjectName("VideoLabel") self.ImageLabel = QtWidgets.QLabel(self.centralwidget) self.ImageLabel.setGeometry(QtCore.QRect(570, 230, 200, 150)) self.ImageLabel.setObjectName("ImageLabel") self.ImageLabel.setText("图像截取展示区域") self.GetButton = QtWidgets.QPushButton(self.centralwidget) self.GetButton.setGeometry(QtCore.QRect(570, 90, 200, 51)) font = QtGui.QFont() font.setPointSize(11) self.GetButton.setFont(font) self.GetButton.setObjectName("GetButton") self.PauseButton = QtWidgets.QPushButton(self.centralwidget) self.PauseButton.setGeometry(QtCore.QRect(570, 20, 200, 51)) font = QtGui.QFont() font.setPointSize(11) self.PauseButton.setFont(font) self.PauseButton.setObjectName("PauseButton") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.SaveButton.setText(_translate("MainWindow", "保存最近一次画面")) self.VideoLabel.setText(_translate("MainWindow", "TextLabel")) self.ImageLabel.setText(_translate("MainWindow", "TextLabel")) self.GetButton.setText(_translate("MainWindow", "截取当前监控画面")) self.PauseButton.setText(_translate("MainWindow", "开启自动跟踪监控"))
然后是main文件的代码,展示如下:
import sys from datetime import datetime from PyQt5.QtGui import QPixmap, QImage from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog from wristcamera import * import cv2 capture = cv2.VideoCapture(0) class MyClass(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyClass, self).__init__(parent) self.setupUi(self) self.isStartState = False self.isImageExist = False self.PauseButton.clicked.connect(self.startVideo) self.GetButton.clicked.connect(self.getImage) self.SaveButton.clicked.connect(self.saveImage) def startVideo(self): self.isStartState = ~self.isStartState while self.isStartState: self.VideoLabel.setPixmap(self.nowImage()[0]) cv2.waitKey(50) def getImage(self): if self.isStartState == False: return self.isImageExist = True self.ImageLabel.setPixmap(self.nowImage()[0].scaled(200, 150)) def saveImage(self): if self.isImageExist == False: return FileName = datetime.now().strftime('%Y-%m-%d_%H_%M_%S') file, tmp = QFileDialog.getSaveFileName(self, 'Save Image', FileName, '*.png *.jpg *.bmp') cv2.imwrite(file, self.nowImage()[1]) # 当前的画面 def nowImage(self): ret, frame = capture.read() # 摄像头读取, ret为是否成功打开摄像头, true, false:frame为视频的每一帧图像 self.img = cv2.flip(frame, 1) # 摄像头是和人对立的,将图像左右调换回来正常显示。 # 提取图像的通道和尺寸,用于将OpenCV下的image转换成Qimage height, width, channel = self.img.shape bytesPerline = 3 * width self.qImg = QImage(self.img.data, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped() # 将QImage显示出来 return QPixmap.fromImage(self.qImg.scaled(480, 360)), self.img if __name__ == '__main__': app = QApplication(sys.argv) myWin = MyClass() myWin.setWindowTitle("唤醒手腕 - 猫头鹰智能监控光棱2000") myWin.show() sys.exit(app.exec_())
运行的结果展示:马赛克是为了保护博主丑陋的模样,谢谢配合
点击保存最近一次画面就会弹窗,文件保存的路径提示:
在新版本中的需要自行下载QtWebEngine,展示如下:
pip install PyQtWebEngine
具体实现代码展示:
import sys from PyQt5.QtCore import QUrl from PyQt5.QtGui import QIcon from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtWidgets import QApplication, QDesktopWidget from PyQt5.QtWidgets import QMainWindow class UsingTest(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setWindowTitle("唤醒手腕") self.setMaximumSize(1500, 900) self.setMinimumSize(1500, 900) self.browser = QWebEngineView() self.browser.load(QUrl("http://wrist.cc/")) self.setCentralWidget(self.browser) def setCenterPosition(self): # 获取屏幕坐标系 screen = QDesktopWidget().screenGeometry() # 获取自身的窗口坐标系 size = self.geometry() newLeft = (screen.width() - size.width()) / 2 newTop = (screen.height() - size.height()) / 2 self.move(newLeft, newTop) if __name__ == '__main__': # 程序的入口 app = QApplication(sys.argv) win = UsingTest() win.setWindowIcon(QIcon("./excel_wrist.ico")) win.setCenterPosition() win.show() sys.exit(app.exec_())
代码运行结果:
首先搭建客户端网页HTML
想法是这样的,那么借助js我们可以获取鼠标在网页的位置,那么将网页呈现的桌面画面与实际桌面相称,进行从而远程控制。
$(document).click(
function (event) {
event = event || window.event;
var x = event.offsetX || event.originalEvent.layerX;
var y = event.offsetY || event.originalEvent.layerY;
var x_rate = x / document.body.clientWidth;
var y_rate = y / document.body.clientHeight;
}
);
如上的Javascript代码就是获取鼠标点击网页页面时候,鼠标位于网页页面的位置坐标(坐标百分比表示),那么我们可以把这个坐标的值转发到服务器端,通过pyautogui进行对应的操作即可。
发送的时候,采用Ajax发送模式,就是不刷新网页就进行发送数据:
function sendPointerPosition(xrate, yrate) {
$.ajax({
url: "/pointer?xrate=" + xrate + "&yrate=" + yrate,
type: "get",
success: function (data) {
console.log(data)
},
error: function (error) {
alert(error)
}
})
}
客户端页面的代码完整展示:
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script> <title>唤醒手腕</title> </head> <body> <img src="{{ url_for('video_feed') }}"> <style> * { padding: 0; margin: 0 } img { width: 100%; } </style> <script> $(document).click( function (event) { event = event || window.event; var x = event.offsetX || event.originalEvent.layerX; var y = event.offsetY || event.originalEvent.layerY; var x_rate = x / document.body.clientWidth; var y_rate = y / document.body.clientHeight; sendPointerPosition(x_rate, y_rate) } ); function sendPointerPosition(xrate, yrate) { $.ajax({ url: "/pointer?xrate=" + xrate + "&yrate=" + yrate, type: "get", success: function (data) { console.log(data) }, error: function (error) { alert(error) } }) } </script> </body> </html>
首先搭建服务端媒体流传输,传输电脑实时画面
这边就是采用pyautogui进行捕捉电脑的画面,并且服务器要对接收到的坐标数据进行执行的操作,展示如下所示:
import pyautogui from flask import Flask, render_template, Response, request import io app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/pointer') def pointer(): x = int(float(request.args["xrate"]) * 1920) y = int(float(request.args["yrate"]) * 1080) # 执行点击操作 pyautogui.click(x, y) return "success" def gen(): while True: screenShotImg = pyautogui.screenshot() imgByteArr = io.BytesIO() screenShotImg.save(imgByteArr, format='JPEG') imgByteArr = imgByteArr.getvalue() frame = imgByteArr yield (b'--frame\r\n Content-Type: image/jpeg\r\n\r\n' + frame) @app.route('/video_feed') def video_feed(): return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='192.168.43.247', debug=True, threaded=True)
构建远程控制桌面gui,将网页嵌入gui应用程序
import sys from PyQt5.QtCore import QUrl from PyQt5.QtGui import QIcon from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtWidgets import QApplication, QDesktopWidget from PyQt5.QtWidgets import QMainWindow class UsingTest(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setWindowTitle("唤醒手腕") self.setMaximumSize(1600, 900) self.setMinimumSize(1600, 900) self.browser = QWebEngineView() self.browser.load(QUrl("http://192.168.1.102:5000/")) self.setCentralWidget(self.browser) def setCenterPosition(self): # 获取屏幕坐标系 screen = QDesktopWidget().screenGeometry() # 获取自身的窗口坐标系 size = self.geometry() newLeft = (screen.width() - size.width()) / 2 newTop = (screen.height() - size.height()) / 2 self.move(newLeft, newTop) if __name__ == '__main__': # 程序的入口 app = QApplication(sys.argv) win = UsingTest() win.setWindowIcon(QIcon("./excel_wrist.ico")) win.setCenterPosition() win.show() sys.exit(app.exec_())
当然可以把gui桌面应用进行打包成exe,在另一台电脑上运行。我这边没有另一台电脑,只能在扩展展示:
可以发现电脑的实时状态已经呈现,我们点击gui上的对应位置,其实在真实电脑中也会同样的执行操作。
就比如我们用鼠标点击gui画面中的windows菜单图标,js会把我们的点击位置传给真实电脑的服务器应用中,然后执行对应的操作,展示如下:
总结:我们采用的同一台电脑上测试,其实建议用另一台笔记本进行操作,这样的话效果会更加的明显。当前这仅仅是单击事件而已,如果加强功能,也可以增加双击,或者长按拖拽的事件。
安装第三方库 pyinstaller
pip install pyinstaller
然后打包exe,若需将xxx.py文件打包,只需在终端执行:
pyinstaller xxx.py
特别注意:终端需切换至xxx.py文件所在目录下
pyinstaller 常用可选项及说明:
-F:打包后只生成单个exe格式文件;
-D:默认选项,创建一个目录,包含exe文件以及大量依赖文件;
-c:默认选项,使用控制台(就是类似cmd的黑框);
-w:不使用控制台;
-p:添加搜索路径,让其找到对应的库;
-i:改变生成程序的icon图标。
然后我们可以发现在目录下生成dist文件夹:
然后我们运行main.exe文件:
这部分借鉴白金之星1717博主:解决pyinstaller打包py文件运行exe闪退等诸多疑难杂症
在打包之前,你需要安装pyinstaller,如果你是使用的虚拟环境,在打包前需要在命令行里激活你安装了pyinstaller的那个虚拟环境。
在使用pyinstaller打包python程序的时候大概分为两种请况:
当要打包的文件为多个py文件,这种情况一般你的代码较多,项目较大,可能你写了一个GUI界面py文件,但这个文件调用了其他文件的函数什么的。
这个时候你需要生成spec文件来打包,这里假设你的要打包的主文件为test.py,首先在命令行中,cd到项目的相对目录下,然后输入:
pyi-makespec test.py
之后会在当前目录下生成一个test.spec,你可以在pycharm中打开这个文件,里面的内容大概是这样的,展示如下所示:
你需要把你的除了主文件以外的其他py文件也写到 a = Analysis([‘GUI.py’], 的这个列表中,像这样
Analysis(['GUI.py', 'test1.py', 'E:\\a\\test2.py']
如果你的其他py文件和你要打包的主文件test.py不在同一个目录,那么你在list中需要输入这个py文件的绝对地址。
如果你的项目调用了一些图片、dll等二进制文件,你也需要将他们打包进去,不然程序无法正常运行,你可以在spec文件中的datas这个list中添加,方法和上面那个一样,不过最好填绝对地址,也可以等你项目打包完了在copy到你的那个exe文件的目录下。
这个种情况,你在程序中调用这些资源的时候最好用相对地址,不然程序到了别人电脑上就找不到地址了,大致只需要配置这些东西啦,其他东西都不是必须的。
然后在刚刚的命令行中输入:pyinstaller -D test.spec 就开始打包了,在这里-D是打包成一个文件夹,-F是打包成一整个文件(传说打包成一整个文件打包缓慢,容易出错,因此不推荐使用,我也没试过)
args | information |
---|---|
-D | –onedir Create a one-folder bundle containing an executable (default) |
-F | –onefile Create a one-file bundled executable. |
同理打包完成后可以在dist目录下找到打包好的exe文件
运行exe文件刹那闪退如何解决?
最常见的问题就是闪退,这种错误让人最烦,因为报错都没看到就结束了,想解决都无从下手,之前我还想过用qq截图,当他报错的一瞬间按下截图快捷键,对手速的要求极高,十分考验程序猿的年龄、婚否等等综合素质,然后2分钟后我想了一个简单的方法,首先打开命令行,然后再命令行中输入你的exe文件的地址:
这样就能够展示出相应的报错的信息了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。