A little introduction pyQt5 -- completing an Excel file processing program from zero to one

Posted by micheal_newby on Fri, 14 Jan 2022 14:17:40 +0100

1, Overview

This project is a course design of mine. The course design requires a software that can realize the functions of Excel addition, deletion, modification and query and corresponding image addition, deletion, modification and query. Finally, it is required to be packaged into exe. Because of data confidentiality, I deleted the relevant pictures and tables in the code, leaving only two test pictures. As the saying goes, you can't do it in vain. I have never been in serious contact with QtDesigner and python before, and my understanding of Python only stays in functions. Therefore, there are many deficiencies in the design mode of the program, including I think the whole project will be a little messy, and the details are written in readme In MD, many people can't get into GitHub, so the code is placed on the code cloud. I found that there is no unified entry post on the Internet. I stepped on many pits this time and wrote it hard. I feel it is of great significance for reference, including pagination, strengthening robustness, etc. I will write it based on the realization of function points to give you a door. There may be more than one article to talk about. All open sources are for you. The specific function implementation depends on the code more clearly. If you have any suggestions about optimization or error, please contact me!

2, Project description (you can also directly see the README.md file)

2.1 project structure

|-data  data
    |-dist  Excel File output location
        |-new.xls  New after user operation Excel file
    |-dist_images  Store the original data image, and the user operates the image reading and output position
        |-M0  Normal sample image
        |-M1  Abnormal sample image
        |-new Add unclassified image
    |-info.xlsx  Example Excel file
|-detect  Neural network(*It can be replaced and cannot be changed. It should also be changed during replacement detail.py Interface in file)
    |-logs  
        |-best.pth  Network weight
    |-model_data
        |-cls_classes.txt  category
    |-nets  Network subject
    |-utils Tool function folder
    |-classification.py  Classification network class
|-icon Icon Folder
	|-cat.ico  program icon Icon
|-img  Example image
|-Clinical_information  Clinical information interface file
|-detail  Image file
|-Image_information Excel  Table image information file
|-information  Main interface layout file
|-new_info  Add patient information file
|-main.py  Program entry file
|-main.spec  Packaged intermediate files
|-requirements.txt  Library version requirements
|-README.md  Project description
|-.gitignore  git Ignored files

# The training network is resnet50 
# Reference blogger: https://blog.csdn.net/weixin_44791964/article/details/109160814

2.2 use

After installing the appropriate environment, click Run main Py.

2.3 function introduction

  1. Before using all functions, you need to open the Excel file as a table database through "Open Excel", otherwise you will be prompted.

  2. View rendering: when the user selects an Excel file, the table view will be rendered automatically, and the current page and total pages will be calculated automatically. The status bar below will display the current user's operation.

  3. When the main interface window is closed, other interfaces will also be closed.

  4. Search patient: when the user enters the first few digits of the ID number and clicks the "search" button, the first matching patient information will be automatically found, and the current page and line will be automatically jumped and located.

  5. Page switching function: click "previous page" to jump to the previous page, and click "next page" to jump to the next page. When you click "previous page" and "next page" on the first page and the last page respectively, a prompt box will pop up.

  6. Click the "view" button to view the clinical information and image information of patients in the current line.

  7. Modification function: double click the cell, press Enter after modifying the content, and the modified data will be written to new in dist folder again Xls file, which will not pollute the original data. For clinical information and image information, click the "confirm modification" button after modification.

  8. Delete function: click the "delete" button, and the modified data will be written to new in dist folder again Xls file, which will not pollute the original data.

  9. Add patient information: click the "add patient information" button. After filling in the information, click the "submit" button. Similarly, the added information will be written to new In the XLS file, the new image will be placed in the images/new folder. After clicking "+ add image" to select the image, the "" before "image information" will disappear. Pay attention to the format when filling in the information. For example, the date format is "YYYY-MM-DD", and the ID number cannot exceed nine digits.

  10. View the image information corresponding to the patient: click the "view" button under the "image information" column, and click the "view image" button in the pop-up interface.

  11. Click the "add", "modify", "delete" and "AI detection" buttons in the interface in 7 to add, delete, modify and artificial intelligence diagnosis. The diagnosis results will be displayed in the output column below, and the folder will be placed under the M0 and M1 folders corresponding to images.

2.4 precautions

  1. The py file is not exactly the same as the ui file. The ui file is just used for layout. Some fine-tuning parts are directly modified in the py file with code, and the ui is not completely synchronized.
  2. The entire application is based on info Xlsx data format to design, and does not have a strong fission ability, if not in strict accordance with info Xlsx rows and columns for typesetting, the maximum probability does not run.
  3. The image shall be named in strict accordance with the format of "ID number -rk", and the ID number shall not exceed nine digits.

2.5 package into exe program

  1. After installing virtualenv, use the command virtualenv env in cmd_ Name creates a virtual environment to isolate it from anaconda's environment and reduce the volume of the package. The project has more than 2GB after packaging, because the torch package accounts for 2GB.

  2. Pychart opens Terminal and switches to Env_ Under the name / scripts path, enter activate Bat activation environment.

  3. View requirements Txt, use pip install to install all packages until No module error is reported.

  4. Run the following command in the active environment:

    pyinstaller main.spec
    
  5. Create the following folder in the generated dist folder:

    |-data  data
        |-dist  
        |-dist_images
            |-M0 Folder named by class alias
            |-M1 Folder named by class alias
            |-new Add unclassified image (it can't be changed at will. If you change it, you need to change the code synchronously)
    

2.6 deficiencies

  1. In different computers, the interface display will be different, and there is no adaptation.
  2. The header should not be written dead. It is better to write it to render with the data.
  3. The robustness is not very strong. For example, if the format in the table is incorrect, it should be intercepted and prompted, and should not be terminated without reason.
  4. It is better to let users choose the folder where data can be opened and stored. The user experience is better. There is a problem with the original design mode.
  5. The modification function needs to be optimized.

3, Getting started with QtDesigner (official start!)

QtDesigner official document

3.1 start

I skipped the environment installation. Please configure QtDesigner and Turn around py tool later (No.

edition: pycharm 2017.3
  1. Click tool - > external tools - > qtdesigner to run
  2. You can open the existing in the pop-up window ui file, or create a new one ui file, here we select MainWindow and click create. (the difference between MainWindow and Widget is that MainWindow has a menu bar and a status bar at the bottom. You can select Widget if you don't need it.)
  3. add controls

    Drag the control in the left column to the canvas and release it to add it. Note that the object name in the "object viewer" in the upper right corner can be modified for better recognition and can not be duplicate.
    When you click the selected control with the left mouse button, the properties of the currently selected control will be displayed in the "property editor" on the right, listing the property values of this class and all its parent classes. We can modify them through the property editor. For example, QTableWIDget has the properties of rowCount and columnCount. You can modify the number of rows and columns of the table.
  4. Modify the name of the main program window

    Search for "title" in the Attribute Editor on the right and modify the value of windowTitle.
  5. Signal slot
    a. Click "Edit signal / slot" in QtDesigner menu bar;

    b. Click the control with the left mouse button to pull out a ground wire. When grounded, only the signal of the current control will be triggered, and when connected with other controls, multiple signals will be triggered at the same time;

    c. In the pop-up window, the left side is the signal that can be triggered by the control, and the right side is the slot function connected with this signal. For example, the clicked signal of the button is connected with the slot function searchInfo. Click to select the signal on the left, then click the slot function on the right, and click OK to associate.

    To create a new slot function, click Edit.

    Then click "+" and enter the slot function name.

    Note: here, the slot function associated with the control must be generated py file, otherwise an error will be reported at runtime.
  6. Menu bar signal slot
    New menu: double click Enter here to Enter the editing mode, Enter the tab name of the menu bar and press Enter to complete the new menu.

    Similarly, double click "Enter here" in the tab and press Enter to create a new sub tab.

    Select the action editor tab in the action editor column at the bottom right.

    Right click and select new.

    Fill in the name of the tab in the pop-up window, the shortcut key of shortcut, and click "OK".

    Switch to the signal / slot editor, click the green "+" in the upper left corner to create a new one.

    Select the sender as the newly created action, signal, receiver and slot, as follows:


    The slot function is user-defined. If you don't know how to create a new slot function, go back to 5 View.
  7. Will The ui file is converted to a file with the same name py file, note: every time it is regenerated py file will overwrite the contents of the original file, that is, if you write new code in it, you should be very careful. It can't run at this time. Let's open a new main py file, copy the following code and run it.
import sys
from information import Ui_MainWindow  # By information Information transferred from UI Py file, Ui_MainWindow is information Py. This step is written according to your own class name.
class MyMainForm(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
	# Slot function
	def MethodName(self):
		print("test")
if __name__ == "__main__":
    #Fixed, PyQt5 programs need QApplication objects. sys.argv is a list of command-line parameters to ensure that the program can be run by double clicking
    app = QApplication(sys.argv)
    #initialization
    myWin = MyMainForm()
    #Displays the window control on the screen
    myWin.show()
    #Program running, sys The exit method ensures that the program exits completely.
    sys.exit(app.exec())

### If this step does not work, please check main Is there a slot function associated with the control just defined in the PY file.

Summary
At this step, the basic process has been opened up and you can start your own page layout!
3.2 introduce the special function points and compare them. This is the program for processing Excel files

3.2 table data rendering and inserting button controls in cells

When the user opens the excel file, the information in the excel file is rendered to the QTableWidget. It is divided into three steps: use xlrd library to read Excel files, get the information of each line, and render it to QTableWidget by line. See main readExcel, getOnePage and information.py file The generateRow methods in the. Py file. (please import the corresponding package!)

# Read Excel file
    def readExcel(self, fileName):
        workbook = xlrd.open_workbook(fileName)
        # Get sheet_name
        self.sheet_name = workbook.sheet_names()[0]
        # Get sheet content according to sheet index or name
        self.sheet = workbook.sheet_by_index(0)  # Start at index 0

        # Total number of rows obtained
        self.nrows = self.sheet.nrows
        # Get total pages
        self.pageCount = math.ceil((self.nrows - 2) / self.pageSize)
        self.setTotalPage(self.pageCount)
        # Gets the number of rows on the last page
        self.lastPageCount = self.nrows - 2 - self.pageSize * (self.pageCount - 1)

        # Get the contents of the first column
        self.ids = self.sheet.col_values(0)
        for i, v in enumerate(self.ids):
            # Jump over two item s
            if i > 1:
               self.ids[i] = str(int(v))

    # Generate one page line by line
    def getOnePage(self):
        self.isEidt = False # isEdit is used as a valve. Because the cell changed signal of QTableWidget is connected, I don't want to trigger it in the early stage. I want to trigger it when the user modifies it
        self.changePageStatus(self.currentPage + 1)
        for i in range(self.pageSize):
            for j in range(self.infoCols):
                if self.lastPageFlag and i >= self.lastPageCount:
                    val = ''
                else:
                    index = self.currentPage * self.pageSize + i + 2
                    # Get value
                    val = self.sheet.cell_value(index, j)
                    if isinstance(val, float):
                        if j == 0:
                            # Remove the number after the decimal point
                            val = int(val)
                            # TableWidget needs string format to display normally
                            val = str(val)
                        elif j == 1:
                        	# Do date format conversion and display the correct date format
                            data_time = datetime(*xldate_as_tuple(val, 0))
                            val = data_time.strftime('%Y-%m-%d')
                        else:
                            val = str(val)
                # Remove header
                self.generateRow(i + 1, j, val, self.lastPageCount, self.lastPageFlag, index)
        self.isEidt = True

    # Generate a row of the table
    def generateRow(self, row, col, val, lastPageNum, lastPageFlag, trueRow):
        # print('p', row, col, val)
        item = QtWidgets.QTableWidgetItem(val)
        self.tableWidget.setItem(row, col, item)
        if row <= lastPageNum or lastPageFlag == False:
            # Insert view clinical information button
            self.bedButton = QtWidgets.QPushButton('see')
            self.bedButton.setStyleSheet('QPushButton{margin:3px};')
            self.bedButton.setObjectName("bedButton" + str(trueRow))
            self.tableWidget.setCellWidget(row, 6, self.bedButton)
            # Insert view video information button
            self.imageButton = QtWidgets.QPushButton('see')
            self.imageButton.setStyleSheet('QPushButton{margin:3px};')
            self.imageButton.setObjectName("imageButton" + str(trueRow))
            self.tableWidget.setCellWidget(row, 7, self.imageButton)
            # Insert delete information button
            self.deleteButton = QtWidgets.QPushButton('delete')
            self.deleteButton.setStyleSheet('QPushButton{margin:3px};')
            self.deleteButton.setObjectName("deleteButton" + str(trueRow))
            self.tableWidget.setCellWidget(row, 8, self.deleteButton)

            # lambda anonymous functions are used to pass parameters
            self.bedButton.clicked.connect(lambda: self.MainWindow.getBedInfo(trueRow))
            self.imageButton.clicked.connect(lambda: self.MainWindow.getImageInfo(trueRow))
            self.deleteButton.clicked.connect(lambda: self.MainWindow.deleInfo(trueRow))

        else:
            self.tableWidget.removeCellWidget(row, 6)
            self.tableWidget.removeCellWidget(row, 7)
            self.tableWidget.removeCellWidget(row, 8)

3.3 how to transfer parameters to slot functions?

Parameter passing: use the anonymous function lambda. The scenario is: when I click the button, open another Widget. At this time, I need to pass in the ID number.

# lambda anonymous functions are used to pass parameters
self.bedButton.clicked.connect(lambda: self.goToNewWidget(user_id))

def goToNewWidget(self, user_id):
	print(user_id)

3.4 how to click a button to open a new window?

  1. The tutorial before installation generates a new window Py file, such as new py.
  2. from new import Ui_new import a new py file and slot the corresponding button.
  3. The opening function is realized in the slot function.
self.bedButton.clicked.connect(self.goToNewWidget())

def goToNewWidget(self):
	self.new_widget = QWidget()
    self.new_ui = Ui_New_Info()
    self.new_ui.setupUi(self.new_widget, self)
    self.new_widget.setWindowTitle('New Information')
    self.new_widget.show()

3.5 text information displayed in the status bar

	self.statusbar.showMessage(message)

3.6 close all other windows when closing the main interface

Override the closeEvent method. See information closeEvent method in py file.

# --------------information.py------------------
	# Override close method
    def closeEvent(self, event):
        if self.MainWindow.clinical_widget:
            # print('close')
            self.MainWindow.clinical_widget.close()
        if self.MainWindow.image_widget:
            # print('close')
            self.MainWindow.image_widget.close()
        if self.MainWindow.new_widget:
            # print('close')
            self.MainWindow.new_widget.close()
        if self.MainWindow.detail_widget:
            # print('close')
            self.MainWindow.detail_widget.close()
        event.accept()

### All widgets here are mounted in main In the QMainWindow object in the QMainWindow. Py file, in order to get the widget in QMainWindow in other functions, I mount QMainWindow as the attribute of the current class, that is, self MainWindow = MainWindow, adding one more layer of if judgment is to prevent some windows from not opening. If this is closed, the program will get stuck.

# ---------------main.py-------------
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        self.setWindowIcon(QIcon('icon\cat.ico'))

        # Four windows
        self.clinical_widget = ''
        self.image_widget = ''
        self.new_widget = ''
        self.detail_widget = ''

3.7 Add icon icon of program

	self.setWindowIcon(QIcon('icon\cat.ico')

3.8 QTableWidget displays the correct date format

You will find that the date read from the Excel table is a string of numbers. You need to use the datetime library to convert it in order to display it correctly.

from datetime import datetime
from xlrd import xldate_as_tuple
data_time = datetime(*xldate_as_tuple(val, 0))
                            val = data_time.strftime('%Y-%m-%d')

# Write the correct date format in Excel
datetime.strptime(self.getTableWidgetItemContent(row, col), '%Y-%m-%d')

3.9 open file selection box

The first parameter is the window parent class of the open file selection box, the second parameter is the name of the pop-up selection box, the third parameter is the specified path to open (optional), and the fourth parameter is the restriction type (Note: the type restriction here is "invalid").

image_Name, imgType = QFileDialog.getOpenFileName(self,
                                                  "Select Picture",
                                                  "",
                                                       "*.jpg;;*.png;;All Files(*)")

3.10 pop up prompt box

from PyQt5.QtWidgets import *
 QMessageBox.information(self, "Tips", "The current page is the last!")
 QMessageBox.warning(self, "warning", "Please open it first Excel File!")
 QMessageBox.error(self, "warning", "Please open it first Excel File!")
 ### The specific pop-up box type depends on the document

3.11 displaying pictures on QLabel

See detail The setPixMap method in the. Py file.

    def setPixMap(self, path):
        # Use qlabel to display pictures, show_image is the object name of qlabel, which is described in the control added from 3.1
        png = QtGui.QPixmap(path).scaled(self.show_image.width(),self.show_image.height())
        self.show_image.setPixmap(png) # setPixmap here is the native method of QLabel
        self.show_image.setScaledContents(True)

4, Specific function realization

4.1 Excel query

Idea: get all the ID numbers in the Excel table and put them in the list. Because the ID numbers are stored by row, the index of the list is the number of rows of patient information in the Excel file - 1 (the list index starts from zero). When the user enters the ID number in the input box and clicks the search button, the spaces before and after the value in the input box will be intercepted, and the native methods count and index of the list will be used to check whether the current patient exists. If it exists, it will be located to that page and line, and if it does not exist, it will be given corresponding prompts. Users can automatically return the first match without entering the complete ID number. See main The searchInfo method in py.

    # Search for patient information
    def searchInfo(self):
        if self.fileName != '':
            search_id = self.getContent().strip() # String format
            self.showStatusMessage("search ID number:" + search_id)
            # Clear search box contents
            self.clearContect()

            # Use startswitch to return a list
            res = [idx for idx in self.ids if idx.startswith(search_id)]
            if len(res) == 0:
                QMessageBox.information(self, "Tips", "No match found")
            else:
                # The first match, index, is the actual number of rows in the Excel table
                index = self.ids.index(res[0]) - 2
                # Get the number of pages where matches are located
                page = math.floor(index / self.pageSize)
                row = (index % self.pageSize) + 1
                self.currentPage = page
                if self.currentPage == (self.pageCount - 1):
                    self.lastPageFlag = True
                self.getOnePage()
                self.isEidt = False
                self.setLineColor(row)
                self.isEidt = True
        else:
            QMessageBox.warning(self, "warning", "Please open it first Excel File!")

4.2 addition, deletion and modification of Excel

Idea: it's easy to understand that addition, deletion and modification can be understood as two steps: reading and rewriting. Use xlrd library to read Excel files and xlwt library to write Excel files. After adding, deleting and modifying the read information, write back the information after the operation. See main getNewXl method in PY

# Create a new workbook and save it. If there is row, it will be deleted, if there is row and col, it will be modified, if there is none, it will be new, change_val is the specified value. If it is not transmitted, it is the content modified by double clicking the table, and count is the counter to prevent multiple pop-up prompt boxes
    def getNewXl(self, row = -1, col = -1, change_val = '', count_n = 0):
        try:
            # New workbook
            workbook = xlwt.Workbook(encoding='utf-8')
            # New sheet
            sheet_w = workbook.add_sheet(self.sheet_name)

            # loop
            count = 0
            for x in range(self.sheet.nrows):
                if col == -1:
                    # delete
                    if x != row:
                        for y in range(self.sheet.ncols):
                            val = self.sheet.cell_value(x, y)
                            if y == 1:
                                dateFormat = xlwt.XFStyle()
                                dateFormat.num_format_str = 'yyyy/mm/dd'
                                sheet_w.write(count, y, val, dateFormat)
                            else:
                                sheet_w.write(count, y, val)
                        count = count + 1
                else:
                    # modify
                    for y in range(self.sheet.ncols):
                        if x == row and y == col:
                            if change_val == '':
                                val = self.text
                            else:
                                val = change_val
                        else:
                            val = self.sheet.cell_value(x, y)
                        if y == 1:
                            dateFormat = xlwt.XFStyle()
                            dateFormat.num_format_str = 'yyyy/mm/dd'
                            sheet_w.write(x, y, val, dateFormat)
                        else:
                            sheet_w.write(x, y, val)
            if row == -1:
                new_row = self.sheet.nrows
                # newly added
                for i, v in enumerate(self.forms):
                    if i == 1:
                        dateFormat = xlwt.XFStyle()
                        dateFormat.num_format_str = 'yyyy/mm/dd'
                        sheet_w.write(new_row, i, v, dateFormat)
                    else:
                        sheet_w.write(new_row, i, v)

            # Save Workbook
            path = self.dist_root + self.dist_name
            workbook.save(path)
            # Re render the view
            self.readExcel(path)
            self.getOnePage()
        except:
            if row == -1:
                QMessageBox.warning(self, "error", "Failed to add")
            elif col == -1:
                QMessageBox.warning(self, "error", "Deletion failed")
            else:
                if count_n == 0:
                    QMessageBox.warning(self, "error", "Modification failed")
                else:
                    self._count = self._count + 1
                    if self._count == count_n:
                        QMessageBox.warning(self, "error", "Modification failed")
                        self._count = 0
        else:
            if row ==  -1:
                self.showStatusMessage("Successfully added")
            elif col == -1:
                self.showStatusMessage("Delete succeeded")
            else:
                self.showStatusMessage("Modified successfully")

4.3 addition, deletion, modification and query of images in folders

Idea: to add, delete, change and query the pictures in a folder, there must be data. Therefore, we need to use the os library to traverse the files in the folder to obtain each file name and form a list of file names. Then we can find the information entered by the user in the list. The method is the same as that of Excel. Increment is realized by using cv2 this library. Delete is using os Remove method. Change is to add + delete. See detail The logic in the PY file.

# Get folder picture directory tuple
    def getDirectTuple(self):
        self.fileList = []
        for filepath, dirnames, filenames in os.walk(r'data\dist_images'):
            for filename in filenames:
                self.fileList.append(os.path.join(filepath, filename))
        # print(self.fileList)

5, Packing precautions

There are many tutorials on the Internet for packaging a single py file into exe, but for the whole project is very scattered. We use intermediate documents spec to improve the success rate. Note: the steps described here are finally packaged in a folder, not a single exe.
step

  • Open the cmd window, enter pip install pyinstaller, and the command line outputs successfully, indicating success.
  • Pychart opens Terminal and enters PYI makespec main Py -- > after packaging, a directory will be generated (main.py is the entry file of your program).
  • Now a main is generated under the folder Spec file.
  • Edit main Spec file, find a = Analysis()
    a. The first parameter is to place all py files needed. The format is ['aaa.py', 'bbb.py', 'ccc.py']. Note: under the same level directory, write the file name directly. If it is not under the same file, write the relative path ['aaa.py', 'bbb.py', 'director\ccc.py'].
    b. The fourth parameter, data = []. If a non py file needs to be packaged, find the data list and write the path and folder name of the non py file in the tuple. For example, if there are picture files, they can be placed in the images folder. The first item in the tuple is the path of the file before packaging, and the second item is the directory path of the file after packaging. Note: the relative path should be written here, and the first item and the second item should be the same. When there is nothing in the folder, the folder will be ignored. For the robustness of the program, it is best to use relative paths in the program. (if you understand, even if you don't understand)
    c. The fifth parameter, hiddenimports = []. If No module name... Appears after packaging, a temporary solution can be adopted to place the missing modules in this list. hiddenimports=[‘PyQt5.sip’]
    d. Add program icon. Add Icon = 'icon / cat. Exe ICO ', write the relative path! Here is a picture turn ico file website.
a = Analysis(['main.py', 'Clinical_information.py', 'detail.py', 'Image_information.py', 'information.py', 'new_info.py', 'detect\\classification.py', 'detect\\utils\\utils.py', 'detect\\nets\\__init__.py', 'detect\\nets\\mobilenet.py', 'detect\\nets\\resnet50.py', 'detect\\nets\\vgg16.py', 'detect\\nets\\vit.py'],
             pathex=['D:\\AhhC_File\\CourseDesign\\smodel_mart-medical-system'],
             binaries=[],
             datas=[('detect\\logs','detect\\logs'),('detect\\model_data','detect\\model_data'),('icon','icon')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True,
          icon='icon/cat.ico')

  • Finally, run pyinstaller main Spec, a build and dist folder will be generated when the package is successful
  • Reference articles : Although many of them are not applicable, well, thank you.
  • Solution to stack overflow error in packaging times
# In the generated main Add to spec file
# -*- mode: python ; coding: utf-8 -*-
import sys
sys.setrecursionlimit(5000)
  • Solution to too large folder volume after packaging
    If anaconda environment is used, the volume after packaging will be abnormally large, more than 3GB. This can be isolated by using the steps of 2.5 packaging into exe program.

summary

Every day I feel what junk code I write. I can't finish a sentence or two. I still have to look at the code, although I'm not a serious python person, although I'm just a front-end. After writing this program for about four or five days, I did my own testing and optimization, which also taught me some design patterns. It's really one day, write bug. Finally, I found many shortcomings, such as ugly and unable to adapt on my friend's computer after packaging, and some hidden bugs. If you want to learn something, you have to do it yourself!
Criticism and correction are welcome.

Code download

https://gitee.com/Jesy_Hsu/smart-medical-system.git

Topics: Python Qt