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

from server import db

class User(db.Model):

  pass

在server.py中,

1

2

3

4

5

6

from flask import Flask

from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db'

db = SQLAlchemy(app)

from models import User

这样就产生了循环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【一】相关推荐

  1. 开源代码学习之persepolis【二】

    一.下载界面 1.主界面下载显示 MainWindow首先对aria进行初始化,启动aria2.启动方法在download.py中. # start aria2         start_aria ...

  2. github 开源 代码 学习 集合(转载)

    一个支持多种item类型的recycleView依赖注入库 1.通过注解的方式方便的把ViewHolder注入到recycleView中. 2.去除findViewByID等冗余操作. 3.去除编写a ...

  3. CV Code | 本周新出计算机视觉开源代码汇总(含目标跟踪、语义分割、姿态跟踪、少样本学习等)...

    点击我爱计算机视觉标星,更快获取CVML新技术 刚刚过去的一周出现了很多很实用.有意思.很神奇的CV代码. 比如大家期待的SiamRPN++算法,官方终于要开源了. 阿里MNN成为移动端网络部署的新选 ...

  4. CV Code | 本周新出计算机视觉开源代码汇总(含图像修复、目标检测、医学图像分割、度量学习等)...

    点击我爱计算机视觉标星,更快获取CVML新技术 CV君汇总了过去一周计算机视觉领域新出的开源代码,涉及到图像质量评价.图像去雾.图像修复.医学图像分割.目标检测.人脸对齐.度量学习等,其中有多篇来自C ...

  5. 国际表征学习会议ICLR 2020共计198篇开源代码论文目录

    国际学习表征会议 ICLR 2020 (International Conference on Learning Representation) 将于明年4月26日于埃塞俄比亚首都的斯亚贝巴举行.此次 ...

  6. 如何有效的学习开源代码

    导读:对于开发者来说,社区里丰富的开源代码其实是笔极为宝贵的财富.如果能充分利用好开放源代码的资源,不仅可以掌握多种编程方法,提高实践能力,还能获得好的思想,激发编程灵感.开源代码怎么学以及怎样才能学 ...

  7. 系统入门到实战学习某项技术、有问题找“百度“、学习优秀的技术博客、找开源代码等资料

    一.系统入门到实战学习某项技术 先看视频入门到实战(B站.慕课网) 然后看书,再把知识的体系串起来 二.有问题找"百度" 1.学习各种疑惑,问搜索引擎[最大的学习资料库] ■ 搜索 ...

  8. AI实战:基于深度学习的空气质量预测模型开源代码汇总

    基于深度学习的空气质量预测模型开源代码汇总 一.传统机理空气质量模型 空气质量模型是基于人类对大气物理和化学过程科学认识的基础上,运用气象学原理及数学方法,从水平和垂直方向在大尺度范围内对空气质量进行 ...

  9. Shimeji开源桌宠代码学习(2)

    在 Shimeji开源桌宠代码学习(1)中描述了整个配置文件加载的过程,其中很多地方使用了Builder这一概念,首先我们先来看看这些Builder都有什么特征,我认为我们从AnimationBuil ...

最新文章

  1. 搜索引擎ElasticSearchV5.4.2系列二之ElasticSearchV5.4.2+kibanaV5.4.2+x-packV5.4.2安装
  2. 机器学习之深入理解SVM
  3. 建高性能ASP.NET站点 第五章—性能调优综述(中篇)
  4. 梯度下降原理及在线性回归、逻辑回归中的应用
  5. 非阻塞IO与异步IO
  6. AV Linux 2016系统今年发布:影音制作专用
  7. hive中文字符乱码 解决方法【转】
  8. k8s挂载目录_拥抱云原生,如何将开源项目用k8s部署?
  9. WLC HA (for AP)?
  10. Atitit.url 汉字中文路径  404 resin4 resin  解决  v2 q329
  11. Linux下正则表达式匹配性能
  12. VMware Error | IP地址经常变更
  13. 共识,权威以及去中心化的区块链
  14. 没有装php可以用phpmyadmin,phpMyAdmin 安装及问题总结
  15. 外贸企业邮箱可以撤回邮件吗?如何撤回已发送的邮件?
  16. TIME_WAIT状态(2MSL)的作用
  17. 如何设置条码标签的打印数量
  18. maven 零散配置
  19. SAP S4 FI后台详细配置教程- PART1 (通用配置及基础架构篇)
  20. 微信小程序中获取用户微信公众号授权(openid)用来发送模板消息

热门文章

  1. 恢复rm -rf 的数据
  2. linux误删 bin目录,记linux下rm误删bin文件的解决方式
  3. 还在说大学排名是笑话?最新规定:世界top50大学可以直接落户上海!
  4. 校园二手平台使用说明
  5. 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV
  6. 1微秒等于多少皮秒_皮秒(ps)是一个时间单位。它是这样换算的↓1秒s_圈子-新氧美容整形...
  7. php微信生成微信公众号二维码扫描进入公众号带参数
  8. Habor镜像仓库的搭建
  9. 会议OA之我的会议(排座送审)
  10. C++ 类(静态成员和静态函数)