下面直接使用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
main函数加载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子类进行调用
自定义继承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)
MainWindow窗口显示图片
首先我们设计好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_())
运行的结果展示:马赛克是为了保护博主丑陋的模样,谢谢配合
点击保存最近一次画面就会d窗,文件保存的路径提示:
在新版本中的需要自行下载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会把我们的点击位置传给真实电脑的服务器应用中,然后执行对应的 *** 作,展示如下:
总结:我们采用的同一台电脑上测试,其实建议用另一台笔记本进行 *** 作,这样的话效果会更加的明显。当前这仅仅是单击事件而已,如果加强功能,也可以增加双击,或者长按拖拽的事件。
实现python gui程序打包成exe安装第三方库 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文件
- 要打包的文件为多个py文件
当要打包的文件为多个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文件的地址:
这样就能够展示出相应的报错的信息了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)