【原创小软件】图片压缩工具

公司同事做标书做合同需要用到很多图片,然后做出来的成品有时又会有文件大小的限制,所以需要压缩图片,又不希望改变图片分辨率,因为会影响清晰度,如果原本是png, bmp图片,另存为jpg就会小很多了,但有时候,jpg也还是嫌大,所以需要在jpg的基础上再压缩,给同事简单地解释了一下,结论是jpg不能再压缩了,除非改变分辨率或者改变清晰度,妥协后的结果是,分辨率不能小,清晰度可以根据情况降低。
然后同事拿出了2个网上找的图片压缩工具,效果可以接受,但最大的压缩比例,在有些情况下文件大小还是太大,而且在使用上希望可以再方便一点,于是收集了需求如下:

  1. 可以选择单个图片、多个图片、多个文件夹
  2. 可以单独选择某个文件类型,也可以选择所有文件类型
  3. 可以在压缩前预览压缩后的大小
  4. 最好可以预览压缩后的图片质量(画面质量),并和压缩前的图片放在一起对比
  5. 可以选择压缩后图片另存为路径,也可以直接就保存在原图片一起

1,2其实是最初的需求,在拿出成品后给多名同事使用后,又出现了3,4,5需求,所以甲方才会被人砍(狗头,你看第3点,因为jpg压缩有不可预测性,你看连PS在保存jpg的时候,也只是给了个预估的大小,你再看第4点,心里的话:这个需求做不了!我跟同事说,这个功能连photoshop 2020都没有,表示做不了。
但是后来下班骑车的时候一想,3和4也不是不能实现啊,1.0版的时候,是压缩完了,读取新旧文件,然后显示压缩前后的文件大小对比,要达到“预览”的效果,我tm直接把这个压缩完了的结果说是“预览”不就好了嘛,反正使用上也体会不到区别,至于对比压缩前后的图片质量,我也tm直接把图片先给压缩完了,再把新旧图片同时显示出来对比不就好了嘛。一开始不能做的想法,是太从程序本身出发了,预测jpg的压缩比例和预测压缩后的图片质量,这种不可能的事如果从用户角度出发,只要呈现出需要的结果就行了,况且都0202年了,机器性能对于这种小工具来说,近乎是取之不尽的,怎么方便怎么来就是了。

先放张成品图
在这里插入图片描述
UI部分的代码:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Help(object):
    def setupUi(self, Help):
        Help.setObjectName("Help")
        Help.resize(700, 450)
        Help.setMinimumSize(QtCore.QSize(700, 450))
        Help.setMaximumSize(QtCore.QSize(700, 450))
        self.buttonBox = QtWidgets.QDialogButtonBox(Help)
        self.buttonBox.setGeometry(QtCore.QRect(240, 400, 191, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.lb_help = QtWidgets.QLabel(Help)
        self.lb_help.setGeometry(QtCore.QRect(10, 10, 251, 16))
        self.lb_help.setObjectName("lb_help")
        self.lb_img = QtWidgets.QLabel(Help)
        self.lb_img.setGeometry(QtCore.QRect(20, 30, 661, 371))
        self.lb_img.setText("")
        self.lb_img.setPixmap(QtGui.QPixmap("help.png"))
        self.lb_img.setObjectName("lb_img")

        self.retranslateUi(Help)
        self.buttonBox.accepted.connect(Help.accept)
        self.buttonBox.rejected.connect(Help.reject)
        QtCore.QMetaObject.connectSlotsByName(Help)

    def retranslateUi(self, Help):
        _translate = QtCore.QCoreApplication.translate
        Help.setWindowTitle(_translate("Help", "Help"))
        self.lb_help.setText(_translate("Help", "关于“选择多个文件夹”按钮的用法"))

因为还有一个帮助的弹窗,分另一个文件写了UI

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_JPG_Compressor(object):
    def setupUi(self, JPG_Compressor):
        JPG_Compressor.setObjectName("JPG_Compressor")
        JPG_Compressor.resize(900, 700)
        JPG_Compressor.setMinimumSize(QtCore.QSize(900, 700))
        JPG_Compressor.setMaximumSize(QtCore.QSize(900, 700))
        self.te_showDetails = QtWidgets.QTextEdit(JPG_Compressor)
        self.te_showDetails.setGeometry(QtCore.QRect(270, 10, 611, 271))
        self.te_showDetails.setFocusPolicy(QtCore.Qt.NoFocus)
        self.te_showDetails.setObjectName("te_showDetails")
        self.layoutWidget = QtWidgets.QWidget(JPG_Compressor)
        self.layoutWidget.setGeometry(QtCore.QRect(20, 10, 241, 201))
        self.layoutWidget.setObjectName("layoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.bt_selectFiles = QtWidgets.QPushButton(self.layoutWidget)
        self.bt_selectFiles.setObjectName("bt_selectFiles")
        self.horizontalLayout.addWidget(self.bt_selectFiles)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setSpacing(7)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem2)
        self.bt_selectDirs = QtWidgets.QPushButton(self.layoutWidget)
        self.bt_selectDirs.setObjectName("bt_selectDirs")
        self.horizontalLayout_2.addWidget(self.bt_selectDirs)
        spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem3)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.qualitySlider = QtWidgets.QSlider(self.layoutWidget)
        self.qualitySlider.setMinimum(10)
        self.qualitySlider.setMaximum(90)
        self.qualitySlider.setProperty("value", 50)
        self.qualitySlider.setOrientation(QtCore.Qt.Horizontal)
        self.qualitySlider.setObjectName("qualitySlider")
        self.verticalLayout.addWidget(self.qualitySlider)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_3.addItem(spacerItem4)
        self.lb_qualityText = QtWidgets.QLabel(self.layoutWidget)
        self.lb_qualityText.setObjectName("lb_qualityText")
        self.horizontalLayout_3.addWidget(self.lb_qualityText)
        self.lb_quality = QtWidgets.QLabel(self.layoutWidget)
        self.lb_quality.setObjectName("lb_quality")
        self.horizontalLayout_3.addWidget(self.lb_quality)
        spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_3.addItem(spacerItem5)
        self.verticalLayout.addLayout(self.horizontalLayout_3)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_6.addItem(spacerItem6)
        self.bt_preview = QtWidgets.QPushButton(self.layoutWidget)
        self.bt_preview.setObjectName("bt_preview")
        self.horizontalLayout_6.addWidget(self.bt_preview)
        spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_6.addItem(spacerItem7)
        self.verticalLayout.addLayout(self.horizontalLayout_6)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem8)
        self.bt_compress = QtWidgets.QPushButton(self.layoutWidget)
        self.bt_compress.setObjectName("bt_compress")
        self.horizontalLayout_4.addWidget(self.bt_compress)
        self.bt_save = QtWidgets.QPushButton(self.layoutWidget)
        self.bt_save.setObjectName("bt_save")
        self.horizontalLayout_4.addWidget(self.bt_save)
        spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem9)
        self.verticalLayout.addLayout(self.horizontalLayout_4)
        self.layoutWidget1 = QtWidgets.QWidget(JPG_Compressor)
        self.layoutWidget1.setGeometry(QtCore.QRect(20, 290, 861, 391))
        self.layoutWidget1.setObjectName("layoutWidget1")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.layoutWidget1)
        self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.lb_before = QtWidgets.QLabel(self.layoutWidget1)
        self.lb_before.setObjectName("lb_before")
        self.horizontalLayout_5.addWidget(self.lb_before)
        spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem10)
        self.verticalLayout_2.addLayout(self.horizontalLayout_5)
        self.gv_before = QtWidgets.QGraphicsView(self.layoutWidget1)
        self.gv_before.setFocusPolicy(QtCore.Qt.NoFocus)
        self.gv_before.setObjectName("gv_before")
        self.verticalLayout_2.addWidget(self.gv_before)
        self.horizontalLayout_8.addLayout(self.verticalLayout_2)
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.lb_after = QtWidgets.QLabel(self.layoutWidget1)
        self.lb_after.setObjectName("lb_after")
        self.horizontalLayout_7.addWidget(self.lb_after)
        spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem11)
        self.verticalLayout_3.addLayout(self.horizontalLayout_7)
        self.gv_after = QtWidgets.QGraphicsView(self.layoutWidget1)
        self.gv_after.setFocusPolicy(QtCore.Qt.NoFocus)
        self.gv_after.setObjectName("gv_after")
        self.verticalLayout_3.addWidget(self.gv_after)
        self.horizontalLayout_8.addLayout(self.verticalLayout_3)
        self.bt_previewimg = QtWidgets.QPushButton(JPG_Compressor)
        self.bt_previewimg.setGeometry(QtCore.QRect(80, 250, 131, 28))
        self.bt_previewimg.setObjectName("bt_previewimg")
        self.bt_help = QtWidgets.QPushButton(JPG_Compressor)
        self.bt_help.setGeometry(QtCore.QRect(20, 220, 31, 28))
        self.bt_help.setObjectName("bt_help")

        self.retranslateUi(JPG_Compressor)
        QtCore.QMetaObject.connectSlotsByName(JPG_Compressor)

    def retranslateUi(self, JPG_Compressor):
        _translate = QtCore.QCoreApplication.translate
        JPG_Compressor.setWindowTitle(_translate("JPG_Compressor", "图片压缩工具 V1.3"))
        self.bt_selectFiles.setText(_translate("JPG_Compressor", "选择文件"))
        self.bt_selectDirs.setText(_translate("JPG_Compressor", "选择多个文件夹"))
        self.lb_qualityText.setText(_translate("JPG_Compressor", "文件质量:"))
        self.lb_quality.setText(_translate("JPG_Compressor", "50"))
        self.bt_preview.setText(_translate("JPG_Compressor", "压缩并预览文件大小"))
        self.bt_compress.setText(_translate("JPG_Compressor", "就地保存"))
        self.bt_save.setText(_translate("JPG_Compressor", "另存为图片"))
        self.lb_before.setText(_translate("JPG_Compressor", "压缩前"))
        self.lb_after.setText(_translate("JPG_Compressor", "压缩后"))
        self.bt_previewimg.setText(_translate("JPG_Compressor", "预览图片质量"))
        self.bt_help.setText(_translate("JPG_Compressor", "?"))

程序代码:

import re, os, sys, shutil
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QFileDialog, QGraphicsPixmapItem, QGraphicsScene, QDialog
from PyQt5.QtGui import QPixmap, QTextCursor
from PIL import Image
from JPG_Compressor_UI import Ui_JPG_Compressor
from JPG_Compressor_Help_UI import Ui_Help

class JpgCompressor(QtWidgets.QWidget, Ui_JPG_Compressor):
    def __init__(self):
        super(JpgCompressor, self).__init__()
        self.setupUi(self)
        #初始化UI及信号连接
        self.qualitySlider.setMinimum(10)
        self.qualitySlider.setMaximum(90)
        self.qualitySlider.setValue(50)
        self.lb_quality.setText('50')
        self.qualitySlider.valueChanged.connect(self.QualityChanged)
        self.bt_selectFiles.clicked.connect(self.SelectFiles)
        self.bt_selectDirs.clicked.connect(self.SelectDirs)
        self.bt_preview.clicked.connect(self.Preview)
        self.bt_compress.clicked.connect(lambda:self.Save(0))
        self.bt_save.clicked.connect(lambda:self.Save(1))
        self.bt_help.clicked.connect(self.DisplayHelp)
        self.bt_previewimg.clicked.connect(self.PreviewImg)
        #初始化默认路径
        with open('config.ini', 'r') as file:
            self.inidir =file.read()
        self.filepaths = []             #列表存放文件完整路径
        self.dirs = []                  #列表存放文件夹的路径
        self.selectedpath = ''          #选中的文件夹
        self.filecount = 0              #选中的文件数
        self.compressmode = 0                   #选择文件的模式
        self.comprssed = 0              #标记是否完成压缩
        #若上次意外退出,初始化时清理文件
        if os.path.exists('temp'):
            shutil.rmtree('temp')

    def QualityChanged(self):
        self.lb_quality.setText(str(self.qualitySlider.value()))

    def SelectFiles(self):
        selectedfiles, filetype = QFileDialog.getOpenFileNames(self, '选择文件', self.inidir, 'Image Files(*.jpg;*.jpeg;*.png;*.bmp)')
        #仅当选择了文件之后执行
        if(selectedfiles != []):
            self.compressmode = 0
            self.te_showDetails.clear()     #清空显示框
            self.filecount = len(selectedfiles)
            self.filepaths = selectedfiles
            #记录当前选中文件的路径,作为下次开启对话框时的初始路径
            self.inidir = os.path.dirname(self.filepaths[0])
            self.te_showDetails.setText('已选择' + str(len(self.filepaths)) + '个文件')

    def SelectDirs(self):
        self.selectedpath = QFileDialog.getExistingDirectory(self, '选择文件夹', self.inidir + '/..')
        #仅当选择了文件夹之后执行
        if(self.selectedpath != ''):
            self.compressmode = 1
            self.inidir = self.selectedpath
            self.te_showDetails.clear()
            self.Clear()
            #列出文件夹中所有文件
            buf = os.listdir(self.selectedpath)
            for i in buf:
                #只保留文件夹
                if os.path.isdir(self.selectedpath + '/' + i):
                    self.dirs.append(self.selectedpath + '/' + i + '/')
            self.te_showDetails.setText('已选择:')
            self.te_showDetails.append(str(len(self.dirs)) + '个文件夹')
            #读取各个文件夹中的文件路径
            self.ReadFilesFromDirs()

    def ReadFilesFromDirs(self):
        self.filecount = 0
        for path in self.dirs:
            filename = os.listdir(path)
            #只保留图像文件
            for i in filename:
                if re.search('\.jpg|\.JPG|\.png|\.PNG|\.jpeg|\.JPEG|\.bmp|\.BMP', i) != None:
                    self.filepaths.append(path + i)
                    self.filecount += 1
        self.te_showDetails.append(str(self.filecount) + '个文件')

    def Preview(self):
        if len(self.filepaths) == 0:
            self.te_showDetails.append('没有选择文件!')
        else:
            for i in self.filepaths:
                #压缩文件
                self.Compress(i)
            #标记已经完成压缩
            self.comprssed = 1
            self.te_showDetails.append('所有图片已压缩完成')
    
    def Compress(self, filepath):
        dirname = os.path.dirname(filepath)
        #读取文件名
        filename = os.path.basename(filepath)
        #过滤掉后缀名
        filename_ex = re.sub('\.jpg|\.JPG|\.png|\.PNG|\.jpeg|\.JPEG|\.bmp|\.BMP', '', filename)
        #创建临时文件夹
        if not os.path.exists('temp'):
            os.mkdir('temp')
        os.chdir('temp')
        #打开图片并保存
        with Image.open(filepath).convert('RGB') as img:
            #一律保存为jpg格式
            #如果选择的只有文件
            if self.compressmode == 0:
                newpath = os.path.abspath('.') + '/' + filename_ex + '.jpg'
            #如果选择的是多个文件夹
            elif self.compressmode == 1:
                buf = os.path.basename(dirname)
                #在temp文件夹里创建相应的子文件夹
                if not os.path.exists(buf):
                    os.mkdir(buf)
                newpath = os.path.abspath('.') + '/' + buf + '/' + filename_ex + '.jpg'
            img.save(newpath, quality = self.qualitySlider.value())
        #退出文件夹
        os.chdir('..')
        #显示压缩结果
        self.ShowDetails(filename, filepath, newpath)

    def ShowDetails(self, filename, oldpath, newpath):
        old = os.path.getsize(oldpath) / 1024.0
        new = os.path.getsize(newpath) / 1024.0
        old = round(old, 1)
        new = round(new, 1)
        self.te_showDetails.append(filename + '\t\t' + str(old) + 'KB --> ' + str(new) + 'KB')
        #把光标移到最下面
        self.te_showDetails.moveCursor(QTextCursor.End)

    def Save(self, savemode):
        #选择了文件,并且完成了压缩
        if self.filecount != 0 and self.comprssed == 1:
            #选择就地保存
            if savemode == 0:
                #如果是选择了文件压缩的
                if self.compressmode == 0:
                    #扫描temp文件夹内所有文件
                    files = os.listdir('./temp')
                    #设置目的地
                    dest = os.path.dirname(self.filepaths[0]) + '/已压缩'
                    #在原图片位置创建文件夹:已压缩
                    if not os.path.exists(dest):
                        os.mkdir(dest)
                    #逐个移动文件
                    for f in files:
                        source = './temp/' + f
                        try:
                            shutil.move(source, dest)
                        except shutil.Error:
                            self.te_showDetails.append('文件已存在!')
                #如果是选择了文件夹压缩的
                elif self.compressmode == 1:
                    for i in range(len(self.dirs)):
                        #在每一个原文件夹位置创建新文件夹:已压缩
                        if not os.path.exists(self.dirs[i] + '/已压缩'):
                            os.mkdir(self.dirs[i] + '/已压缩')
                        #设置起始地文件夹位置
                        buf = os.path.abspath(self.dirs[i])
                        sourcedir = './temp/' + os.path.basename(buf)
                        #设置目的地文件夹位置
                        dest = self.dirs[i] + '已压缩/'
                        files = os.listdir(sourcedir)
                        #逐个移动文件
                        for f in files:
                            source = sourcedir + '/' + f
                            try:
                                shutil.move(source, dest)
                            except shutil.Error:
                                self.te_showDetails.append('文件已存在!')
            #选择另存为
            elif savemode == 1:
                #选择保存的位置
                filepath = QFileDialog.getExistingDirectory(self, '选择保存位置', self.inidir + '/..')
                #把临时文件夹中的图片移动到需要保存的位置
                files = os.listdir('./temp/')
                for i in files:
                    shutil.move('./temp/' + i, filepath)
                self.te_showDetails.append('文件另存为成功')
            #重设压缩标记
            self.comprssed = 0
            self.Clear()
        #没有选择文件
        elif self.filecount == 0:
            self.te_showDetails.append('没有选择文件!')
        #选择了文件,但没有完成压缩
        elif self.filecount != 0 and self.comprssed == 0:
            self.te_showDetails.append('没有完成压缩!')

    def PreviewImg(self):
        if self.filecount == 0:
            self.te_showDetails.append('没有选择文件!')
        elif self.filecount > 1:
            self.te_showDetails.append('请选择单个文件!')
        else:
            #先压缩图片
            self.Compress(self.filepaths[0])
            #创建pixmap对象
            img_1 = QPixmap()
            img_2 = QPixmap()
            #pixmap读取图片
            QPixmap.load(img_1, self.filepaths[0])
            buf = re.sub('\.png|\.PNG|\.jpeg|\.JPEG|\.bmp|\.BMP', '.jpg', os.path.basename(self.filepaths[0]))
            QPixmap.load(img_2, './temp/' + buf)
            #创建graphics pixmap item
            item_1 = QGraphicsPixmapItem(img_1)
            item_2 = QGraphicsPixmapItem(img_2)
            #创建graphics scene
            scene_1 = QGraphicsScene()
            scene_2 = QGraphicsScene()
            #往scene里添加item
            scene_1.addItem(item_1)
            scene_2.addItem(item_2)
            #往graphics view里设置scene
            self.gv_before.setScene(scene_1)
            self.gv_after.setScene(scene_2)
            #设置graphics view为自适应item尺寸
            self.gv_before.fitInView(item_1)
            self.gv_after.fitInView(item_2)

    #清场用
    def Clear(self):
        self.filecount = 0
        self.filepaths.clear()
        self.dirs.clear()

    #显示帮助
    def DisplayHelp(self):
        self.helpwindow = Help()
        self.helpwindow.show()

    #重写退出事件,退出前清场并更新ini文件
    def closeEvent(self, event):
        if os.path.exists('temp'):
            shutil.rmtree('temp')
        with open('config.ini', 'w') as file:
            file.write(self.inidir)

#弹出帮助窗口类
class Help(QDialog, Ui_Help):
    def __init__(self):
        super(Help, self).__init__()
        self.setupUi(self)

if __name__=="__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainwindow = JpgCompressor()
    mainwindow.show()
    sys.exit(app.exec_())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
毕业设计,基于SpringBoot+Vue+MySQL开发的社区医院管理系统,源码+数据库+毕业论文+视频演示 信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的社区医院管理系统实现了病例信息、字典表、家庭医生、健康档案、就诊信息、前台、药品、用户、用户、用户表等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让社区医院管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。 关键字:社区医院管理系统;信息管理,时效性,安全性,MySql
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值