基本功能实现!还有挺多BUG

This commit is contained in:
liyp 2022-03-25 17:35:45 +08:00
parent e4fbb93f94
commit d88249e4cf
18 changed files with 859 additions and 74 deletions

BIN
images/SwiftUI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
images/g.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

1
images/icon.svg Normal file
View file

@ -0,0 +1 @@
<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100"><g><path d="M78.846,43.805c0.226-11.807-9.155-22.283-20.687-22.283c-7.107,0-13.433,3.484-17.563,8.91 c-4.529-5.971-22.354-1.723-19.441,13.373C12.919,45.133,5,51.297,5,60.367c0,10.002,7.676,18.111,17.145,18.111H44V60.502H32 l18-18.01l18,18.01H56v17.977h21.855C87.324,78.479,95,70.369,95,60.367C95,51.32,87.418,43.717,78.846,43.805z"></path></g></svg>

After

Width:  |  Height:  |  Size: 511 B

BIN
images/lol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/pic_list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
images/setting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
images/setting_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

361
images/todo.svg Normal file
View file

@ -0,0 +1,361 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="120"
height="120"
viewBox="0 0 120 120"
version="1.1"
id="svg5"
sodipodi:docname="新建文档 1.2022_01_22_12_01_40.0.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="4.531376"
inkscape:cx="68.30155"
inkscape:cy="50.426184"
inkscape:window-width="1920"
inkscape:window-height="1015"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid9" />
</sodipodi:namedview>
<defs
id="defs2">
<inkscape:path-effect
effect="bspline"
id="path-effect2507"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect952"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect948"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect831"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect827"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect823"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect819"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect815"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect811"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect557"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect553"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect286"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect165"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect46"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
</defs>
<g
inkscape:label="图层 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#49cf5a;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
d="M 15,0 C 11.667167,0 5.0005002,0 1.6666668,3.3339 c -3.3338333,3.3339 -3.3338333,10.000433 -3.3338333,26.667366 0,16.666934 0,43.333067 0,59.999801 0,16.666733 0,23.333263 3.3339,26.666093 C 5.0006335,120 11.667167,120 28.3341,120 c 16.666933,0 43.333067,0 59.999799,0 16.666731,0 23.333261,0 26.666101,-3.3329 3.33283,-3.3329 3.33283,-9.99943 3.33283,-27.499715 0,-17.500285 0,-45.833052 0,-62.499768 0,-16.666717 0,-21.666617 -3.3329,-24.167117 C 111.66703,0 105.0005,0 88.333566,0 71.666633,0 45.0005,0 18.332833,0 c 0,0 0,0 -3.332833,0 z"
id="path44"
inkscape:path-effect="#path-effect46"
inkscape:original-d="M 18.332833,0 C 11.667167,0.001 5.0005002,0.001 -1.6671665,0 c 10e-4,6.6678 10e-4,13.334333 0,20 10e-4,26.6682 10e-4,53.334333 0,80 10e-4,6.6678 10e-4,13.33433 0,20 6.6678,0.001 13.3343335,0.001 19.9999995,0 26.6682,0.001 53.334334,0.001 80,0 6.667797,0.001 13.334327,0.001 19.999997,0 0.001,-6.6658 0.001,-13.33233 0,-20 0.001,-28.3329 0.001,-56.665667 0,-85 0.001,-4.9991 0.001,-9.999 0,-15 -6.6658,0.001 -13.33233,0.001 -19.999997,0 -26.6662,0.001 -53.332333,0.001 -80,0 0,0 10e-4,0.001 0,0 z" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -55,55 c -1.665667,-1.665667 -3.332333,-3.332333 -4.999516,-3.332817 -1.667184,-4.83e-4 -3.333817,1.66615 -3.3333,3.333333 C -63.3323,56.6677 -61.665667,58.334333 -60,60"
id="path555"
inkscape:path-effect="#path-effect557"
inkscape:original-d="m -55,55 c -1.665667,-1.665667 -3.332333,-3.332333 -5,-5 -1.6657,1.6677 -3.332333,3.334333 -5,5 1.6677,1.6677 3.334333,3.334333 5,5" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -60,60 c 3.334333,3.334333 6.667667,6.667667 10,10"
id="path809"
inkscape:path-effect="#path-effect811"
inkscape:original-d="m -60,60 c 3.334333,3.334333 6.667667,6.667667 10,10" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -55,55 c 3.334333,3.334333 6.667667,6.667667 10,10"
id="path813"
inkscape:path-effect="#path-effect815"
inkscape:original-d="m -55,55 c 3.334333,3.334333 6.667667,6.667667 10,10" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -50,70 c 1.667667,1.667667 3.334333,3.334333 5.000517,3.333817 C -43.3333,73.3333 -41.666667,71.666667 -40,70"
id="path817"
inkscape:path-effect="#path-effect819"
inkscape:original-d="m -50,70 c 1.667667,1.667667 3.334333,3.334333 5,5 1.6677,-1.6657 3.334333,-3.332333 5,-5" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -40,70 c 5,-5 10,-10 15,-15"
id="path821"
inkscape:path-effect="#path-effect823"
inkscape:original-d="m -40,70 c 5.001,-4.999 10.001,-9.999 15,-15" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -45,65 c 5,-5 10,-10 15,-15"
id="path825"
inkscape:path-effect="#path-effect827"
inkscape:original-d="m -45,65 c 5.001,-4.999 10.001,-9.999 15,-15" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -25,55 c 1.666667,-1.666667 3.333333,-3.333333 3.333816,-4.999516 4.84e-4,-1.666184 -1.666149,-3.332817 -3.333332,-3.333301 C -26.6667,46.6667 -28.333333,48.333333 -30,50"
id="path829"
inkscape:path-effect="#path-effect831"
inkscape:original-d="m -25,55 c 1.667667,-1.665667 3.334333,-3.332333 5,-5 -1.6657,-1.6657 -3.332333,-3.332333 -5,-5 -1.6657,1.6677 -3.332333,3.334333 -5,5" />
<path
style="fill:#000000;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 60,50 C 50,60 40.0002,69.9998 34.166767,75.833233 28.333333,81.666667 26.6667,83.3333 25.000517,83.333817 23.334333,83.334333 21.6677,81.6677 19.167683,79.167683 16.667667,76.667667 13.3344,73.3344 10.834367,70.834367 8.334333,68.334333 6.6677,66.6677 6.6671835,65.000517 6.666667,63.333333 8.3333,61.6667 10.000484,61.667184 c 1.667183,4.83e-4 3.333849,1.667149 5.833883,4.167183 C 18.3344,68.3344 21.667667,71.667667 25,75"
id="path946"
inkscape:path-effect="#path-effect948"
inkscape:original-d="M 60,50 C 50.001,60.001 40.0012,70.0008 30,80 28.334333,81.667667 26.6677,83.3343 25,85 23.334333,83.334333 21.6677,81.6677 20,80 16.667667,76.667667 13.3344,73.3344 10,70 8.334333,68.334333 6.6677,66.6677 5,65 c 1.667667,-1.665667 3.3343,-3.3323 5,-5 1.667667,1.667667 3.334333,3.334333 5,5 3.3344,3.3344 6.667667,6.667667 10,10" />
<path
style="fill:#000000;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 25,75 C 35,65 45,55 50.83335,49.16665 c 5.83335,-5.83335 7.499983,-7.499983 9.167167,-7.499467 1.667183,5.17e-4 3.333816,1.66715 3.333299,3.333334 C 63.3333,46.6667 61.666667,48.333333 60,50"
id="path950"
inkscape:path-effect="#path-effect952"
inkscape:original-d="m 25,75 c 10.001,-9.999 20.001,-19.999 30,-30 1.6677,-1.6657 3.334333,-3.332333 5,-5 1.6677,1.6677 3.334333,3.334333 5,5 -1.6657,1.6677 -3.332333,3.334333 -5,5" />
<path
style="fill:#ff0000;fill-opacity:0.950941"
id="path2558"
sodipodi:type="arc"
sodipodi:cx="60"
sodipodi:cy="30"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 65,30 a 5,5 0 0 1 -4.959312,4.999834 5,5 0 0 1 -5.040026,-4.918462 5,5 0 0 1 4.877286,-5.079882 5,5 0 0 1 5.119403,4.835787 L 60,30 Z" />
<rect
style="fill:#ff0000;fill-opacity:0.950941"
id="rect2693"
width="40"
height="10"
x="60"
y="25" />
<path
style="fill:#ff0000;fill-opacity:0.950941"
id="path2717"
sodipodi:type="arc"
sodipodi:cx="105"
sodipodi:cy="30"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 110,30 a 5,5 0 0 1 -4.95931,4.999834 5,5 0 0 1 -5.04003,-4.918462 5,5 0 0 1 4.87729,-5.079882 5,5 0 0 1 5.1194,4.835787 L 105,30 Z" />
<rect
style="fill:#ff0000;fill-opacity:0.950941"
id="rect2821"
width="5"
height="10"
x="100"
y="25" />
<path
style="fill:#ffff00;fill-opacity:0.950941"
id="path2925"
sodipodi:type="arc"
sodipodi:cx="65"
sodipodi:cy="60"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 70,60 a 5,5 0 0 1 -4.959312,4.999834 5,5 0 0 1 -5.040026,-4.918462 5,5 0 0 1 4.877286,-5.079882 5,5 0 0 1 5.119403,4.835787 L 65,60 Z" />
<rect
style="fill:#ffff00;fill-opacity:0.950941"
id="rect2949"
width="40"
height="10"
x="65"
y="55" />
<path
style="fill:#ffff00;fill-opacity:0.950941"
id="path2973"
sodipodi:type="arc"
sodipodi:cx="105"
sodipodi:cy="60"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 110,60 a 5,5 0 0 1 -4.95931,4.999834 5,5 0 0 1 -5.04003,-4.918462 5,5 0 0 1 4.87729,-5.079882 5,5 0 0 1 5.1194,4.835787 L 105,60 Z" />
<path
style="fill:#00ffff;fill-opacity:0.950941"
id="path2975"
sodipodi:type="arc"
sodipodi:cx="60"
sodipodi:cy="85"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 65,85 a 5,5 0 0 1 -4.959312,4.999834 5,5 0 0 1 -5.040026,-4.918462 5,5 0 0 1 4.877286,-5.079882 5,5 0 0 1 5.119403,4.835787 L 60,85 Z" />
<rect
style="fill:#00ffff;fill-opacity:0.950941"
id="rect2999"
width="45"
height="10"
x="60"
y="80" />
<path
style="fill:#00ffff;fill-opacity:0.950941"
id="path3023"
sodipodi:type="arc"
sodipodi:cx="105.00265"
sodipodi:cy="85.16272"
sodipodi:rx="5"
sodipodi:ry="5"
sodipodi:start="0"
sodipodi:end="6.2506349"
sodipodi:arc-type="slice"
d="m 110.00265,85.16272 a 5,5 0 0 1 -4.95932,4.999834 5,5 0 0 1 -5.04002,-4.918462 5,5 0 0 1 4.87729,-5.079882 5,5 0 0 1 5.1194,4.835787 l -4.99735,0.162723 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

BIN
images/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
images/upload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

64
resource/current.qss Normal file
View file

@ -0,0 +1,64 @@
/*去掉item虚线边框*/
QListWidget, QListView, QTreeWidget, QTreeView {
outline: 0px;
}
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
QListWidget {
min-width: 120px;
max-width: 120px;
color: white;
background: black;
}
QPushButton {
max-width: 120px;
color: white;
border-top-left-radius:10px;
border-top-right-radius:10px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
background: pink;
}
QPushButton:pressed,
QPushButton:pressed:focus {
/* 改变背景色 */
background-color: #f50057;
/* 改变边框风格 */
border-style:inset;
/* 改变边框风格 */
border-style:inset;
}
QPushButton#upload_btn {
padding: 3px 20px;
text-align:center;
}
/*被选中时的背景颜色和左边框颜色*/
QListWidget::item:selected {
background: rgb(52, 52, 52);
border-right: 4px solid rgb(9, 187, 7);
}
/*鼠标悬停颜色*/
HistoryPanel::item:hover {
background: rgb(52, 52, 52);
}
/*右侧的层叠窗口的背景颜色*/
QStackedWidget {
background: rgb(30, 30, 30);
}
/*模拟的页面*/
QLabel {
color: white;
}
QLineEdit {
border: 2px solid rgb(52,52,52);
border-top-left-radius:10px;
border-top-right-radius:10px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
}

129
start.py
View file

@ -1,91 +1,72 @@
import os
import sys import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt, QSize
from PyQt5 import QtCore from tool.UploadTip import UploadTip
from PyQt5.QtGui import QFont, QIcon from tool.ConfigWidget import ConfigView
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QDialog, QLabel, QLineEdit, QGridLayout, QApplication from tool import QSSLoader
from PyQt5.QtCore import Qt
from qt_material import apply_stylesheet
class MainWindow(QWidget):
class MainWin(QWidget):
def __init__(self): def __init__(self):
super(MainWin, self).__init__() super(MainWindow, self).__init__()
self.setWindowTitle('上传至阿里云cos') layout = QHBoxLayout(self, spacing=0)
self.resize(400, 500) self.listWidget = QListWidget()
self.setWindowIcon(QIcon('./images/icon.png')) self.resize(800, 600)
layout = QVBoxLayout() layout.addWidget(self.listWidget)
self.config_btn = QPushButton('配置') # 右侧层叠窗口
# self.config_btn self.stackedWidget = QStackedWidget(self)
self.config_btn.setFixedSize(60, 40) layout.addWidget(self.stackedWidget)
layout.setContentsMargins(0, 0, 0, 0)
self.config_btn.clicked.connect(self.configAction)
layout.addStretch()
layout.addWidget(self.config_btn, 0, Qt.AlignCenter)
layout.addStretch()
# layout.addLayout(tip_widget)
layout.addStretch()
self.setLayout(layout) self.setLayout(layout)
self.iniUI()
def configAction(self): def iniUI(self):
dialog = QDialog() # 初始化界面
dialog.setMinimumWidth(500) # 通过QListWidget的当前item变化来切换QStackedWidget中的序号
dialog.setWindowTitle("配置oss信息") self.listWidget.currentRowChanged.connect(
access_key_id_label = QLabel('access_key_id:') self.stackedWidget.setCurrentIndex)
access_key_id_text = QLineEdit() # 去掉边框
access_key_secret_label = QLabel('access_key_secret:') # self.listWidget.setFrameShape(QListWidget.NoFrame)
access_key_secret_text = QLineEdit() # # 隐藏滚动条
access_key_secret_text.setEchoMode(QLineEdit.Password) self.listWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
bucket_name_label = QLabel('bucket_name') self.listWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
bucket_name_text = QLineEdit()
bucket_name_text.setPlaceholderText('设置存储空间名')
endpoint_label = QLabel('endpoint')
endpoint_text = QLineEdit()
endpoint_text.setPlaceholderText('地域节点(如oss-cn-beijing.aliyuncs.com)')
upload_path_label = QLabel('upload_path')
upload_path_text = QLineEdit()
upload_path_text.setPlaceholderText('上传路径(如images/)')
upload_domain_label = QLabel('upload_domain')
upload_domain_text = QLineEdit()
upload_domain_text.setPlaceholderText('绑定域名(需要带https://)')
dialog_layout = QGridLayout()
font = QFont()
font.setFamily("Arial")
font.setPointSize(50)
dialog.setFont(font)
dialog_layout.addWidget(access_key_id_label, 0, 0)
dialog_layout.addWidget(access_key_id_text, 0, 1)
dialog_layout.addWidget(access_key_secret_label, 1, 0)
dialog_layout.addWidget(access_key_secret_text, 1, 1)
dialog_layout.addWidget(bucket_name_label, 2, 0)
dialog_layout.addWidget(bucket_name_text, 2, 1)
dialog_layout.addWidget(endpoint_label, 3, 0)
dialog_layout.addWidget(endpoint_text, 3, 1)
dialog_layout.addWidget(upload_path_label, 4, 0)
dialog_layout.addWidget(upload_path_text, 4, 1)
dialog_layout.addWidget(upload_domain_label, 5, 0)
dialog_layout.addWidget(upload_domain_text, 5, 1)
save_btn = QPushButton('保存配置')
content = [access_key_id_text.text(), access_key_secret_text.text(), bucket_name_text.text(),
endpoint_text.text(), upload_path_text.text(), upload_domain_text.text()]
save_btn.clicked.connect(lambda: self.save_oss_config(content)) # print(os.getcwd())
dialog_layout.addWidget(save_btn, 6, 1) self.upload_item = QListWidgetItem(
dialog.setLayout(dialog_layout) QIcon(QPixmap(os.getcwd()+'/images/upload.png')), '上传区', self.listWidget)
# 设置窗口的属性为ApplicationModal模态用户只有关闭弹窗后才能关闭主界面 self.set_item = QListWidgetItem(
dialog.setWindowModality(QtCore.Qt.ApplicationModal) QIcon(QPixmap(os.getcwd()+'/images/setting_icon.png')), '配置区域')
dialog.exec_() self.upload_item.setSizeHint(QSize(16777215, 60))
# 文字居中
self.upload_item.setTextAlignment(Qt.AlignCenter)
self.set_item.setSizeHint(QSize(16777215, 60))
# 文字居中
self.set_item.setTextAlignment(Qt.AlignCenter)
self.listWidget.addItem(self.upload_item)
self.listWidget.addItem(self.set_item)
upload_widget = UploadTip()
config_widget = ConfigView()
self.stackedWidget.addWidget(upload_widget)
self.stackedWidget.addWidget(config_widget)
def save_oss_config(self, content):
print(content)
for i in content:
print(i)
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication(sys.argv) app = QApplication(sys.argv)
main = MainWin() main = MainWindow()
apply_stylesheet(app, theme='dark_yellow.xml') style_file = 'resource/current.qss'
style_sheet = QSSLoader.QSSLoader.read_qss_file(style_file)
# apply_stylesheet(app, theme='light_blue.xml')
app.setWindowIcon(QIcon('./images/icon.svg')) app.setWindowIcon(QIcon('./images/icon.svg'))
main.setStyleSheet(style_sheet)
main.show() main.show()
sys.exit(app.exec_()) sys.exit(app.exec_())

64
test/ConfigView.py Normal file
View file

@ -0,0 +1,64 @@
import os
import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
from ListWidgetItem import ListWidgetItem
class ConfigView(QLabel):
def __init__(self):
super(ConfigView, self).__init__()
self.config_view=QLabel()
def configAction(self):
dialog = QDialog()
# dialog.resize(300,200)
dialog.setMaximumSize(500 ,400)
dialog.setWindowTitle("配置oss信息")
access_key_id_label = QLabel('access_key_id:')
access_key_id_text = QLineEdit()
access_key_secret_label = QLabel('access_key_secret:')
access_key_secret_text = QLineEdit()
access_key_secret_text.setEchoMode(QLineEdit.Password)
bucket_name_label = QLabel('bucket_name')
bucket_name_text = QLineEdit()
bucket_name_text.setPlaceholderText('设置存储空间名')
endpoint_label = QLabel('endpoint')
endpoint_text = QLineEdit()
endpoint_text.setPlaceholderText('地域节点(如oss-cn-beijing.aliyuncs.com)')
upload_path_label = QLabel('upload_path')
upload_path_text = QLineEdit()
upload_path_text.setPlaceholderText('上传路径(如images/)')
upload_domain_label = QLabel('upload_domain')
upload_domain_text = QLineEdit()
upload_domain_text.setPlaceholderText('绑定域名(需要带https://)')
dialog_layout = QGridLayout()
font = QFont()
font.setFamily("Arial")
font.setPointSize(50)
dialog.setFont(font)
dialog_layout.addWidget(access_key_id_label, 0, 0)
dialog_layout.addWidget(access_key_id_text, 0, 1)
dialog_layout.addWidget(access_key_secret_label, 1, 0)
dialog_layout.addWidget(access_key_secret_text, 1, 1)
dialog_layout.addWidget(bucket_name_label, 2, 0)
dialog_layout.addWidget(bucket_name_text, 2, 1)
dialog_layout.addWidget(endpoint_label, 3, 0)
dialog_layout.addWidget(endpoint_text, 3, 1)
dialog_layout.addWidget(upload_path_label, 4, 0)
dialog_layout.addWidget(upload_path_text, 4, 1)
dialog_layout.addWidget(upload_domain_label, 5, 0)
dialog_layout.addWidget(upload_domain_text, 5, 1)
save_btn = QPushButton('保存配置')
content = [access_key_id_text.text(), access_key_secret_text.text(), bucket_name_text.text(),
endpoint_text.text(), upload_path_text.text(), upload_domain_text.text()]
save_btn.clicked.connect(lambda: self.save_oss_config(content))
dialog_layout.addWidget(save_btn, 6, 1)
dialog.setLayout(dialog_layout)
# 设置窗口的属性为ApplicationModal模态用户只有关闭弹窗后才能关闭主界面
dialog.setWindowModality(QtCore.Qt.ApplicationModal)
dialog.exec_()

68
tool/ConfigWidget.py Normal file
View file

@ -0,0 +1,68 @@
from PyQt5.QtWidgets import *
from tool.FileConfig import *
class ConfigView(QWidget):
def __init__(self):
super(ConfigView, self).__init__()
layout = QGridLayout()
self.access_key_id_label = QLabel('access_key_id:')
self.access_key_id_text = QLineEdit()
self.access_key_secret_label = QLabel('access_key_secret:')
self.access_key_secret_text = QLineEdit()
self.access_key_secret_text.setEchoMode(QLineEdit.Password)
self.bucket_name_label = QLabel('bucket_name')
self.bucket_name_text = QLineEdit()
self.bucket_name_text.setPlaceholderText('设置存储空间名')
self.endpoint_label = QLabel('endpoint')
self.endpoint_text = QLineEdit()
self.endpoint_text.setPlaceholderText('地域节点(如oss-cn-beijing.aliyuncs.com)')
self.upload_path_label = QLabel('upload_path')
self.upload_path_text = QLineEdit()
self.upload_path_text.setPlaceholderText('上传路径(如images/)')
self.upload_domain_label = QLabel('upload_domain')
self.upload_domain_text = QLineEdit()
self.upload_domain_text.setPlaceholderText('绑定域名(需要带https://)')
self.set_confirm = QPushButton('保存')
self.set_confirm.setObjectName('set_confirm')
self.set_default = QPushButton('设为默认图床')
self.set_default.setCheckable(False)
self.set_default.setObjectName('default_btn')
btn_layout = QHBoxLayout()
btn_layout.addWidget(self.set_confirm)
btn_layout.addWidget(self.set_default)
# 填充配置文件
config = checkConfig(set_config_path())
if config != None:
self.access_key_id_text.setText(config[0])
self.access_key_secret_text.setText(config[1])
self.bucket_name_text.setText(config[2])
self.endpoint_text.setText(config[3])
self.upload_path_text.setText(config[4])
self.upload_domain_text.setText(config[5])
self.set_confirm.clicked.connect(self.save_config)
layout.addWidget(self.access_key_id_label, 0, 0)
layout.addWidget(self.access_key_id_text, 0, 1)
layout.addWidget(self.access_key_secret_label, 1, 0)
layout.addWidget(self.access_key_secret_text, 1, 1)
layout.addWidget(self.bucket_name_label, 2, 0)
layout.addWidget(self.bucket_name_text, 2, 1)
layout.addWidget(self.endpoint_label, 3, 0)
layout.addWidget(self.endpoint_text, 3, 1)
layout.addWidget(self.upload_path_label, 4, 0)
layout.addWidget(self.upload_path_text, 4, 1)
layout.addWidget(self.upload_domain_label, 5, 0)
layout.addWidget(self.upload_domain_text, 5, 1)
layout.addItem(btn_layout, 6, 1)
self.setLayout(layout)
def save_config(self):
saveConfig(self.access_key_id_text.text(), self.access_key_secret_text.text(), self.bucket_name_text.text(),
self.endpoint_text.text(),
self.upload_path_text.text(), self.upload_domain_text.text())

65
tool/FileConfig.py Normal file
View file

@ -0,0 +1,65 @@
import json
import os
import platform
config_json = '''
{
"OSS_ACCESS_KEY_ID": "",
"OSS_ACCESS_KEY_SECRET": "",
"OSS_BUCKET": "",
"OSS_ENDPOINT": "",
"UPLOAD_PATH": "",
"UPLOAD_DOMAIN": ""
}
'''
def set_config_path():
# 创建Linux下配置文件目录
if platform.system() == 'Linux':
#
config_path = os.path.expanduser('~') + '/.config/PyQtPicUpload/'
if not os.path.exists(config_path):
os.mkdir(config_path)
# print(config_path)
config_file = config_path + 'config.json'
return config_file
# 检测配置文件
def checkConfig(config_file):
try:
with open(config_file, 'r') as file:
config = json.load(file)
# print(str(config))
access_key_id = config['OSS_ACCESS_KEY_ID']
# print(access_key_id)
access_key_secret = config['OSS_ACCESS_KEY_SECRET']
# print(access_key_secret)
bucket_name = config['OSS_BUCKET']
endpoint = config['OSS_ENDPOINT']
upload_path = config['UPLOAD_PATH']
upload_domain = config['UPLOAD_DOMAIN']
# print(upload_domain)
for param in (access_key_id, access_key_secret, bucket_name, endpoint, upload_path, upload_domain):
assert '' != param, '请配置上传参数!'
return [access_key_id, access_key_secret, bucket_name, endpoint, upload_path, upload_domain]
except Exception as e:
print(e)
return None
def saveConfig(access_key_id, access_key_secret, bucket_name, endpoint, upload_path, upload_domain):
config_file = set_config_path()
with open(config_file, 'w+') as file:
json_config = {
"OSS_ACCESS_KEY_ID": access_key_id,
"OSS_ACCESS_KEY_SECRET": access_key_secret,
"OSS_BUCKET": bucket_name,
"OSS_ENDPOINT": endpoint,
"UPLOAD_PATH": upload_path if upload_path[-1] == '/' else upload_path + '/',
"UPLOAD_DOMAIN": upload_domain if upload_domain[-1] == '/' else upload_domain + '/'
}
file.write(json.dumps(json_config))

8
tool/QSSLoader.py Normal file
View file

@ -0,0 +1,8 @@
class QSSLoader:
def __init__(self):
pass
@staticmethod
def read_qss_file(qss_file_name):
with open(qss_file_name, 'r', encoding='UTF-8') as file:
return file.read()

173
tool/UploadTip.py Normal file
View file

@ -0,0 +1,173 @@
import json
import sys
import time
import os
import oss2
from PyQt5.QtCore import QSize, Qt, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtGui import QPixmap
from tool import FileConfig
import notify2
class UploadAction(QThread):
status = pyqtSignal(str)
def __init__(self, filepath):
super(UploadAction, self).__init__()
try:
with open(FileConfig.set_config_path(), 'r') as file:
config = json.load(file)
except Exception as e:
print(e)
self.status.emit(False)
self.filepath = filepath
# print(str(config))
self.access_key_id = config['OSS_ACCESS_KEY_ID']
# print(access_key_id)
self.access_key_secret = config['OSS_ACCESS_KEY_SECRET']
# print(access_key_secret)
self.bucket_name = config['OSS_BUCKET']
self.endpoint = config['OSS_ENDPOINT']
self.upload_path = config['UPLOAD_PATH'] if config['UPLOAD_PATH'][-1] == '/' else config['UPLOAD_PATH'] + '/'
# 在域名后面添加 /
self.upload_domain = config['UPLOAD_DOMAIN'] if config['UPLOAD_DOMAIN'][-1] == '/' else config[
'UPLOAD_DOMAIN'] + '/'
def percentage(self, consumed_bytes, total_bytes):
"""进度条回调函数,计算当前完成的百分比
:param consumed_bytes: 已经上传/下载的数据量
:param total_bytes: 总数据量
"""
if total_bytes:
rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
print('\r{0}% '.format(rate))
sys.stdout.flush()
def run(self):
print('filepath:',self.filepath)
# 创建Bucket对象所有Object相关的接口都可以通过Bucket对象来进行
bucket = oss2.Bucket(oss2.Auth(self.access_key_id, self.access_key_secret), self.endpoint, self.bucket_name)
# 必须以二进制的方式打开文件。
# 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
with open(self.filepath, 'rb') as fileobj:
# 填写Object完整路径。Object完整路径中不能包含Bucket名称。
upload_name = self.upload_path + self.filepath.split('/')[-1]
bucket.put_object(upload_name, fileobj, progress_callback=self.percentage)
self.status.emit(self.upload_domain + upload_name)
# print('result_url:',self.upload_domain + upload_name)
class UploadTip(QWidget):
def __init__(self):
super(UploadTip, self).__init__()
self.pic_show = QLabel()
# self.resize(300,500)
# self.pic_show.setMaximumSize(300, 400)
self.pic_show.setObjectName('pic_show')
# self.pic_show.setStyleSheet('align:center')
self.pic_show.setAlignment(Qt.AlignCenter)
self.pic_show.setPixmap(
QPixmap(os.getcwd() + '/images/upload.png'))
self.pic_show.setStyleSheet('border:4px solid;')
# self.pic_show.
# .scaled(self.pic_show.size(), aspectRatioMode=QtCore.Qt.KeepAspectRatio)
self.pic_tip = QLabel('Ctrl + V 粘贴图片')
self.pic_tip.setAlignment(QtCore.Qt.AlignCenter)
self.tip_layout = QVBoxLayout(self)
self.tip_layout.addStretch()
self.tip_layout.addWidget(self.pic_show)
self.tip_layout.addStretch()
self.tip_layout.addWidget(self.pic_tip)
# self.tip_layout.addStretch()
self.upload_btn = QPushButton('点击上传')
self.upload_btn.setObjectName('upload_btn')
# self.upload_btn.set(Qt.AlignCenter)
self.tip_layout.addWidget(self.upload_btn, 0, Qt.AlignCenter)
# layout.setSpacing(0)
# 美化风格
# self.setStyleSheet(qt_material.apply_stylesheet(self,''))
self.createActions()
self.upload_btn.clicked.connect(self.upload_action)
self.restore_path = ''
self.setLayout(self.tip_layout)
def upload_action(self):
if self.restore_path != '':
self.upload_btn.setEnabled(False)
self.upload_btn.setText('上传中...')
self.upload_action.start()
def upload_status(self, status):
# print('upload_status:',status)
# 判断上传结果
if status:
print(status)
clipboard = QApplication.clipboard()
clipboard.setText('![]('+status+')')
notify2.init('OSS上传')
notify2.Notification('OSS上传',status,self.restore_path).show()
self.upload_btn.setText('点击上传')
self.upload_btn.setEnabled(True)
else:
print('upload error ')
os.remove(self.restore_path)
def createActions(self):
pastAction = QAction(self)
pastAction.setShortcut("Ctrl+V")
pastAction.triggered.connect(self.pasteData)
self.addAction((pastAction)) # Activate QAction
def setImage(self, path):
# print(path)
image = QPixmap(path)
# print(image.width(),image.height())
if image.width() > image.height():
scale = self.pic_show.width() / image.width()
# print('比例:', scale)
# width=scale*clipboard.pixmap().width()*scale
height = image.height() * scale
# print('转换后高度:', height)
self.pic_show.setPixmap(image.scaled(QSize(self.pic_show.width(), int(height)))) # 用于粘贴图片
else:
scale = self.pic_show.height() / image.height()
# print('比例:', scale)
width = image.width() * scale
# print('转换后宽度:', width)
self.pic_show.setPixmap(image.scaled(QSize(int(width), self.pic_show.height())))
self.pic_show.setAlignment(QtCore.Qt.AlignCenter)
def pasteData(self):
clipboard = QApplication.clipboard()
mimeData = clipboard.mimeData()
if mimeData.hasImage():
# 根据时间设置图片文件名
file_name = time.strftime('%Y-%m-%d-%H%M%S', time.localtime()) + '.png'
# 将图片保存到指定位置
self.restore_path = '/tmp/' + file_name
clipboard.pixmap().save(self.restore_path, 'PNG')
# print(restore_path)
self.setImage(self.restore_path)
elif mimeData.hasText():
self.restore_path = clipboard.text()
self.setImage(self.restore_path)
print("pasted from clipboard")
# 设置点击事件的信号传递
self.upload_action = UploadAction(self.restore_path)
self.upload_action.status.connect(self.upload_status)