Erste Version
This commit is contained in:
commit
fcf086bdee
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.idea
|
||||||
|
__pycache__
|
||||||
|
venv
|
||||||
|
Dicom Extractor 2023.exe
|
13
LICENSE
Normal file
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar
|
||||||
|
14 rue de Plaisance, 75014 Paris, France
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
BIN
Resources/icon.ico
Normal file
BIN
Resources/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
11
compile.bat
Normal file
11
compile.bat
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
python -m nuitka^
|
||||||
|
--onefile^
|
||||||
|
--disable-console^
|
||||||
|
--windows-icon-from-ico=Resources\icon.ico^
|
||||||
|
--include-data-files=Resources\icon.ico=icon.ico^
|
||||||
|
--plugin-enable=pyqt6^
|
||||||
|
--include-module=pydicom.encoders.gdcm^
|
||||||
|
--include-module=pydicom.encoders.pylibjpeg^
|
||||||
|
--output-filename="Dicom Extractor 2023.exe"^
|
||||||
|
--remove-output^
|
||||||
|
main.py
|
19
drives.py
Normal file
19
drives.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from ctypes import windll
|
||||||
|
from string import ascii_uppercase
|
||||||
|
|
||||||
|
|
||||||
|
class Drives:
|
||||||
|
def __init__(self):
|
||||||
|
self.list = self.getDrives()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getDrives():
|
||||||
|
drives = []
|
||||||
|
bitmask = windll.kernel32.GetLogicalDrives()
|
||||||
|
|
||||||
|
for letter in ascii_uppercase:
|
||||||
|
if bitmask & 1:
|
||||||
|
drives.append(letter)
|
||||||
|
bitmask >>= 1
|
||||||
|
|
||||||
|
return drives
|
10
main.py
Normal file
10
main.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
from wmain import wMain
|
||||||
|
|
||||||
|
version = "20231012"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication([])
|
||||||
|
app.setStyle("Fusion")
|
||||||
|
win = wMain(version)
|
||||||
|
app.exec()
|
49
registry.py
Normal file
49
registry.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import winreg
|
||||||
|
|
||||||
|
|
||||||
|
class Registry:
|
||||||
|
def __init__(self):
|
||||||
|
self.regInit()
|
||||||
|
self.ArchivePath, self.CDRomPath = self.regRead()
|
||||||
|
|
||||||
|
# Initialize registry with values if there are none
|
||||||
|
@staticmethod
|
||||||
|
def regInit():
|
||||||
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
||||||
|
|
||||||
|
# Key
|
||||||
|
try:
|
||||||
|
key = winreg.OpenKeyEx(reg, r"SOFTWARE\Dicom Extractor 2023", 0, winreg.KEY_ALL_ACCESS)
|
||||||
|
except FileNotFoundError:
|
||||||
|
winreg.CreateKey(reg, r"SOFTWARE\Dicom Extractor 2023")
|
||||||
|
key = winreg.OpenKeyEx(reg, r"SOFTWARE\Dicom Extractor 2023", 0, winreg.KEY_ALL_ACCESS)
|
||||||
|
|
||||||
|
# Value ArchivePath
|
||||||
|
try:
|
||||||
|
_ = winreg.QueryValueEx(key, "ArchivePath")
|
||||||
|
except FileNotFoundError:
|
||||||
|
winreg.SetValueEx(key, "ArchivePath", 0, winreg.REG_SZ, "Init")
|
||||||
|
|
||||||
|
# Value CDRomPath
|
||||||
|
try:
|
||||||
|
_ = winreg.QueryValueEx(key, "CDRomPath")
|
||||||
|
except FileNotFoundError:
|
||||||
|
winreg.SetValueEx(key, "CDRomPath", 0, winreg.REG_SZ, "C")
|
||||||
|
|
||||||
|
# Read values
|
||||||
|
@staticmethod
|
||||||
|
def regRead():
|
||||||
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
||||||
|
key = winreg.OpenKeyEx(reg, r"SOFTWARE\Dicom Extractor 2023", 0, winreg.KEY_ALL_ACCESS)
|
||||||
|
archivePath = winreg.QueryValueEx(key, "ArchivePath")
|
||||||
|
cdromPath = winreg.QueryValueEx(key, "CDRomPath")
|
||||||
|
|
||||||
|
return archivePath[0], cdromPath[0]
|
||||||
|
|
||||||
|
# Write values
|
||||||
|
@staticmethod
|
||||||
|
def regWrite(ArchivePath, CDRomPath):
|
||||||
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
||||||
|
key = winreg.OpenKeyEx(reg, r"SOFTWARE\Dicom Extractor 2023", 0, winreg.KEY_ALL_ACCESS)
|
||||||
|
winreg.SetValueEx(key, "ArchivePath", 0, winreg.REG_SZ, ArchivePath)
|
||||||
|
winreg.SetValueEx(key, "CDRomPath", 0, winreg.REG_SZ, CDRomPath)
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
PyQt6
|
||||||
|
pydicom
|
||||||
|
nuitka
|
213
warchive.py
Normal file
213
warchive.py
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import pydicom
|
||||||
|
import shutil
|
||||||
|
import random
|
||||||
|
from registry import Registry
|
||||||
|
from PyQt6.QtWidgets import QDialog
|
||||||
|
from PyQt6.QtWidgets import QLabel
|
||||||
|
from PyQt6.QtWidgets import QPushButton
|
||||||
|
from PyQt6.QtWidgets import QStyle
|
||||||
|
|
||||||
|
|
||||||
|
class wArchive(QDialog):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setFixedSize(400, 400)
|
||||||
|
self.setWindowTitle("Archiviere...")
|
||||||
|
self.setStyleSheet("background-color: white")
|
||||||
|
|
||||||
|
pixmap = QStyle.StandardPixmap.SP_DriveNetIcon
|
||||||
|
icon = self.style().standardIcon(pixmap)
|
||||||
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
|
column1w = 180
|
||||||
|
column2s = column1w + 20
|
||||||
|
column2w = 400 - column2s - 10
|
||||||
|
|
||||||
|
self.lLine1 = QLabel("Starte Archivierung:", self)
|
||||||
|
self.lLine1.setGeometry(10, 10, column1w, 20)
|
||||||
|
self.tLine1 = QLabel("", self)
|
||||||
|
self.tLine1.setGeometry(column2s, 10, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine2 = QLabel("Pfad zum Archiv:", self)
|
||||||
|
self.lLine2.setGeometry(10, 30, column1w, 20)
|
||||||
|
self.tLine2 = QLabel("", self)
|
||||||
|
self.tLine2.setGeometry(column2s, 30, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine3 = QLabel("CD-Rom-Laufwerk:", self)
|
||||||
|
self.lLine3.setGeometry(10, 50, column1w, 20)
|
||||||
|
self.tLine3 = QLabel("", self)
|
||||||
|
self.tLine3.setGeometry(column2s, 50, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine4 = QLabel("DICOMDIR-Datei gefunden:", self)
|
||||||
|
self.lLine4.setGeometry(10, 70, column1w, 20)
|
||||||
|
self.tLine4 = QLabel("", self)
|
||||||
|
self.tLine4.setGeometry(column2s, 70, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine5 = QLabel("DICOM-Verzeichnis gefunden:", self)
|
||||||
|
self.lLine5.setGeometry(10, 90, column1w, 20)
|
||||||
|
self.tLine5 = QLabel("", self)
|
||||||
|
self.tLine5.setGeometry(column2s, 90, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine6 = QLabel("Archiv beschreibbar:", self)
|
||||||
|
self.lLine6.setGeometry(10, 110, column1w, 20)
|
||||||
|
self.tLine6 = QLabel("", self)
|
||||||
|
self.tLine6.setGeometry(column2s, 110, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine7 = QLabel("DICOM-Dateien gefunden:", self)
|
||||||
|
self.lLine7.setGeometry(10, 130, column1w, 20)
|
||||||
|
self.tLine7 = QLabel("", self)
|
||||||
|
self.tLine7.setGeometry(column2s, 130, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine8 = QLabel("Name:", self)
|
||||||
|
self.lLine8.setGeometry(10, 150, column1w, 20)
|
||||||
|
self.tLine8 = QLabel("", self)
|
||||||
|
self.tLine8.setGeometry(column2s, 150, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine9 = QLabel("Geburtsdatum:", self)
|
||||||
|
self.lLine9.setGeometry(10, 170, column1w, 20)
|
||||||
|
self.tLine9 = QLabel("", self)
|
||||||
|
self.tLine9.setGeometry(column2s, 170, column2w, 20)
|
||||||
|
|
||||||
|
self.lLine10 = QLabel("Dateien:", self)
|
||||||
|
self.lLine10.setGeometry(10, 190, column1w, 20)
|
||||||
|
self.tLine10 = QLabel("", self)
|
||||||
|
self.tLine10.setGeometry(column2s, 190, column2w, 20)
|
||||||
|
|
||||||
|
self.bArchive = QPushButton("Archivieren", self)
|
||||||
|
self.bArchive.setGeometry(10, 350, 380, 40)
|
||||||
|
self.bArchive.setEnabled(False)
|
||||||
|
self.bArchive.clicked.connect(self.copyData)
|
||||||
|
|
||||||
|
archive = threading.Thread(target=self.archive)
|
||||||
|
archive.start()
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.exec()
|
||||||
|
|
||||||
|
def archive(self):
|
||||||
|
okay = "✓"
|
||||||
|
notokay = "✗"
|
||||||
|
|
||||||
|
self.tLine1.setText(okay)
|
||||||
|
self.tLine1.setStyleSheet("color: green")
|
||||||
|
|
||||||
|
reg = Registry()
|
||||||
|
self.ArchivePath, self.CDRomPath = reg.regRead()
|
||||||
|
self.tLine2.setText(self.ArchivePath)
|
||||||
|
self.tLine3.setText(self.CDRomPath + ":\\")
|
||||||
|
|
||||||
|
# Logic
|
||||||
|
dicomfile = False
|
||||||
|
dicomdir = False
|
||||||
|
target_writable = False
|
||||||
|
has_dicom_files = False
|
||||||
|
has_pName = False
|
||||||
|
has_pBirth = False
|
||||||
|
|
||||||
|
# Check if DICOMDIR file exists
|
||||||
|
if os.path.isfile(os.path.join(self.CDRomPath + ":", os.sep, "DICOMDIR")):
|
||||||
|
dicomfile = True
|
||||||
|
self.tLine4.setText(okay)
|
||||||
|
self.tLine4.setStyleSheet("color: green")
|
||||||
|
else:
|
||||||
|
self.tLine4.setText(notokay)
|
||||||
|
self.tLine4.setStyleSheet("color: red")
|
||||||
|
|
||||||
|
# Check if DICOM directory exists
|
||||||
|
if os.path.isdir(os.path.join(self.CDRomPath + ":", os.sep, "DICOM")):
|
||||||
|
dicomdir = True
|
||||||
|
self.tLine5.setText(okay)
|
||||||
|
self.tLine5.setStyleSheet("color: green")
|
||||||
|
else:
|
||||||
|
self.tLine5.setText(notokay)
|
||||||
|
self.tLine5.setStyleSheet("color: red")
|
||||||
|
|
||||||
|
# Check if ArchivePath is writable
|
||||||
|
if os.access(self.ArchivePath, os.W_OK) is True:
|
||||||
|
target_writable = True
|
||||||
|
self.tLine6.setText(okay)
|
||||||
|
self.tLine6.setStyleSheet("color: green")
|
||||||
|
else:
|
||||||
|
self.tLine6.setText(notokay)
|
||||||
|
self.tLine6.setStyleSheet("color: red")
|
||||||
|
|
||||||
|
# List of all files under DICOM directory
|
||||||
|
path = os.path.join(self.CDRomPath + ":", os.sep, "DICOM")
|
||||||
|
self.files = []
|
||||||
|
for x in os.walk(path):
|
||||||
|
for y in glob.glob(os.path.join(x[0], "*")):
|
||||||
|
if os.path.isfile(y):
|
||||||
|
self.files.append(y)
|
||||||
|
|
||||||
|
# Get PatientsName from first file
|
||||||
|
self.pName = ""
|
||||||
|
self.pBirth = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
dicom = pydicom.read_file(self.files[0])
|
||||||
|
self.pName = str(dicom.PatientName)
|
||||||
|
self.pBirth = str(dicom.PatientBirthDate)
|
||||||
|
has_dicom_files = True
|
||||||
|
has_pName = True
|
||||||
|
has_pBirth = True
|
||||||
|
self.tLine7.setText(okay)
|
||||||
|
self.tLine7.setStyleSheet("color: green")
|
||||||
|
except:
|
||||||
|
self.tLine7.setText(notokay)
|
||||||
|
self.tLine7.setStyleSheet("color: red")
|
||||||
|
|
||||||
|
# Output pName and pBirth
|
||||||
|
if self.pName and self.pBirth:
|
||||||
|
self.tLine8.setText(self.pName)
|
||||||
|
self.tLine8.setStyleSheet("color: green")
|
||||||
|
self.tLine9.setText(self.pBirth)
|
||||||
|
self.tLine9.setStyleSheet("color: green")
|
||||||
|
else:
|
||||||
|
self.tLine8.setText(notokay)
|
||||||
|
self.tLine8.setStyleSheet("color: red")
|
||||||
|
self.tLine9.setText(notokay)
|
||||||
|
self.tLine9.setStyleSheet("color: red")
|
||||||
|
|
||||||
|
# Output file count
|
||||||
|
self.tLine10.setText(str(len(self.files)))
|
||||||
|
|
||||||
|
# Activate bArchive
|
||||||
|
if dicomfile and dicomdir and target_writable and has_dicom_files and has_pBirth and has_pName:
|
||||||
|
self.bArchive.setEnabled(True)
|
||||||
|
|
||||||
|
def copyData(self):
|
||||||
|
self.bArchive.setEnabled(False)
|
||||||
|
|
||||||
|
source = self.files
|
||||||
|
|
||||||
|
# LastName^FirstName^Birth
|
||||||
|
mainFolder = os.path.join(self.ArchivePath, self.pName + "^" + self.pBirth)
|
||||||
|
try:
|
||||||
|
os.mkdir(mainFolder)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# LastName^FirstName^Birth\1234
|
||||||
|
subFolder = self.randomString(4)
|
||||||
|
os.mkdir(os.path.join(mainFolder, subFolder))
|
||||||
|
|
||||||
|
for file in source:
|
||||||
|
shutil.copy(file, os.path.join(mainFolder, subFolder))
|
||||||
|
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def randomString(length):
|
||||||
|
string = ""
|
||||||
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
|
||||||
|
for _ in range(length):
|
||||||
|
char = random.choice(chars)
|
||||||
|
string = string + char
|
||||||
|
|
||||||
|
return string
|
80
wconfig.py
Normal file
80
wconfig.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from registry import Registry
|
||||||
|
from drives import Drives
|
||||||
|
from PyQt6.QtWidgets import QPushButton
|
||||||
|
from PyQt6.QtWidgets import QLabel
|
||||||
|
from PyQt6.QtWidgets import QLineEdit
|
||||||
|
from PyQt6.QtWidgets import QComboBox
|
||||||
|
from PyQt6.QtWidgets import QStyle
|
||||||
|
from PyQt6.QtWidgets import QDialog
|
||||||
|
from PyQt6 import QtCore
|
||||||
|
|
||||||
|
|
||||||
|
class wConfig(QDialog):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.reg = Registry()
|
||||||
|
self.drives = Drives()
|
||||||
|
|
||||||
|
self.setWindowTitle("Konfiguration")
|
||||||
|
self.setFixedSize(300, 120)
|
||||||
|
|
||||||
|
pixmap = QStyle.StandardPixmap.SP_DriveNetIcon
|
||||||
|
icon = self.style().standardIcon(pixmap)
|
||||||
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
|
# Window should stay on top and only close button is visible
|
||||||
|
self.setWindowFlags(QtCore.Qt.WindowType.WindowStaysOnTopHint | QtCore.Qt.WindowType.WindowCloseButtonHint)
|
||||||
|
|
||||||
|
# ArchivePath label and input field
|
||||||
|
self.lArchivePath = QLabel("Pfad zum Archiv:", self)
|
||||||
|
self.lArchivePath.setGeometry(10, 10, 100, 20)
|
||||||
|
|
||||||
|
self.leArchivePath = QLineEdit(self)
|
||||||
|
self.leArchivePath.setText(self.reg.ArchivePath)
|
||||||
|
self.leArchivePath.setGeometry(155, 10, 135, 20)
|
||||||
|
|
||||||
|
# CDRomPath label and drop down menu
|
||||||
|
self.lCDRomPath = QLabel("CD-Rom-Laufwerk:", self)
|
||||||
|
self.lCDRomPath.setGeometry(10, 40, 100, 20)
|
||||||
|
|
||||||
|
self.ddCDRomPath = QComboBox(self)
|
||||||
|
self.ddCDRomPath.addItems(self.drives.list)
|
||||||
|
self.ddCDRomPath.setCurrentText(self.reg.CDRomPath)
|
||||||
|
self.ddCDRomPath.setGeometry(155, 40, 135, 20)
|
||||||
|
|
||||||
|
# Apply
|
||||||
|
self.bApply = QPushButton("Übernehmen", self)
|
||||||
|
self.bApply.setGeometry(10, 70, 135, 40)
|
||||||
|
self.bApply.clicked.connect(self.bApplyFunction)
|
||||||
|
|
||||||
|
# Cancel / Close
|
||||||
|
self.bClose = QPushButton("Schließen", self)
|
||||||
|
self.bClose.setGeometry(155, 70, 135, 40)
|
||||||
|
self.bClose.clicked.connect(self.bCloseFunction)
|
||||||
|
|
||||||
|
self.exec()
|
||||||
|
|
||||||
|
def bApplyFunction(self):
|
||||||
|
# Get text from ArchivePath input field
|
||||||
|
ArchivePath = self.leArchivePath.text()
|
||||||
|
|
||||||
|
# Remove all backslashes from the end of the string
|
||||||
|
while ArchivePath[-1] == "\\":
|
||||||
|
ArchivePath = ArchivePath[:-1]
|
||||||
|
|
||||||
|
# Get selected item from CDRomPath drop down menu
|
||||||
|
CDRomPath = self.ddCDRomPath.currentText()
|
||||||
|
|
||||||
|
# Set both variables in the running app
|
||||||
|
self.reg.ArchivePath = ArchivePath
|
||||||
|
self.reg.CDRomPath = CDRomPath
|
||||||
|
|
||||||
|
# Write both variables to the registry
|
||||||
|
self.reg.regWrite(ArchivePath, CDRomPath)
|
||||||
|
|
||||||
|
def bCloseFunction(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.close()
|
53
wmain.py
Normal file
53
wmain.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
from warchive import wArchive
|
||||||
|
from wconfig import wConfig
|
||||||
|
from PyQt6.QtWidgets import QMainWindow
|
||||||
|
from PyQt6.QtWidgets import QPushButton
|
||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
from PyQt6.QtWidgets import QLabel
|
||||||
|
from PyQt6.QtGui import QIcon
|
||||||
|
from PyQt6.QtCore import Qt
|
||||||
|
|
||||||
|
|
||||||
|
class wMain(QMainWindow):
|
||||||
|
def __init__(self, version):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setWindowTitle("DICOM Extractor 2023")
|
||||||
|
self.setFixedSize(400, 180)
|
||||||
|
self.setWindowIcon(QIcon("Resources\\icon.ico"))
|
||||||
|
|
||||||
|
# Archive button
|
||||||
|
self.bArchive = QPushButton("Archivieren", self)
|
||||||
|
self.bArchive.setGeometry(10, 10, 380, 100)
|
||||||
|
self.bArchive.clicked.connect(self.bArchiveFunction)
|
||||||
|
|
||||||
|
# Config button
|
||||||
|
self.bConfig = QPushButton("Konfiguration", self)
|
||||||
|
self.bConfig.setGeometry(10, 120, 185, 40)
|
||||||
|
self.bConfig.clicked.connect(self.bConfigFunction)
|
||||||
|
|
||||||
|
# Quit button
|
||||||
|
self.bQuit = QPushButton("Beenden", self)
|
||||||
|
self.bQuit.setGeometry(205, 120, 185, 40)
|
||||||
|
self.bQuit.clicked.connect(self.bQuitFunction)
|
||||||
|
|
||||||
|
# Version
|
||||||
|
self.lVersion = QLabel("Version " + version, self)
|
||||||
|
self.lVersion.setGeometry(10, 162, 380, 20)
|
||||||
|
self.lVersion.setAlignment(Qt.AlignmentFlag.AlignHCenter)
|
||||||
|
self.setStyleSheet("QLabel{ color: grey; font-size: 10px; }")
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def bArchiveFunction(self):
|
||||||
|
self.wArchive = wArchive()
|
||||||
|
|
||||||
|
def bConfigFunction(self):
|
||||||
|
self.wConfig = wConfig()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bQuitFunction():
|
||||||
|
QApplication.quit()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
QApplication.quit()
|
Loading…
Reference in New Issue
Block a user