开源代码学习之persepolis【一】
https://github.com/persepolisdm/persepolis
https://github.com/aria2/aria2
Persepolis是一款以aria2为基础打造的下载管理GUI,他是用python和pyqt5写的开源免费跨平台软件,支持GNU/Linux , BSDs, MacOS, 和Microsoft Windows。简单说Persepolis就是给aria2加了个界面,这里主要学习python和pyqt5的用法。
一、启动软件
\persepolis-master\test\test.py
os_type = platform.system() #获取操作系统类型
cwd = os.path.abspath(__file__) #程序绝对路径D:\Users\persepolis-master\test\test.py
run_dir = os.path.dirname(cwd) #程序文件目录D:\Users\persepolis-master\test
parent_dir = os.path.dirname(run_dir) #程序文件父目录D:\Users\persepolis-master,os.path.dirname可以一层一层往上找目录
sys.path.insert(0, parent_dir) #import上一级目录的模块
含义来自https://www.jb51.net/article/85867.htm
python import module会去sys.path搜索,sys.path是个列表,并且我们可以动态修改。 要import某个目录的module,我们sys.path.insert(0,somedir)来加入搜索路径,就可以import了。 既然这样,要import上一级目录的module,可以sys.path.insert(0,parentdir)。 不过这种写绝对路径的方式,如果文件放到其它地方,就不行了。 所以用动态方法来获取上一级目录。为什么用sys.path.insert(0,parentdir) 而不是用sys.path.append(parentdir)呢
因为是遍历搜索路径的,所以如果在其它路径里也有个同名的module,会import错。用sys.path.insert(0,parentdir)可以确保先搜索这个路径。
解决循环import的问题
在python中常常会遇到循环import即circular import的问题。
现实中经常出现这种滑稽的情况,安装无线网卡的时候,需要上网下载网卡驱动..安装压缩软件的时候,从网上下载的压缩软件安装程序居然是被压缩了的..循环依赖就类似于这种情况。
举个例子,
在models.py中,
1 2 3 |
|
在server.py中,
1 2 3 4 5 6 |
|
这样就产生了循环import的问题,models需要from
server
import
db,而
server又需要from
models
import
User。
解决循环import的方法主要有几种。
1.延迟导入(lazy import)
即把import语句写在方法或函数里面,将它的作用域限制在局部。
这种方法的缺点就是会有性能问题。
2.将from xxx import yyy改成import xxx;xxx.yyy来访问的形式
3.组织代码
出现循环import的问题往往意味着代码的布局有问题。
可以合并或者分离竞争资源。
合并的话就是都写到一个文件里面去。
分离的话就是把需要import的资源提取到一个第三方文件去。
总之就是将循环变成单向。
二、初始化
\persepolis-master\persepolis\scripts\persepolis.py
1、配置文件路径
elif os_type == OS.WINDOWS:config_folder = os.path.join(home_address, 'AppData', 'Local', 'persepolis_download_manager')
2、单实例运行
开发中常用的只允许一个实例运行的办法,创建一个互斥量。由于互斥量只允许一个进程或者线程占用,否则会创建失败,利用这个特性可以做到单例运行。
CreateMutex找出当前系统是否已经存在指定进程的实例。如果没有则创建一个互斥体。CreateMutex()函数可用来创建一个有名或无名的互斥量对象。
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针
BOOL bInitialOwner, // 初始化互斥对象的所有者
LPCTSTR lpName // 指向互斥对象名的指针 );
返回值
Long,如执行成功,就返回互斥体对象的句柄;零表示出错。会设置GetLastError。
即使返回的是一个有效句柄,但倘若指定的名字已经存在,GetLastError也会设为ERROR_ALREADY_EXISTS
lpMutexAttributes SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递零值(将参数声明为ByVal As Long,并传递零值),表示使用不允许继承的默认描述符。
bInitialOwner BOOL,如创建进程希望立即拥有互斥体,则设为TRUE。一个互斥体同时只能由一个线程拥有。是FALSE,表示刚刚创建的这个Mutex不属于任何线程也就是没有任何线程拥有他。
lpName String,指定互斥体对象的名字。如已经存在拥有这个名字的一个互斥体,则打开现有的已命名互斥体。这个名字可能不与现有的事件、信号机、可等待计时器或文件映射相符,否则执行失败GetLastError函数返回 ERROR_INVALID_HANDLE。该名称可以有一个"Global\" 或"Local\" 前缀,明确地建立在全局或会话命名空间的对象。剩余的名称可以包含任何字符,除反斜杠字符(\)。
互斥量:
采用互斥对象机制。互斥锁,像一个物件,这个物件只能同时被一个线程持有。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
一、创建 创建互斥锁的方法是调用函数CreateMutex: CreateMutex(&sa, bInitialOwner, szName);第一个参数是一个指向SECURITY_ATTRIBUTES结构体的指针,一般的情况下,可以是nullptr。 第二个参数类型为BOOL,表示互斥锁创建出来后是否被当前线程持有。 第三个参数类型为字符串(const TCHAR*),是这个互斥锁的名字,如果是nullptr,则互斥锁是匿名的。 例: HANDLE hMutex = CreateMutex(nullptr, FALSE, nullptr);上面的代码创建了一个匿名的互斥锁,创建出来后,当前线程不持有这个互斥锁。
二、持有 WaitForSingleObject函数可以让一个线程持有互斥锁。用法: WaitForSingleObject(hMutex, dwTimeout);这个函数的作用比较多。这里只介绍第一个参数为互斥锁句柄时的作用。 它的作用是等待,直到一定时间之后,或者,其他线程均不持有hMutex。第二个参数是等待的时间(单位:毫秒),如果该参数为INFINITE,则该函数会一直等待下去。
三、释放 用ReleaseMutex函数可以让当前线程“放开”一个互斥锁(不持有它了),以便让其他线程可以持有它。用法 ReleaseMutex(hMutex)
四、销毁 当程序不再需要互斥锁时,要销毁它。 CloseHandle(hMutex)
五、命名互斥锁 如果CreateMutex函数的第三个参数传入一个字符串,那么所创建的锁就是命名的。当一个命名的锁被创建出来以后,当前进程和其他进程如果试图创建相同名字的锁,CreateMutex会返回原来那把锁的句柄,并且GetLastError函数会返回ERROR_ALREADY_EXISTS。这个特点可以使一个程序在同一时刻最多运行一个实例。
原文链接:https://blog.csdn.net/enterlly/article/details/79158920
from win32event import CreateMutexfrom win32api import GetLastErrorfrom winerror import ERROR_ALREADY_EXISTSfrom sys import exithandle = CreateMutex(None, 1, 'persepolis_download_manager')if GetLastError() == ERROR_ALREADY_EXISTS:lock_file_validation = Falseprint("already exit")else:lock_file_validation = Trueprint('start app')
3、QSettings初始化
用户对应用程序经常有这样的要求:要求它能记住它的settings,比如窗口大小,位置,一些别的设置,还有一个经常用的,就是recent files,等等这些都可以通过Qsettings来实现。
我们知道,这些settings一般都是存在系统里的,比如windows一般都写在系统注册表或者写INI文件,mac系统一般都在XML文件里,那么按照一般的标准来说,许多应用程序是用INI文件来实现的。而Qsettings就是提供了一种方便的方法来存储和恢复应用程序的settings。
QSettings的API是基于Qvariant,Qvariant是一种数据类型的集合,它包含了大部分通常的Qt数据类型,比如QString,QRec,QImage,等等。
当我们创建一个Qsettings的对象时,我们需要传递给它两个参数,第一个是公司或者组织的名称,第二个是应用程序的名称。如果为ini文件,还需要指定文件名称和格式。
# load persepolis_settings
persepolis_setting = QSettings('persepolis_download_manager', 'persepolis')
然后在应用程序的任何地方想要声明一个Qsettings类型的变量,便不需要书写两个参数了,直接用 settings = Qsettings()即可。
persepolis_download_manager.setting = QSettings()
那么如何用它来保持应用程序的settings信息呢?以AboutWindow初始化为例:
size = self.persepolis_setting.value('AboutWindow/size', QSize(545, 375))
意思是,如果settings里有以前存下的AboutWindow/size值则读取,如果没有则会使用默认值QSize(545, 375)。
AboutWindow关闭时,将self.size()和self.pos()分别保存在'AboutWindow/size'和'AboutWindow/position'中。
def __init__(self, persepolis_setting):super().__init__(persepolis_setting)self.persepolis_setting = persepolis_setting# setting window size and positionsize = self.persepolis_setting.value('AboutWindow/size', QSize(545, 375))position = self.persepolis_setting.value('AboutWindow/position', QPoint(300, 300))def closeEvent(self, event):# saving window size and positionself.persepolis_setting.setValue('AboutWindow/size', self.size())self.persepolis_setting.setValue('AboutWindow/position', self.pos())self.persepolis_setting.sync()event.accept()
Qsettings里常用的方法:
Qsettings.allKeys(self) 返回所有的key,以list的形式
Qsettings.applicationName(self) 返回应用程序名称
Qsettings.clear(self) 清除此settings里的内容
Bool Qsettings.contains(self,key) 如果存在名为key则返回真
Qsettings.remove(self, keyname) 清除key及其所对应的value
Qsetting.fileName() 返回写入注册表地址,或者INI文件路径
下面的文档介绍了最近文件列表的更新方法:
https://cloud.tencent.com/developer/article/1487068
三、界面初始化
PersepolisApplication继承自QApplication,只定义了几个窗口改变的方法。
MainWindow继承自MainWindow_Ui,是界面显示的主窗口,定义了界面上各种操作。
mainwindow = MainWindow(start_in_tray, persepolis_download_manager, persepolis_download_manager.setting)
第一个参数表示是否在托盘中显示,如果为真则初始状态为隐藏。
第二个参数persepolis_download_manager是一个PersepolisApplication,传递到主窗口后未只进行了保存,未找到哪里有使用
self.persepolis_main = persepolis_main
第三个参数persepolis_download_manager.setting = QSettings()为系统设置
class PersepolisApplication(QApplication):def __init__(self, argv):super().__init__(argv)def setPersepolisStyle(self, style):# set styledef setPersepolisFont(self, font, font_size, custom_font):# font and font_size# color_schemedef setPersepolisColorScheme(self, color_scheme):self.persepolis_color_scheme = color_schemeif color_scheme == 'Dark Fusion':dark_fusion = DarkFusionPalette()self.setPalette(dark_fusion)file = QFile(":/dark_style.qss")file.open(QFile.ReadOnly | QFile.Text)stream = QTextStream(file)self.setStyleSheet(stream.readAll())...# create QApplication
persepolis_download_manager = PersepolisApplication(sys.argv)persepolis_download_manager.setting = QSettings()mainwindow = MainWindow(start_in_tray, persepolis_download_manager, persepolis_download_manager.setting)class MainWindow(MainWindow_Ui):def __init__(self, start_in_tray, persepolis_main, persepolis_setting):super().__init__(persepolis_setting)self.persepolis_setting = persepolis_settingself.persepolis_main = persepolis_mainclass MainWindow_Ui(QMainWindow):def __init__(self, persepolis_setting):super().__init__()# MainWindowself.persepolis_setting = persepolis_setting
开源代码学习之persepolis【一】相关推荐
- 开源代码学习之persepolis【二】
一.下载界面 1.主界面下载显示 MainWindow首先对aria进行初始化,启动aria2.启动方法在download.py中. # start aria2 start_aria ...
- github 开源 代码 学习 集合(转载)
一个支持多种item类型的recycleView依赖注入库 1.通过注解的方式方便的把ViewHolder注入到recycleView中. 2.去除findViewByID等冗余操作. 3.去除编写a ...
- CV Code | 本周新出计算机视觉开源代码汇总(含目标跟踪、语义分割、姿态跟踪、少样本学习等)...
点击我爱计算机视觉标星,更快获取CVML新技术 刚刚过去的一周出现了很多很实用.有意思.很神奇的CV代码. 比如大家期待的SiamRPN++算法,官方终于要开源了. 阿里MNN成为移动端网络部署的新选 ...
- CV Code | 本周新出计算机视觉开源代码汇总(含图像修复、目标检测、医学图像分割、度量学习等)...
点击我爱计算机视觉标星,更快获取CVML新技术 CV君汇总了过去一周计算机视觉领域新出的开源代码,涉及到图像质量评价.图像去雾.图像修复.医学图像分割.目标检测.人脸对齐.度量学习等,其中有多篇来自C ...
- 国际表征学习会议ICLR 2020共计198篇开源代码论文目录
国际学习表征会议 ICLR 2020 (International Conference on Learning Representation) 将于明年4月26日于埃塞俄比亚首都的斯亚贝巴举行.此次 ...
- 如何有效的学习开源代码
导读:对于开发者来说,社区里丰富的开源代码其实是笔极为宝贵的财富.如果能充分利用好开放源代码的资源,不仅可以掌握多种编程方法,提高实践能力,还能获得好的思想,激发编程灵感.开源代码怎么学以及怎样才能学 ...
- 系统入门到实战学习某项技术、有问题找“百度“、学习优秀的技术博客、找开源代码等资料
一.系统入门到实战学习某项技术 先看视频入门到实战(B站.慕课网) 然后看书,再把知识的体系串起来 二.有问题找"百度" 1.学习各种疑惑,问搜索引擎[最大的学习资料库] ■ 搜索 ...
- AI实战:基于深度学习的空气质量预测模型开源代码汇总
基于深度学习的空气质量预测模型开源代码汇总 一.传统机理空气质量模型 空气质量模型是基于人类对大气物理和化学过程科学认识的基础上,运用气象学原理及数学方法,从水平和垂直方向在大尺度范围内对空气质量进行 ...
- Shimeji开源桌宠代码学习(2)
在 Shimeji开源桌宠代码学习(1)中描述了整个配置文件加载的过程,其中很多地方使用了Builder这一概念,首先我们先来看看这些Builder都有什么特征,我认为我们从AnimationBuil ...
最新文章
- 搜索引擎ElasticSearchV5.4.2系列二之ElasticSearchV5.4.2+kibanaV5.4.2+x-packV5.4.2安装
- 机器学习之深入理解SVM
- 建高性能ASP.NET站点 第五章—性能调优综述(中篇)
- 梯度下降原理及在线性回归、逻辑回归中的应用
- 非阻塞IO与异步IO
- AV Linux 2016系统今年发布:影音制作专用
- hive中文字符乱码 解决方法【转】
- k8s挂载目录_拥抱云原生,如何将开源项目用k8s部署?
- WLC HA (for AP)?
- Atitit.url 汉字中文路径 404 resin4 resin 解决 v2 q329
- Linux下正则表达式匹配性能
- VMware Error | IP地址经常变更
- 共识,权威以及去中心化的区块链
- 没有装php可以用phpmyadmin,phpMyAdmin 安装及问题总结
- 外贸企业邮箱可以撤回邮件吗?如何撤回已发送的邮件?
- TIME_WAIT状态(2MSL)的作用
- 如何设置条码标签的打印数量
- maven 零散配置
- SAP S4 FI后台详细配置教程- PART1 (通用配置及基础架构篇)
- 微信小程序中获取用户微信公众号授权(openid)用来发送模板消息
热门文章
- 恢复rm -rf 的数据
- linux误删 bin目录,记linux下rm误删bin文件的解决方式
- 还在说大学排名是笑话?最新规定:世界top50大学可以直接落户上海!
- 校园二手平台使用说明
- 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV
- 1微秒等于多少皮秒_皮秒(ps)是一个时间单位。它是这样换算的↓1秒s_圈子-新氧美容整形...
- php微信生成微信公众号二维码扫描进入公众号带参数
- Habor镜像仓库的搭建
- 会议OA之我的会议(排座送审)
- C++ 类(静态成员和静态函数)