PYQT5 系列(一)——参考自《弗兰克万岁》

谁说胖子不能爱 提交于 2020-03-23 17:18:57

源:简书地址-------------->弗兰克万岁<--------------简书地址

PYQT5 (一)MAIN.PY标准开局

1 import sys
2 from PyQt5.QtWidgets import QApplication
3 
4 from lib.main_window import main_window
5 
6 if __name__=='__main__':
7     app = QApplication(sys.argv)
8     m=main_window()
9     sys.exit(app.exec_())
View Code

PYQT5(二)解决子线程闪退的问题

一般情况下是因为你的window没有保存好导致的
举个例子:
我在一个class 为 test的窗口类中写了一个方法

def createNewWindow(self):
    newWindow=QDialog()
    testWindow=MyPersonalPrograme(newWindow)

如果你这么写的话一般来讲,窗口都是一闪而逝的,可以试试改为

def createNewWindow(self):
    self.newWindow=QDialog()
    testWindow=MyPersonalPrograme(self.newWindow)
View Code

PYQT5(三)设置窗口背景颜色和无边框属性,和置顶

#在窗口初始化的时候加入就可以了
#self.window是QMainWindow()
  
from PyQt5.QtWidgets import  QApplication,QMainWindow
from PyQt5 import QtGui, QtCore

        palette1 = QtGui.QPalette()
        palette1.setColor(palette1.Background,QtGui.QColor(255,255,255))
        self.window.setPalette(palette1)

     window.setWindowFlags(Qt.Qt.FramelessWindowHint|Qt.Qt.WindowStaysOnTopHint)#无边框,置顶
        self.window.setAttribute(Qt.Qt.WA_TranslucentBackground)#透明背景色
        
View Code

PYQT5(四)PYCHARM配置

此篇可以详见源:https://www.jianshu.com/p/b5322f8cdcd1

亦可参考我之前的博客:https://www.cnblogs.com/wohuiyijiu/p/12454130.html

(五没找着...)

PYQT5(六)ListWidget列表视图添加按钮以及绑定事件

def GenerateBtn(self,pid):

    viewBtn = QtWidgets.QPushButton('查看')

    viewBtn.setStyleSheet(''' text-align : center;

    background-color : DarkSeaGreen;

    height : 30px;

    border-style: outset;

    color:white;

     font : 13px; ''')

    viewBtn.clicked.connect(lambda:self.jump(pid))

    return viewBtn
View Code
def jump(self,pid):

    if id:

        self.son.pid=pid

        if not self.window.isVisible():

        self.son.window.hide()

        self.window.show()

    else:

        self.window.hide()

        self.son.window.show()

        self.sql.log(4,self.guige, pid)

        self.son.accept()

def buttonForRow(self,res):

    # 列表控件QTableWidget生成列表

    self.result_list.clear()#result_list就是Qtablewidget

    for i in range(0,len(res)):

        item =self.result_list.horizontalHeaderItem(i)

        self.result_list.setHorizontalHeaderItem(i, item)

        self.result_list.setItem(i,0,QtWidgets.QTableWidgetItem(str(res[i][0])))

        self.result_list.setItem(i,1, QtWidgets.QTableWidgetItem(str(res[i][1])))

        btn=self.GenerateBtn(res[i][1])

        self.result_list.setCellWidget(i,2,btn)
View Code

PYQT5(七)QComboBox下拉菜单

下拉菜单的控件名称是QComboBox()
先引入PyQt5.QtWidgets

然后就可以通过QtWidgets 引入QcomboBox了

--------------------------------------------------
from PyQt5.QtWidgets import QApplication,QMainWindow,QDialog

if __name__ == '__main__':

app = QApplication(sys.argv)

QDialog = QDialog()

s=Dialog(QDialog)#Dialog类是自己写的,初始化类

QDialog.show()

sys.exit(app.exec_())

--------------------------------------------------
self.country_box = QtWidgets.QComboBox(Dialog)#Dialog从初始化的时候传参进来放在这里使用

self.country_box.setGeometry(QtCore.QRect(850,231,291,31))

self.country_box.setObjectName("country_box")

self.country_box.addItem("")#先添加一个下拉菜单空位
--------------------------------------------------
self.combo_box.setItemText(0, _translate("Dialog","test combo value"))#该函数只能设置内容,不能新增
--------------------------------------------------
self.country_box.setItemText(1, _translate("Dialog","test 2"))
--------------------------------------------------
如果要新增的话可以直接使用addItem("这里填入文本内容")
--------------------------------------------------
self.country_box.currentText()#发生变动后获取当前选择的内容
--------------------------------------------------
附上常用函数
重载(动态修改内容)

insertItem()

setItemText()
如果组合框的当前项目发生更改(状态改变)

currentIndexChanged()

activated()

highlighted()

移除内容

removeItem()

clear()

获取当前内容

currentText()

绑定事件

self.combobox.currentIndexChanged.connect(self.action)
View Code

PYQT5(八)QCheckBox复选框使用范例

首先创建一个布局,这一段是pyqt5自带的编辑器生成的

---------------------------------------------
self.gridLayoutWidget = QtWidgets.QWidget(QDialog)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(830,140,321,141))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.model_gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.model_gridLayout.setContentsMargins(0,0,0,0)
        self.model_gridLayout.setObjectName("model_gridLayout")


然后再初始化,添加各种数值,因为checkbox比较多,这里用的一个数组循环赋值
---------------------------------------------
       for i in data:
            if i[0]:
                if index<4:
                    checkbox = QtWidgets.QCheckBox(i[0]+'-'+i[1],self.gridLayoutWidget)
                    self.model_girdlayout.addWiget(checkbox,x,index,1,1)
                    index+=1
                else:
                    index=0
                    x+=1
                self.model_widgets.append(checkbox)

model_widgets是用来保存每一个checkbox的,所以不要忘了先初始化变量

如果出现在循环体中绑定点击事件,发生事件混乱现象,可以将创建checkbox再封装一层方法,便可以解决问题。
---------------------------------------------
    def create_checkboc(self,name,id):
        checkbox = QtWidgets.QCheckBox(name+'-'+id,self.gridLayoutWidget)
        checkbox.stateChanged.connect(lambda : self.show(name,id))
        return checkbox
---------------------------------------------
关闭checkbox可以按照如下方法
close() 关闭复选框(并未彻底丢弃)

deleteLater()删除复选框)

附上checkbox的一些常用函数

isChecked()判断函数是否被选中

setChecked()设置是否选择,True为选中。
View Code

PYQT5(九)pyinstaller打包运行报错failed to execute script main,缺少queue包

pyqt5写完win32 应用程序后,经过pyinstaller打包成单个文件,运行弹出错误提示框:failed to execute script main

pycharm中pyinstaller打包参数:

Program:C:\Python\Python35\Scripts\pyinstaller.exe

Parameters: -w -F $FileName$

Working directory: $FileDir$

分析:

经google,发现pyinstaller 有--hidden-import 选项

    --hidden-import MODULENAME, --hiddenimport MODULENAME

              Name an import not visible in the code of the

                script(s). This option can be used multiple times.

解决:

打包时加上 --hidden-import=queue

即Parameters配置修改为:

Parameters:--hidden-import=queue -w -F $FileName$

eg:

pyinstaller --hidden-import=queue -w -F -i test.ico main.py



问题2:

ImportError: No module named ‘queue‘  

Failed to execute script final_exam2  

然后自己手工导入queue模块,并没有报错。

打包时加上 --hidden-import=queue



在尝试重新打包并且使用--hidden-import queue 后,程序能够正常运行。
View Code

PYQT5(十)解决win10向下兼容xp的问题

更新于2020年2月17日
关于开发兼容windowsxp系统,并使用pyinstaller 打包的pyqt5软件。
如果有成功在win10系统编译,同时在xp系统上跑的大神,麻烦艾特我教我一下,或者有正在研究的可以找我讨论一下,网上的资料基本上是坑人的,或者抄来抄去的。
目前来看,最好的方案具体操作步骤如下:

在虚拟机中跑一个xp(如果有xp系统的机子当然更好啦)
我用是virtualbox

2.下载python3.4版本(xp系统最高支持到python3.4)
链接就不上了,直接百度搜索python就有一大堆。

安装pywin32
https://sourceforge.net/projects/pywin32/files/pywin32/Build%20220/pywin32-220.win32-py3.4.exe/download

然后点击安装pywin32的安装文件

安装Pyinstaller3.2.1
-------------------------------------------
安装命令:pip install pyinstaller==3.2.1
-------------------------------------------
到下面的连接中下载pyqt5 python3.4 专用版
附上链接,注意检查位数,我用的是32位的。
这里贴上一个5.5.1的版本,亲测可用。
https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/

by the way 如果安装失败的话,也可以试试
试试 pip install python-qt5

使用exe文件安装后,pip list 中不显示pyqt5
网上说是python 32位和pyqt5的exe包对不上。
结合本人尝试,使用Pyqt5-5.5.1的版本的对应位数的安装包,安装后别管list,直接打包也可以

打包测试
贴上pyinstaller的简单使用教程
-------------------------------------------
 pyinstaller -p C:\Python34\Lib\site-packages\PyQt5 -F -w main.py**
-p  搜索额外的库文件地址
-F 注意大小写,生成的文件是单个exe执行文件
-w 无console窗口
-------------------------------------------

常见错误
-------------------------------------------
from PyQt5 import QtCore, QtGui, QtWidgets
ImportError: cannot import name 'QtCore'
-------------------------------------------
据说别的版本的pyinstaller各种bug,网络上的那些抄来抄去的博客没什么好看的,说有bug但是不说是什么bug,无非就是找不到你的pyqt库的bug。
估计是上一步有问题,可以在cmd里试试
-------------------------------------------
pip uninstall pyinstaller
pip install pyinstaller==3.2.1
-------------------------------------------
所以最好还是下载pyinstaller3.2.1
-------------------------------------------
no model name 'queue'
-------------------------------------------
pyinstaller -F --hidden-import=queue final_exam2.py
-------------------------------------------
pip install openpyxl 失败的解决方法
-------------------------------------------
pip install openpyxl==2.5.14
View Code

PYQT5(十一)实现右键菜单

窗体绑定右键事件
----------------------------------------------
        self.window.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.window.customContextMenuRequested.connect(self.rightMenuShow)
----------------------------------------------
  设置右键菜单事件,和后续的动作
----------------------------------------------
def rightMenuShow(self):
        try:
            self.contextMenu = QMenu()
            self.actionA = self.contextMenu.addAction(u'动作a')
            self.contextMenu.popup(QCursor.pos())  # 2菜单显示的位置
            self.actionA.triggered.connect(self.actionHandler)
            self.contextMenu.show()
        except Exception as e:
            print(e)
    def actionHandler(self):
        print('action')
View Code

PYQT5 (十二)图片控件,截图功能

主要是使用Qlabel来实现
----------------------------------------------
获取宽度:Qlabel.width()

获取高度:Qlabel.height()
----------------------------------------------
def cut(self):

    screen = QApplication.primaryScreen()

# pix = screen.grabWindow(self.window.winId())

    pix = screen.grabWindow(self.img_label.winId())

pix.save("test.jpg")

----------------------------------------------
图片太大的解决方法:
----------------------------------------------
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)

self.scrollArea.setGeometry(QtCore.QRect(20,60,841,591))

self.scrollArea.setWidgetResizable(True)

self.scrollArea.setObjectName("scrollArea")

self.MyScroll = QtWidgets.QWidget()

self.MyScroll.setGeometry(QtCore.QRect(0,0,839,589))

self.MyScroll.setObjectName("MyScroll")

self.MyScroll.setMinimumSize(7000,7000)

#scrollArea就对了
----------------------------------------------
图片控件(QImage)
----------------------------------------------
def pic(self):

# print(self.window.size)

    pix = QPixmap('icon/123.png')

scale=1

    print(pix.width())

if pix.width()

self.img_label.setGeometry(10,10,pix.width()*scale,pix.height()*scale)

else:

self.img_label.setScaledContents(True)

# self.img_label.setGeometry(10, 10, self.width*scale,  self.height*scale)

    self.img_label.setStyleSheet("border: 2px solid red")

self.img_label.setPixmap(pix)

# self.img_label.mouseDoubleClickEvent(self.zoom())
View Code

PYQT5(十三)配合微信截图并保存图片

# -*- coding:utf-8 -*-

import ctypes

import os

from PyQt5.QtWidgets import QApplication

def capture():

    clipboard=QApplication.clipboard()

    try:

        dll = ctypes.cdll.LoadLibrary('PrScrn.dll')

        dataImage = clipboard.pixmap()

        dataImage.save('Grab.png')

    except Exception:

        print("Dll load error!")

        return

    else:

        try:

            dll.PrScrn(0)

            dataImage = clipboard.pixmap()

            dataImage.save('Grab.png')

        except Exception:

            print("Sth wrong in capture!")

            return
View Code

PYQT5 (十四)配合PILLOW使用

主要解决两种不同的库之间图片来回调用问题。
添加logo-------------------------------
    im = Image.open(path)
    im = im.convert("RGBA")
    im=im.resize((600,500),Image.ANTIALIAS)
    try:
        mark = Image.open("image/logo.png")
        s=im.size
        layer = Image.new('RGBA', s, (0, 0, 0, 0))#底层画布
        layer.paste(mark, (int((s[0]-mark.size[0])/2) , int((s[1]-mark.size[1])/2)))#添加水印
        out = Image.composite(layer, im, layer)#整合在一起
        data = out.tobytes("raw", "RGBA")#转换成byte格式
        qim = QtGui.QImage(data, s[0], s[1], QtGui.QImage.Format_RGBA8888)#转换成qimage格式
        qim.save('tttt.jpg')#保存在本地
        return qim#同时返回
        # pix=QtGui.QPixmap.fromImage(qim)
    except Exception as e:
        print('error',e)
添加透明度-------------------------------
#有bug
mark.putalpha(50)

https://www.cnblogs.com/RChen/archive/2007/03/31/pil_thumb.html
View Code

PYQT5(十五) pushbutton绑定事件

self.setting_btn.clicked.connect(lambda :init_setting(self))
View Code

PYQT5(十六)图片容器

def pic(self):
        # print(self.window.size)
        pix = QPixmap('icon/123.png')
        scale=1
        if pix.width()<self.width:#对比宽度
self.img_label.setGeometry(10,10,pix.width()*scale,pix.height()*scale)
        else:
            self.img_label.setScaledContents(True)
            # self.img_label.setGeometry(10, 10, self.width*scale,  self.height*scale)
        self.img_label.setStyleSheet("border: 2px solid red")

        self.img_label.setPixmap(pix)

        # self.img_label.mouseDoubleClickEvent(self.zoom())
View Code

PYQT5(十七)打开文件目录

 def setPicPath(self):
        path=self.load_last_path()
        file=QDialog()
        fname,ftype=QFileDialog.getOpenFileName(file,'open',path)
        print(fname)

        if fname:
            res = self.save_last_path(fname)
            if res == 0:
                print('false occured in path saving processing')
View Code
如果要获取地址或者别的可以试试下面这些函数

 

 

 

getOpenFileNames 获取多个文件的地址,返回的是一个数组

getOpenFileUrl 返回PyQt5.QtCore.QUrl 对象,不知道什么用途

PYQT5 (十八)文件拖放(drag and drop)并获取文件信息

#通过重写QScrollArea 类实现的文件拖拽操作
class MyScrollWidget(QtWidgets.QScrollArea):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            try:
                event.setDropAction(Qt.Qt.CopyAction)
            except Exception as e:
                print(e)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        try:
            if event.mimeData().hasUrls:
                event.setDropAction(Qt.Qt.CopyAction)
                event.accept()
                links = []
                for url in event.mimeData().urls():
                    links.append(str(url.toLocalFile()))
                print(links)
            else:
                event.ignore()
        except Exception as e:
            print(e)```
View Code

PYQT5(十九)标题栏如何隐藏放大缩小按钮,固定窗口大小

self.window.setWindowFlags(QtCore.Qt.WindowTitleHint|QtCore.Qt.WindowCloseButtonHint)
---------------------
固定窗口大小
self.window.setFixedSize(100,200)
View Code

PYQT5(二十) 设置窗口小图标和标题

from PyQt5 import QtCore, QtGui#相关库
.
.
.#这里省略中间的一些代码
        _translate = QtCore.QCoreApplication.translate
        self.window.setWindowIco(QIcon('./test.jgp'))
        self.window.setWindowTitle(_translate("window", "CLIENT INFO"))
        self.window.setWindowFlags(QtCore.Qt.WindowTitleHint|QtCore.Qt.WindowCloseButtonHint)#隐藏关闭按钮
View Code

PYQT5(二十一)设置窗口位置

self.window.move(500,500)
View Code

PYQT5(二十二)Qlabel边框和背景颜色

        self.setFrameShape(QFrame.Box)
        self.setStyleSheet('border-width: 1px;border-style: solid;
border-color: rgb(255, 170, 0);background-color: rgb(100,149,237);')
        print('dialog_label')
View Code

PYQT5(二十三)FOCUS焦点事件

        self.setFocusPolicy(QtCore.Qt.ClickFocus)

    def focusInEvent(self, QFocusEvent):
        print('focus in')
        pix = QPixmap('icon/action2.png')
        self.setPixmap(pix)
    def focusOutEvent(self, QFocusEvent):
        pix = QPixmap('icon/123.png')
        self.setPixmap(pix)

----------------------
https://www.jianshu.com/p/ef674f39499d
View Code

PYQT5(二十四)文本框回应回车事件

self.sendLineEdit.returnPressed.connect(self.SendData)
这个是LineEdit按下Enter按键触发SendData函数
View Code

PYQT5(二十五) QLabel自适应

让QLabel自适应text的大小,直接用下面的代码:
LabelName->adjustSize();

让QLabel能够自动判断并换行显示:
LabelName->setGeometry(QRect(328, 240, 329, 27*4)); //四倍行距
LabelName->setWordWrap(true);
LabelName->setAlignment(Qt::AlignTop);
View Code

PYQT5(二十六)打开外部链接

def outer(self):
    QtGui.QDesktopServices.openUrl(QtCore.QUrl('http://www.hao123.com'))
View Code

PYQT5(二十七)输出log到文件中

with open('log','a+') as l:
        print("date.txt exits%s \n"%now, file=l)
View Code

PYQT5(二十八)文本框自动跟随文本多少改变大小

需要重写控件,我用的是QTextedit,其他的应该也是差不多的。

self.document().contentsChanged.connect(self.textAreaChanged)


def textAreaChanged(self):
        #判断文本框长度变化
        # self.document().adjustSize()
        newHeight = self.document().size().height() + 30
        print(newHeight)

        if newHeight>300:
            self.setGeometry(QtCore.QRect(self.X, self.Y, 141, 300))
        else:
            self.setGeometry(QtCore.QRect(self.X, self.Y, 141, newHeight))
        self.setLineWrapMode(1)
View Code

PYQT5(二十九)多屏幕适配问题

        
self.move(int(QApplication.desktop().screenGeometry(0).width())-180, 90, )
#  screenGeometry(0)就是主屏幕
#  1的话是分屏1,以此类推
View Code

PYQT5(三十)去掉窗口标题栏,去掉任务栏显示,窗口置顶的方法

this->setWindowFlags
(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); 
// 去掉标题栏,去掉任务栏显示,窗口置顶

翻译成pyqt---------------------
window.setWindowFlags
(Qt.Qt.FramelessWindowHint|Qt.Qt.WindowStaysOnTopHint|Qt.Qt.Tool)
View Code

PYQT5(三十一)保存窗口位置下次使用

from PyQt5.Qt import QMainWindow,QDialog
import json
window=QMainWindow()
def save_location(self):
        with open('window_location.txt','w') as f:
            data={'x':self.window.x(),'y':self.window.y()}
            f.write(json.dumps(data))
    def load_laction(self):
        with open('window_location.txt', 'r') as f:
            txt=f.read()
            print(txt)
            j=json.loads(txt)
            return j
View Code

PYQT5(三十二)QMainWindow 重写CloseEvent

    def closeEvent(self, e):
        e.ignore()
        self.hide()
        self.save_location()
View Code

PYQT5(三十三)输入对话框

    QID = QInputDialog()
    QID.setGeometry(int((screen.width() - size.width()) / 2),
                    int((screen.height() - size.height())) / 2, 200, 200)
    text, ok = QID.getText(self.window, '输入', '标题')
View Code

PYQT5(三十四)日期控件

    self.dateEdit.setDate(QDate.currentDate())
    self.dateEdit.setCalendarPopup(True)
View Code

三十五 没啥用,作者的近况

 

PYQT5(三十六)获取屏幕分辨率大小

 

        
        from PyQt5.QtWidgets import QApplication, QWidget
        self.desktop = QApplication.desktop()
        self.screenRect = self.desktop.screenGeometry()
        self.height = self.screenRect.height()
        self.width = self.screenRect.width()
View Code

PYQT5(三十七)表格控件调整列宽

列宽自动分配
--------------------------------------
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
--------------------------------------
self.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
--------------------------------------
这个是行宽的
此种模式下,我们没法手动调整列宽。

手动调整
--------------------------------------
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)

固定值
--------------------------------------
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)

用户无法调整该部分的大小。该部分只能使用resizeSection()以编程方式调整大小。节大小默认为defaultSectionSize。

随内容分配列宽
--------------------------------------
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)

我们把它和列宽自动分配结合在一起看,效果立马显现。

上面两种方式结合
--------------------------------------
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)


列宽是自动分配的,但是第一列我们可以手动调整宽度,而表格整体的列宽仍是自动分配的。第二、三列我们没有办法调整列宽,这个是自动分配的。

自定义列宽

--------------------------------------
1. self.tableWidget.setColumnWidth(0, 40)
2. self.tableWidget.setColumnWidth(1, 200)
3. self.tableWidget.setColumnWidth(2, 200)
View Code

PYQT(三十八)PDF阅读器

https://blog.csdn.net/weixin_43773093/article/details/88783757

随便复制了一下,以防走丢。
UI 设计
首先使用 Qt Designer 设计出图形界面:

新建一个 MainWindow 主界面,然后设置一个 toolbar,并在 toolbar 中添加三个 action,并为每个 action 设置好相应图标。

也可以直接 compile 我制作好的 PyReader.ui 文件,或者导入 Ui_PyReader.py 文件。

依赖要求
Python3
PyQt5
PyMuPDF

主要任务
我们使用 PyMuPDF 来解析 PDF ,来获取 PDF 文本信息。

安装
我们只须在 cmd 中输入:pip install PyMuPDF,即可安装 PyMuPDF。

导入

导入 PyMuPDF
import fitz
在本节中,我们只需了解以下几个基本操作:

fitz.open() 函数用来读取 PDF 文件内容,doc.loadPage() 函数用来获取具体某一页的信息。特别的 ,我们使用loadPage(0) 来获取封面信息。

# 读取 PDF
doc = fitz.open(fname)
# 获取第 n 页内容
page = doc.loadPage(n)
本节主要的内容就是把封面渲染到主界面中,并完成添加与删除封面的任务。

显示表格
我们采用 QtWidgets.QTableWidget 表格控件来显示封面。

首先让我们设置表格样式与功能:

其中,我们设置了单元格的纵横比为 4 : 3,以及其他的一些静态属性,并将 self.table 与右键菜单绑定,支持点击单元格调用 self.generateMenu 函数。
----------------------------------------------------
def _setTableStyle(self):
    # 开启水平与垂直滚轴
    self.table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
    self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
    # 设置 5 行 8 列 的表格
    self.table.setColumnCount(8)
    self.table.setRowCount(5)
    # 设置标准宽度
    self.width = self.screen.width() // 8
    # 设置单元格的宽度
    for i in range(8):
        self.table.setColumnWidth(i, self.width)
    # 设置单元格的高度
    # 设置纵横比为 4 : 3
    for i in range(5):
        self.table.setRowHeight(i, self.width * 4 // 3)
    # 隐藏标题栏
    self.table.verticalHeader().setVisible(False)
    self.table.horizontalHeader().setVisible(False)
    # 禁止编辑
    self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
    # 不显示网格线
    self.table.setShowGrid(False)
    # 将单元格绑定右键菜单
    # 点击单元格,调用 self.generateMenu 函数
    self.table.setContextMenuPolicy(Qt.CustomContextMenu)
    self.table.customContextMenuRequested.connect(self.generateMenu)
----------------------------------------------------
加封面
首先让我们来看如何生成 TableWidget 可显示的 图像类文件。

我们通过 doc.loadPage(0) 获取页面对象,并传递给 render_pdf_page() 函数,设置缩放比为 1 : 1。首先构建 QImage 对象,在通过 convertFromImage 函数将 QImage 对象转化为可显示对象。
----------------------------------------------------
# 显示 PDF 封面
# page_data 为 page 对象
def render_pdf_page(page_data, for_cover=False):
    # 图像缩放比例
    zoom_matrix = fitz.Matrix(4, 4)
    if for_cover:
        zoom_matrix = fitz.Matrix(1, 1)
    
    # 获取封面对应的 Pixmap 对象
    # alpha 设置背景为白色
    pagePixmap = page_data.getPixmap(
        matrix = zoom_matrix, 
        alpha=False) 
    # 获取 image 格式
    imageFormat = QtGui.QImage.Format_RGB888 
    # 生成 QImage 对象
    pageQImage = QtGui.QImage(
        pagePixmap.samples,
        pagePixmap.width, 
        pagePixmap.height, 
        pagePixmap.stride,
        imageFormat)

    # 生成 pixmap 对象
    pixmap = QtGui.QPixmap()
    pixmap.convertFromImage(pageQImage)
    return pixmap
----------------------------------------------------
接着,我们就要想单元格中添加封面图片:

我们使用工具栏中的 + 号来添加 PDF 封面。
----------------------------------------------------
self.addbar.triggered.connect(self.open),当点击 + 号时,就会调用 self.open 函数。
----------------------------------------------------
我们通过 getOpenFileName() 函数 来获取文件地址,self 后面的三个参数分别是窗口名称,文件默认路径以及支持的文件类型,这个函数返回文件的地址。

filter_book() 函数用来确保不会重复显示同一本书的封面。
----------------------------------------------------
def getfile(self):
    # 打开单个文件
    fname, _ = QFileDialog.getOpenFileName(self, 'Open files', './', '(*.pdf)')
    return fname

def open(self):
    # 打开文件
    fname = self.getfile()
    if self.filter_book(fname):
        self.setIcon(fname)
                
# 获取无重复图书的地址
def filter_book(self, fname):
    if not fname:
        return False
    if fname not in self.booklist:
        self.booklist.append(fname)
        return True
    return False      
----------------------------------------------------               
然后,我们就要将 PDF 封面渲染到主界面上:

label.setScaledContents(True) 使得图片可以充满 label。self.table.setCellWidget(self.x, self.y, label) 用来设置标签的行与列。最后确保每八个元素换行,换行后将列数清零。
----------------------------------------------------
def setIcon(self, fname):
    # 打开 PDF
    doc = fitz.open(fname)
    # 加载封面
    page = doc.loadPage(0)
    # 生成封面图像
    cover = render_pdf_page(page, True)
    label = QLabel(self)
    # 设置图片自动填充 label
    label.setScaledContents(True)
    # 设置封面图片
    label.setPixmap(QPixmap(cover))
    # 设置单元格元素为 label
    self.table.setCellWidget(self.x, self.y, label)
    # 删除 label 对象,防止后期无法即时刷新界面
    # 因为 label 的生存周期未结束
    del label
    # 设置当前行数与列数
    self.crow, self.ccol = self.x, self.y
    # 每 8 个元素换行
    if (not self.y % 7) and (self.y):
        self.x += 1
        self.y = 0
    else:
        self.y += 1
----------------------------------------------------
右键菜单
上面我们已经提到,如何将单元格与右键菜单绑定。

本次教程中,右键菜单只有两项,分别为开始阅读(暂未实现),以及删除图书。
----------------------------------------------------
def generateMenu(self, pos):
    row_num = col_num = -1
    # 获取选中的单元格的行数以及列数
    for i in self.table.selectionModel().selection().indexes():
        row_num = i.row()
        col_num = i.column()
    # 若选取的单元格中有元素,则支持右键菜单
    if (row_num < self.crow) or (row_num == self.crow and col_num <= self.ccol):
        menu = QMenu()
        # 添加选项
        item1 = menu.addAction('开始阅读')
        item2 = menu.addAction('删除图书')
        # 获取选项
        action = menu.exec_(self.table.mapToGlobal(pos))
        if action == item1:
            pass
        # 点击选项二,调用 self.delete_book 删除图书
        elif action == item2:
            self.delete_book(row_num, col_num)
----------------------------------------------------
接下来,让我们看如何删除图书:

首先维护一个 self.booklist ,里面储存无重复 PDF 文件地址。首先获取图书在 booklist 中的索引,在 booklist 中删除该元素。接着清空选中单元格之后(包含选中单元格)的所有单元格的内容。最后将 booklist 中 index 之后的图书地址重新显示到 table 上。简单地说,就是删除选中单元格,并将之后单元格向前挪一位。

----------------------------------------------------
# 删除图书
def delete_book(self, row, col):
    # 获取图书在列表中的位置
    index = row * 8 + col
    self.x = row
    self.y = col
    if index >= 0:
        self.booklist.pop(index)

    i, j = row, col
    while 1:
        # 移除 i 行 j 列单元格的元素
        self.table.removeCellWidget(i, j)
        # 一直删到最后一个有元素的单元格
        if i == self.crow and j == self.ccol:
            break
        if (not j % 7) and j:
            i += 1
            j = 0
        else:
            j += 1

    # 如果 booklist 为空,设置当前单元格为 -1
    if not self.booklist:
        self.crow = -1
        self.ccol = -1
    # 删除图书后,重新按顺序显示封面图片
    for fname in self.booklist[index:]:
        self.setIcon(fname)
----------------------------------------------------
View Code

PyQt5(三十九)QTableWidget(表单控件)自适应窗口大小、栏位大小调整及布局

https://blog.csdn.net/yl_best/article/details/84070231
View Code

PYQT5(四十)下载并安装配置QT-DESIGNER

https://www.jianshu.com/p/4df033879a3f
View Code

 

 

(1)找不着

PYQT5(2)MyScrollWidget拖放文件功能的实现 

class MyScrollWidget(QWidget):
    def __init__(self):
        super(QWidget, self).__init__()
        # self.resize(800, 600)
        self.move(0, 0)
        # self.setMouseTracking(False)
        self.last_time_move = 0
        self.last_time_move_x = 0
    def eventFilter(self,source, event):
        try:
            if event.type() == QEvent.MouseMove:
                print(event.pos().y(),event.pos().x())
                if self.last_time_move == 0:
                    self.last_time_move = event.pos().y()
                    self.last_time_move_x=event.pos().x()
                distance = (self.last_time_move - event.pos().y())/100
                distance_x = (self.last_time_move - event.pos().x())/100
                self.scroll(distance_x,0)
                self.last_time_move = event.pos().y()
                self.last_time_move_x=event.pos().x()
            elif event.type() == QEvent.MouseButtonRelease:
                self.last_time_move = 0
                self.last_time_move_x = 0
            return QWidget.eventFilter(self, source, event)
        except Exception as e:
            print(e)
#by the way 没能搞定y轴上的滚动,不过发现用滚轮也可以,就先放一放了,实现功能再回来优化
View Code

PYQT5(3)多线程QProgressBar卡死的问题

def init_progress(parent):
    m = wake_progress()
    parent.progress = m
    m.run()
    if not m.window.isVisible():
        m.window.show()

#激活方法

class wake_progress(QThread):
#线程类
    def __init__(self):
        super().__init__()
        self.window = QMainWindow()
        self.p=''
    def run(self):
        self.p =file_upload_statu_bar(self.window)

class file_upload_statu_bar(progress_bar):
#原始类
    def __init__(self,Form):
        print('progress bar')
        self.window=Form
        super().__init__()
        self.setupUi(Form)
        self.window.show()
    def change(self,name):
        self.label.setText(name)
View Code

出现进度条的线程卡死的情况

最后通过参考自知诸狭的文章
其中一段:
对于执行很耗时的程序来说,由于PyQt需要等待程序执行完毕才能进行下一步,这个过程表现在界面上就是卡顿;而如果在执行这个耗时程序时不断地运行QApplication.processEvents(),那么就可以实现一边执行耗时程序,一边刷新页面的功能,会给人一种相对更流畅的感觉,QApplication.processEvents()的使用方法是,在主函数执行耗时操作的地方,加入QApplication.processEvents(),processEvents()函数的使用方法简单来说就是刷新页面。

于是在循环内加入

from PyQt5.QtWidgets import QApplication
def slotAdd(self): 
  for n in range(10): 
  str_n = 'File index {0}'.format(n)
  self.listFile.addItem(str_n) 
  QApplication.processEvents()#这一句是关键
  time.sleep(1) 
View Code

就可以成功解决问题

PYQT5 (4)之QSystemTrayIcon实现窗口最小化到托盘

from PyQt5 import QtGui

from PyQt5.QtWidgets import QSystemTrayIcon


class MyTray(QSystemTrayIcon):
    def __init__(self):
        super().__init__()
        try:
            self.setIcon(QtGui.QIcon('icon/car.png'))
            self.activated.connect(self.iconClicked)
        except Exception as e:
            print(e)
    def bind(self,window):
        self.parent_window=window
    def test(self):
        try:
            self.parent_window.show()
        except Exception as e:
            print(e)

    def iconClicked(self,reason):
    #鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击"
        print('click')
        if reason == 2 :#2是双击
            self.test()
View Code

加一段添加二级菜单的功能,暂未试验过

    def showMenu(self):
        "设计托盘的菜单,这里我实现了一个二级菜单"
        self.menu = QMenu()
        self.menu1 = QMenu()
        self.showAction1 = QAction("显示消息1", self, triggered=self.showM)
        self.showAction2 = QAction("显示消息2", self,triggered=self.showM)
        self.quitAction = QAction("退出", self, triggered=self.quit)

        self.menu1.addAction(self.showAction1)
        self.menu1.addAction(self.showAction2)
        self.menu.addMenu(self.menu1, )

        self.menu.addAction(self.showAction1)
        self.menu.addAction(self.showAction2)
        self.menu.addAction(self.quitAction)
        self.menu1.setTitle("二级菜单")
        self.setContextMenu(self.menu)
View Code

PYQT5(5)带跳转按钮的QTableWidgets

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem


class btn_table(QTableWidget):
    def __init__(self,x,y,window,res):
        self.centralwidget = QtWidgets.QWidget(window)
        self.centralwidget.setObjectName("centralwidget")
        self.centralwidget.resize(500,500)
        super().__init__(self.centralwidget)
        self.setGeometry(QtCore.QRect(20, 10, 471, 401))
        self.setObjectName("client_table")
        self.setColumnCount(x)
        self.setRowCount(y)

        self.buttonForRow(res)

        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
    def buttonForRow(self,res):#添加内容并在最后一行添加一个按钮
        # requir:[[value1,value2,value3,...],[value1,value2,value3,value4,...]]
        self.clear()
        for i in range(0,len(res)):
            try:
                item = self.horizontalHeaderItem(i)
                self.setHorizontalHeaderItem(i, item)
            except Exception as e:
                print(e)
                t = QtWidgets.QTableWidgetItem()
                self.setHorizontalHeaderItem(i, t)
                item = self.horizontalHeaderItem(i)

            for a in range(0,len(res[i])):
                self.setItem(i,a,QtWidgets.QTableWidgetItem(str(res[i][a])))
                print(res[i][a])
                # self.setItem(i, 1, QtWidgets.QTableWidgetItem(str(res[i][1])))
            btn=self.GenerateBtn(res[i][1])
            self.setCellWidget(i,len(res[0]),btn)
    def GenerateBtn(self,clientid):
        viewBtn = QtWidgets.QPushButton('查看')
        viewBtn.setStyleSheet(''' text-align : center;
                              background-color : DarkSeaGreen;
                              height : 30px;
                              border-style: outset;
                              color:white;
                              font : 13px; ''')
        viewBtn.clicked.connect(lambda:self.jump(clientid) )
        return viewBtn
    def jump(self,clientid):
        print(clientid)
View Code

大概效果如下

 

PYQT(6)python3.4+pymssql+pyinstaller 编译exe 出错问题

我用的是pyinstaller -F -w来生成单独的exe 文件,总是出现
缺少__mssql什么的文件

百度一下得出解决办法:

http://www.tuicool.com/articles/7RbU3i

后来.py文件加了下面代码

import pymssql
import _mssql
_mssql.__version__

使用pyinstaller打包的时候主要注意这几个包
requests
pymssql
View Code

PYQT5(7)实现可以拖拽的窗体

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

    def mousePressEvent(self, event):
        if event.button() == Qt.Qt.LeftButton:
            self.m_flag = True
            self.m_Position = event.globalPos() - self.pos()  # 获取鼠标相对窗口的位置
            event.accept()
            self.setCursor(QCursor(Qt.Qt.OpenHandCursor))  # 更改鼠标图标

    def mouseMoveEvent(self, QMouseEvent):
        if Qt.Qt.LeftButton and self.m_flag:
            self.move(QMouseEvent.globalPos() - self.m_Position)  # 更改窗口位置
            QMouseEvent.accept()

    def mouseReleaseEvent(self, QMouseEvent):
        self.m_flag = False
        self.setCursor(QCursor(Qt.Qt.ArrowCursor))
View Code

PYQT5(8)重写Qlabel

from PyQt5 import Qt, QtCore
from PyQt5.QtWidgets import QLabel, QFrame
class dialog_label(QLabel):
def init(self,centralwidget):
super().init(centralwidget)
# self.dialog_label.setGeometry(QtCore.QRect(30, 30, 251, 91))
self.setFrameShape(QFrame.Box)
self.setStyleSheet('border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);')
print('dialog_label')

0人点赞
PYQT5进阶日志
View Code

PYQT5(9)QLabel 实现右键在点击位置弹出菜单,并绑定事件

class MyLabel(QLabel):
    def __init__(self,centralwidget):
#centralwidget 窗体参数
        super().__init__(centralwidget)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.rightMenuShow)#开放右键策略
    def rightMenuShow(self, point):
#添加右键菜单
            self.popMenu = QMenu()
            tj=QAction(u'添加', self)
            sc=QAction(u'删除', self)
            xg = QAction(u'修改', self)
            self.popMenu.addAction(tj)
            self.popMenu.addAction(sc)
            self.popMenu.addAction(xg)
#绑定事件
            tj.triggered.connect(self.test)
            sc.triggered.connect(self.test)
            xg.triggered.connect(self.test)
            self.showContextMenu(QtGui.QCursor.pos())
    def test(self):
        print('test')
    def showContextMenu(self, pos):
#调整位置
        '''''
        右键点击时调用的函数
        '''
        # 菜单显示前,将它移动到鼠标点击的位置

        self.popMenu.move( pos)
        self.popMenu.show()
View Code

PYQT5(10)Qlabel实现捕捉键盘按键事件

    def keyPressEvent(self, event):
        if (event.key() == Qt.Qt.Key_P):#P
            if QApplication.keyboardModifiers() == Qt.Qt.ShiftModifier:#shirft
                print("shift + p")
                self.talk_edit.show()
                self.talk_edit.setFocus()
            else:
                print("p")
                print('okokok')
View Code

https://blog.csdn.net/m0_37828248/article/details/79766580?utm_source=blogxgwz8

PYQT5(11)自适应文字高宽的Qtextedit

     self.width = 24
        self.height = 42
        self.edit.resize(self.width, self.height)
        self.document = self.edit.document()
        self.document.contentsChanged.connect(self.textAreaChanged)
        self.edit.setLineWrapMode(QTextEdit.NoWrap)
View Code
    def textAreaChanged(self):
        self.document.adjustSize()
 
        newWidth = self.document.size().width() + 10
        newHeight = self.document.size().height() + 20
        if newWidth != self.edit.width():
            self.edit.setFixedWidth(newWidth)
        if newHeight != self.edit.height():
            self.edit.setFixedHeight(newHeight)
View Code

PYQT5(12)可复用的自动保存窗口位置的frame

import json
import os
from PyQt5.QtWidgets import QMainWindow
class AutoSaveWindow(QMainWindow):
    def __init__(self,name=''):
        #注意初始化的时候要带上name参数
        super().__init__()
        self.name=name
        if os.path.exists('window_location_%s.txt'%self.name):
            self.load_location()
        #每次启动都检查位置并移动
        

    def closeEvent(self, *args, **kwargs):
        self.save_location()

    def save_location(self):
        with open('window_location_%s.txt'%self.name, 'w') as f:
            data = {'x': self.x(), 'y': self.y()}
            f.write(json.dumps(data))

    def load_location(self):
        with open('window_location_%s.txt'%self.name, 'r') as f:
            txt = f.read()
            print(txt)
            j = json.loads(txt)
            self.move(j['x'],j['y'])
View Code

PYQT5(13)重复绑定按钮事件需要做的一件事情

btn.disconnect()

PYQT5(14)pyqt5 QTreeWidget使用集锦(如右键菜单)

比较好的教程:https://zhuanlan.zhihu.com/p/36033317

 
image

【简介】

PyQT5中 QTreeWidget 例子

from PyQt5.QtWidgets import *
import sys

class TreeWidgetDemo(QMainWindow):
def **init**(self, parent=None):
super(TreeWidgetDemo, self).**init**(parent)
self.setWindowTitle('TreeWidget 例子')
self.tree = QTreeWidget()
# 设置列数
self.tree.setColumnCount(2)
# 设置头的标题
self.tree.setHeaderLabels(['Key', 'Value'])
# 设置自适应宽度
self.header().setSectionResizeMode(QHeaderView.ResizeToContents)
root = QTreeWidgetItem(self.tree)
root.setText(0, 'root')
root.setText(1, '0')

    child1 = QTreeWidgetItem(root)
    child1.setText(0, 'child1')
    child1.setText(1, '1')

    child2 = QTreeWidgetItem(root)
    child2.setText(0, 'child2')
    child2.setText(1, '2')

    child3 = QTreeWidgetItem(root)
    child3.setText(0, 'child3')
    child3.setText(1, '3')

    child4 = QTreeWidgetItem(child3)
    child4.setText(0, 'child4')
    child4.setText(1, '4')

    child5 = QTreeWidgetItem(child3)
    child5.setText(0, 'child5')
    child5.setText(1, '5')

    self.tree.addTopLevelItem(root)
    self.tree.clicked.connect(self.onTreeClicked)

    self.setCentralWidget(self.tree)

def onTreeClicked(self, qmodelindex):
    item = self.tree.currentItem()
    print("key=%s ,value=%s" % (item.text(0), item.text(1)))
View Code

启动一下试试

if **name** == '**main**':
app = QApplication(sys.argv)
tree = TreeWidgetDemo()
tree.show()
sys.exit(app.exec_())
View Code

分析判断是否是父项

def onTreeClicked(self, qmodelindex):
    item = self.tree.currentItem()
     if item.parent()==None:
        print("key=%s ,value=%s" % (item.text(0), item.text(1)))
        #None表示是最高一级
View Code

信号触发条件:

activated(QModelIndex) 当用户激活index指定的项目时,发出此信号
clicked(QModelIndex) 左键单击鼠标按钮时,发出此信号
collapsed(QModelIndex) 当索引指定的项目折叠时,发出信号。
currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)当前项目更改时,发出信号
doubleClicked(QModelIndex) 双击鼠标按钮时,发出此信号
entered(QModelIndex) 当鼠标光标进入index指定的项目时,发出此信号
expanded(QModeldelIndex) 当索引指定的项目展开时,发出信号
iconSizeChanged(QSize) 在视图可见时设置此图标大小时,发出此信号
itemActivated(QTreeWidgetItem*,int) 当用户通过单击,双击或按特殊键(例如,Enter)激活项目时,发出信号
itemChanged(QTreeWidgetItem*,int) 当指定项目中列的内容发生更改时,发出信号
itemClicked(QTreeWidgetItem*,int) 当用户在窗口内单击时,发出信号。
itemCollapsed(QTreeWidgetItem*) 折叠指定项目时,发出信号
itemDoubleClicked(QTreeWidgetItem*,int) 当用户在窗口内双击时,发出信号
itemEntered(QTreeWidgetItem*,int) 当鼠标光标进入指定列上的项目时,发出信号
itemExpanded(QTreeWidgetItem*) 扩展指定项目时,发出信号
itemPressed(QTreeWidgetItem*,int) 当用户在窗口内按下鼠标按钮时,发出信号。
itemSelectionChange() 当树构件中的选择发生变化时,发出信号
pressed(QModelIndex) 按下鼠标按钮时,发出信号
viewportEntered() 当鼠标光标进入控件时,发出信号
View Code

获取父项某一个column的内容和

    def getLocation(self,item):

        if item.parent():
            temp = item.parent().text(0)
            parent=self.getLocation(item.parent())
            if parent :
                res=os.path.join(parent,temp)

                return res
            else:
                return temp
        else:
            return 0
#举例,text(0)是文件夹的名称,那么递归后就可以获取全部路径
View Code

右键菜单

     def __init__(self):
        self.setContextMenuPolicy(Qt.CustomContextMenu)#打开右键菜单的策略
        self.customContextMenuRequested.connect(self.rightClickMenu)#绑定事件

    def rightClickMenu(self,pos):
        try:
            self.contextMenu = QMenu()#创建对象
            self.actionA = self.contextMenu.addAction(u'动作')#添加动作
            self.actionA = self.contextMenu.addAction(u'动作b')
            self.actionA.triggered.connect(self.actionHandler)
            self.contextMenu.exec_(self.mapToGlobal(pos))#随指针的位置显示菜单
            self.contextMenu.show()#显示
        except Exception as e:
            print(e)
    def actionHandler(self):
        print(self.currentItem().text(0))
View Code

删除子节点下的所有item

                item=self.currentItem()
                for i in range(0,item.childCount()):
                    print(item.child(item.childCount()-1).text(0))
                    item.removeChild(item.child(item.childCount()-1))
                
View Code

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!