class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.setWindowModality(Qt.ApplicationModal) MainWindow.resize(1492, 1852) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) MainWindow.setMinimumSize(QSize(700, 700)) MainWindow.setMaximumSize(QSize(16777215, 16777215)) MainWindow.setBaseSize(QSize(600, 600)) font = QFont() font.setPointSize(12) font.setKerning(True) MainWindow.setFont(font) MainWindow.setAutoFillBackground(False) MainWindow.setStyleSheet(u"") MainWindow.setDocumentMode(False) MainWindow.setTabShape(QTabWidget.Rounded) MainWindow.setDockOptions(QMainWindow.AllowTabbedDocks|QMainWindow.AnimatedDocks) MainWindow.setUnifiedTitleAndToolBarOnMac(False) self.action_Quit = QAction(MainWindow) self.action_Quit.setObjectName(u"action_Quit") self.main_widget = QWidget(MainWindow) self.main_widget.setObjectName(u"main_widget") self.main_widget.setEnabled(True) self.main_widget.setMinimumSize(QSize(650, 650)) self.main_widget.setContextMenuPolicy(Qt.DefaultContextMenu) self.main_widget.setAutoFillBackground(False) self.main_widget.setStyleSheet(u"") self.main_layout = QGridLayout(self.main_widget) self.main_layout.setObjectName(u"main_layout") self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") self.log_button = QPushButton(self.main_widget) self.log_button.setObjectName(u"log_button") sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy1.setHorizontalStretch(0) sizePolicy1.setVerticalStretch(0) sizePolicy1.setHeightForWidth(self.log_button.sizePolicy().hasHeightForWidth()) self.log_button.setSizePolicy(sizePolicy1) self.log_button.setMinimumSize(QSize(24, 24)) font1 = QFont() font1.setPointSize(9) font1.setBold(True) font1.setKerning(True) self.log_button.setFont(font1) self.log_button.setCursor(QCursor(Qt.PointingHandCursor)) self.log_button.setCheckable(False) self.log_button.setFlat(True) self.horizontalLayout_2.addWidget(self.log_button) self.main_layout.addLayout(self.horizontalLayout_2, 5, 2, 1, 1) self.shuttle_widget = QWidget(self.main_widget) self.shuttle_widget.setObjectName(u"shuttle_widget") self.shuttle_widget.setMinimumSize(QSize(600, 600)) self.shuttle_widget.setMaximumSize(QSize(600, 600)) self.shuttle_widget.setAutoFillBackground(False) self.shuttle_widget.setStyleSheet(u"QWidget#shuttle_widget {background: url(images/ShuttleXpress_Black.png);\n" " background-repeat:no-repeat;}\n" " ") self.button_1 = QCheckBox(self.shuttle_widget) self.button_1.setObjectName(u"button_1") self.button_1.setGeometry(QRect(80, 266, 24, 24)) sizePolicy1.setHeightForWidth(self.button_1.sizePolicy().hasHeightForWidth()) self.button_1.setSizePolicy(sizePolicy1) self.button_1.setMinimumSize(QSize(24, 24)) self.button_1.setFont(font) self.button_1.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.usb_status = QPushButton(self.shuttle_widget) self.usb_status.setObjectName(u"usb_status") self.usb_status.setEnabled(False) self.usb_status.setGeometry(QRect(288, 10, 24, 24)) sizePolicy1.setHeightForWidth(self.usb_status.sizePolicy().hasHeightForWidth()) self.usb_status.setSizePolicy(sizePolicy1) self.usb_status.setMinimumSize(QSize(24, 24)) self.usb_status.setFont(font1) self.usb_status.setCursor(QCursor(Qt.ArrowCursor)) self.usb_status.setAutoFillBackground(False) self.usb_status.setText(u"") icon = QIcon() icon.addFile(u"images/usb_black_24.png", QSize(), QIcon.Disabled, QIcon.Off) icon.addFile(u"images/usb_white_24.png", QSize(), QIcon.Disabled, QIcon.On) self.usb_status.setIcon(icon) self.usb_status.setIconSize(QSize(24, 24)) self.usb_status.setCheckable(True) self.usb_status.setChecked(False) self.usb_status.setFlat(True) self.button_5 = QCheckBox(self.shuttle_widget) self.button_5.setObjectName(u"button_5") self.button_5.setGeometry(QRect(498, 266, 24, 24)) sizePolicy1.setHeightForWidth(self.button_5.sizePolicy().hasHeightForWidth()) self.button_5.setSizePolicy(sizePolicy1) self.button_5.setMinimumSize(QSize(24, 24)) self.button_5.setFont(font) self.button_5.setLayoutDirection(Qt.RightToLeft) self.button_5.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_pos4 = QRadioButton(self.shuttle_widget) self.wheel_pos4.setObjectName(u"wheel_pos4") self.wheel_pos4.setGeometry(QRect(382, 164, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos4.sizePolicy().hasHeightForWidth()) self.wheel_pos4.setSizePolicy(sizePolicy1) self.wheel_pos4.setMinimumSize(QSize(24, 24)) self.wheel_pos4.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_cent0 = QRadioButton(self.shuttle_widget) self.wheel_cent0.setObjectName(u"wheel_cent0") self.wheel_cent0.setGeometry(QRect(289, 130, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_cent0.sizePolicy().hasHeightForWidth()) self.wheel_cent0.setSizePolicy(sizePolicy1) self.wheel_cent0.setMinimumSize(QSize(24, 24)) self.wheel_cent0.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_cent0.setChecked(True) self.wheel_pos1 = QRadioButton(self.shuttle_widget) self.wheel_pos1.setObjectName(u"wheel_pos1") self.wheel_pos1.setGeometry(QRect(314, 133, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos1.sizePolicy().hasHeightForWidth()) self.wheel_pos1.setSizePolicy(sizePolicy1) self.wheel_pos1.setMinimumSize(QSize(24, 24)) self.wheel_pos1.setStyleSheet(u"color: white;") self.wheel_pos2 = QRadioButton(self.shuttle_widget) self.wheel_pos2.setObjectName(u"wheel_pos2") self.wheel_pos2.setGeometry(QRect(338, 139, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos2.sizePolicy().hasHeightForWidth()) self.wheel_pos2.setSizePolicy(sizePolicy1) self.wheel_pos2.setMinimumSize(QSize(24, 24)) self.wheel_pos2.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.dial = QDial(self.shuttle_widget) self.dial.setObjectName(u"dial") self.dial.setGeometry(QRect(197, 178, 216, 216)) sizePolicy2 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy2.setHorizontalStretch(0) sizePolicy2.setVerticalStretch(0) sizePolicy2.setHeightForWidth(self.dial.sizePolicy().hasHeightForWidth()) self.dial.setSizePolicy(sizePolicy2) self.dial.setMinimumSize(QSize(24, 24)) self.dial.setAutoFillBackground(False) self.dial.setStyleSheet(u"background-color: black;") self.dial.setMinimum(0) self.dial.setMaximum(10) self.dial.setPageStep(1) self.dial.setValue(5) self.dial.setSliderPosition(5) self.dial.setInvertedAppearance(False) self.dial.setInvertedControls(False) self.dial.setWrapping(True) self.dial.setNotchTarget(3.700000000000000) self.dial.setNotchesVisible(False) self.wheel_neg6 = QRadioButton(self.shuttle_widget) self.wheel_neg6.setObjectName(u"wheel_neg6") self.wheel_neg6.setGeometry(QRect(162, 204, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg6.sizePolicy().hasHeightForWidth()) self.wheel_neg6.setSizePolicy(sizePolicy1) self.wheel_neg6.setMinimumSize(QSize(24, 24)) self.wheel_neg6.setStyleSheet(u"color: white;") self.wheel_pos5 = QRadioButton(self.shuttle_widget) self.wheel_pos5.setObjectName(u"wheel_pos5") self.wheel_pos5.setGeometry(QRect(400, 182, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos5.sizePolicy().hasHeightForWidth()) self.wheel_pos5.setSizePolicy(sizePolicy1) self.wheel_pos5.setMinimumSize(QSize(24, 24)) self.wheel_pos5.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.button_2 = QCheckBox(self.shuttle_widget) self.button_2.setObjectName(u"button_2") self.button_2.setGeometry(QRect(156, 122, 24, 24)) sizePolicy1.setHeightForWidth(self.button_2.sizePolicy().hasHeightForWidth()) self.button_2.setSizePolicy(sizePolicy1) self.button_2.setMinimumSize(QSize(24, 24)) self.button_2.setFont(font) self.button_2.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_neg5 = QRadioButton(self.shuttle_widget) self.wheel_neg5.setObjectName(u"wheel_neg5") self.wheel_neg5.setGeometry(QRect(178, 182, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg5.sizePolicy().hasHeightForWidth()) self.wheel_neg5.setSizePolicy(sizePolicy1) self.wheel_neg5.setMinimumSize(QSize(24, 24)) self.wheel_neg5.setStyleSheet(u"color: white;") self.wheel_pos6 = QRadioButton(self.shuttle_widget) self.wheel_pos6.setObjectName(u"wheel_pos6") self.wheel_pos6.setGeometry(QRect(416, 204, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos6.sizePolicy().hasHeightForWidth()) self.wheel_pos6.setSizePolicy(sizePolicy1) self.wheel_pos6.setMinimumSize(QSize(24, 24)) self.wheel_pos6.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_neg1 = QRadioButton(self.shuttle_widget) self.wheel_neg1.setObjectName(u"wheel_neg1") self.wheel_neg1.setGeometry(QRect(264, 133, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg1.sizePolicy().hasHeightForWidth()) self.wheel_neg1.setSizePolicy(sizePolicy1) self.wheel_neg1.setMinimumSize(QSize(24, 24)) self.wheel_neg1.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.button_4 = QCheckBox(self.shuttle_widget) self.button_4.setObjectName(u"button_4") self.button_4.setGeometry(QRect(430, 122, 24, 24)) sizePolicy1.setHeightForWidth(self.button_4.sizePolicy().hasHeightForWidth()) self.button_4.setSizePolicy(sizePolicy1) self.button_4.setMinimumSize(QSize(24, 24)) self.button_4.setFont(font) self.button_4.setLayoutDirection(Qt.RightToLeft) self.button_4.setAutoFillBackground(False) self.button_4.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_pos7 = QRadioButton(self.shuttle_widget) self.wheel_pos7.setObjectName(u"wheel_pos7") self.wheel_pos7.setGeometry(QRect(427, 229, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos7.sizePolicy().hasHeightForWidth()) self.wheel_pos7.setSizePolicy(sizePolicy1) self.wheel_pos7.setMinimumSize(QSize(24, 24)) self.wheel_pos7.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.button_3 = QCheckBox(self.shuttle_widget) self.button_3.setObjectName(u"button_3") self.button_3.setGeometry(QRect(290, 72, 24, 24)) sizePolicy1.setHeightForWidth(self.button_3.sizePolicy().hasHeightForWidth()) self.button_3.setSizePolicy(sizePolicy1) self.button_3.setMinimumSize(QSize(24, 24)) self.button_3.setFont(font) self.button_3.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.button_3.setTristate(False) self.wheel_neg2 = QRadioButton(self.shuttle_widget) self.wheel_neg2.setObjectName(u"wheel_neg2") self.wheel_neg2.setGeometry(QRect(240, 139, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg2.sizePolicy().hasHeightForWidth()) self.wheel_neg2.setSizePolicy(sizePolicy1) self.wheel_neg2.setMinimumSize(QSize(24, 24)) self.wheel_neg2.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_pos3 = QRadioButton(self.shuttle_widget) self.wheel_pos3.setObjectName(u"wheel_pos3") self.wheel_pos3.setGeometry(QRect(361, 149, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_pos3.sizePolicy().hasHeightForWidth()) self.wheel_pos3.setSizePolicy(sizePolicy1) self.wheel_pos3.setMinimumSize(QSize(24, 24)) self.wheel_pos3.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_neg3 = QRadioButton(self.shuttle_widget) self.wheel_neg3.setObjectName(u"wheel_neg3") self.wheel_neg3.setGeometry(QRect(217, 149, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg3.sizePolicy().hasHeightForWidth()) self.wheel_neg3.setSizePolicy(sizePolicy1) self.wheel_neg3.setMinimumSize(QSize(24, 24)) self.wheel_neg3.setStyleSheet(u"color: white;") self.wheel_neg4 = QRadioButton(self.shuttle_widget) self.wheel_neg4.setObjectName(u"wheel_neg4") self.wheel_neg4.setGeometry(QRect(196, 164, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg4.sizePolicy().hasHeightForWidth()) self.wheel_neg4.setSizePolicy(sizePolicy1) self.wheel_neg4.setMinimumSize(QSize(24, 24)) self.wheel_neg4.setStyleSheet(u"background: #000000ff;\n" " color: white;\n" " ") self.wheel_neg7 = QRadioButton(self.shuttle_widget) self.wheel_neg7.setObjectName(u"wheel_neg7") self.wheel_neg7.setGeometry(QRect(151, 229, 24, 24)) sizePolicy1.setHeightForWidth(self.wheel_neg7.sizePolicy().hasHeightForWidth()) self.wheel_neg7.setSizePolicy(sizePolicy1) self.wheel_neg7.setMinimumSize(QSize(24, 24)) self.wheel_neg7.setStyleSheet(u"color: white;") self.dial.raise_() self.button_1.raise_() self.usb_status.raise_() self.button_5.raise_() self.wheel_pos4.raise_() self.wheel_cent0.raise_() self.wheel_pos1.raise_() self.wheel_pos2.raise_() self.wheel_neg6.raise_() self.wheel_pos5.raise_() self.button_2.raise_() self.wheel_neg5.raise_() self.wheel_pos6.raise_() self.wheel_neg1.raise_() self.button_4.raise_() self.wheel_pos7.raise_() self.button_3.raise_() self.wheel_neg2.raise_() self.wheel_pos3.raise_() self.wheel_neg3.raise_() self.wheel_neg4.raise_() self.wheel_neg7.raise_() self.main_layout.addWidget(self.shuttle_widget, 3, 2, 1, 1) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.about_button = QPushButton(self.main_widget) self.about_button.setObjectName(u"about_button") sizePolicy1.setHeightForWidth(self.about_button.sizePolicy().hasHeightForWidth()) self.about_button.setSizePolicy(sizePolicy1) self.about_button.setMinimumSize(QSize(24, 24)) self.about_button.setFont(font1) self.about_button.setCursor(QCursor(Qt.WhatsThisCursor)) self.about_button.setCheckable(False) self.about_button.setFlat(True) self.horizontalLayout.addWidget(self.about_button) self.main_layout.addLayout(self.horizontalLayout, 1, 2, 1, 1) self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") self.plug_button = QPushButton(self.main_widget) self.plug_button.setObjectName(u"plug_button") sizePolicy1.setHeightForWidth(self.plug_button.sizePolicy().hasHeightForWidth()) self.plug_button.setSizePolicy(sizePolicy1) self.plug_button.setMinimumSize(QSize(24, 24)) self.plug_button.setFont(font1) self.plug_button.setCursor(QCursor(Qt.PointingHandCursor)) self.plug_button.setCheckable(False) self.plug_button.setFlat(True) self.horizontalLayout_3.addWidget(self.plug_button) self.main_layout.addLayout(self.horizontalLayout_3, 3, 1, 1, 1) self.verticalLayout = QVBoxLayout() self.verticalLayout.setObjectName(u"verticalLayout") self.conf_button = QPushButton(self.main_widget) self.conf_button.setObjectName(u"conf_button") sizePolicy1.setHeightForWidth(self.conf_button.sizePolicy().hasHeightForWidth()) self.conf_button.setSizePolicy(sizePolicy1) self.conf_button.setMinimumSize(QSize(24, 24)) self.conf_button.setFont(font1) self.conf_button.setCursor(QCursor(Qt.PointingHandCursor)) self.conf_button.setCheckable(False) self.conf_button.setFlat(True) self.verticalLayout.addWidget(self.conf_button) self.main_layout.addLayout(self.verticalLayout, 3, 4, 1, 1) MainWindow.setCentralWidget(self.main_widget) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName(u"statusbar") self.statusbar.setMinimumSize(QSize(600, 0)) MainWindow.setStatusBar(self.statusbar) self.about_widget = QDockWidget(MainWindow) self.about_widget.setObjectName(u"about_widget") self.about_widget.setEnabled(True) sizePolicy3 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy3.setHorizontalStretch(0) sizePolicy3.setVerticalStretch(0) sizePolicy3.setHeightForWidth(self.about_widget.sizePolicy().hasHeightForWidth()) self.about_widget.setSizePolicy(sizePolicy3) self.about_widget.setMinimumSize(QSize(600, 600)) self.about_widget.setVisible(True) self.about_widget.setFloating(False) self.about_widget.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetMovable) self.about_widget.setAllowedAreas(Qt.TopDockWidgetArea) self.about_layout = QWidget() self.about_layout.setObjectName(u"about_layout") sizePolicy3.setHeightForWidth(self.about_layout.sizePolicy().hasHeightForWidth()) self.about_layout.setSizePolicy(sizePolicy3) self.about_layout.setAutoFillBackground(False) self.gridLayout_3 = QGridLayout(self.about_layout) self.gridLayout_3.setObjectName(u"gridLayout_3") self.about_text = QTextEdit(self.about_layout) self.about_text.setObjectName(u"about_text") self.about_text.setFocusPolicy(Qt.WheelFocus) self.about_text.setAcceptDrops(False) self.about_text.setStyleSheet(u"color: white;") self.about_text.setFrameShape(QFrame.StyledPanel) self.about_text.setFrameShadow(QFrame.Sunken) self.about_text.setUndoRedoEnabled(False) self.about_text.setReadOnly(True) self.about_text.setAcceptRichText(True) self.gridLayout_3.addWidget(self.about_text, 0, 0, 1, 1) self.about_widget.setWidget(self.about_layout) MainWindow.addDockWidget(Qt.TopDockWidgetArea, self.about_widget) self.log_widget = QDockWidget(MainWindow) self.log_widget.setObjectName(u"log_widget") self.log_widget.setEnabled(True) self.log_widget.setMinimumSize(QSize(550, 158)) self.log_widget.setFont(font) self.log_widget.setVisible(True) self.log_widget.setFloating(False) self.log_widget.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetFloatable|QDockWidget.DockWidgetMovable) self.log_widget.setAllowedAreas(Qt.BottomDockWidgetArea) self.log_layout = QWidget() self.log_layout.setObjectName(u"log_layout") sizePolicy4 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy4.setHorizontalStretch(0) sizePolicy4.setVerticalStretch(0) sizePolicy4.setHeightForWidth(self.log_layout.sizePolicy().hasHeightForWidth()) self.log_layout.setSizePolicy(sizePolicy4) self.gridLayout_2 = QGridLayout(self.log_layout) self.gridLayout_2.setObjectName(u"gridLayout_2") self.log_content_layout = QVBoxLayout() self.log_content_layout.setObjectName(u"log_content_layout") self.log_content_layout.setSizeConstraint(QLayout.SetDefaultConstraint) self.log_text = QPlainTextEdit(self.log_layout) self.log_text.setObjectName(u"log_text") sizePolicy4.setHeightForWidth(self.log_text.sizePolicy().hasHeightForWidth()) self.log_text.setSizePolicy(sizePolicy4) self.log_text.setMinimumSize(QSize(0, 0)) self.log_text.setAcceptDrops(False) self.log_text.setFrameShape(QFrame.StyledPanel) self.log_text.setFrameShadow(QFrame.Sunken) self.log_text.setUndoRedoEnabled(False) self.log_text.setReadOnly(True) self.log_content_layout.addWidget(self.log_text) self.buttons_layout = QHBoxLayout() self.buttons_layout.setObjectName(u"buttons_layout") self.buttons_layout.setSizeConstraint(QLayout.SetDefaultConstraint) self.log_clear_button = QToolButton(self.log_layout) self.log_clear_button.setObjectName(u"log_clear_button") icon1 = QIcon() icon1.addFile(u"images/delete-sweep_24.png", QSize(), QIcon.Normal, QIcon.Off) self.log_clear_button.setIcon(icon1) self.log_clear_button.setIconSize(QSize(24, 24)) self.buttons_layout.addWidget(self.log_clear_button) self.log_content_layout.addLayout(self.buttons_layout) self.gridLayout_2.addLayout(self.log_content_layout, 0, 0, 1, 1) self.log_widget.setWidget(self.log_layout) MainWindow.addDockWidget(Qt.BottomDockWidgetArea, self.log_widget) self.config_widget = QDockWidget(MainWindow) self.config_widget.setObjectName(u"config_widget") self.config_widget.setEnabled(True) self.config_widget.setMinimumSize(QSize(250, 600)) self.config_widget.setFloating(False) self.config_widget.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetFloatable|QDockWidget.DockWidgetMovable) self.config_widget.setAllowedAreas(Qt.RightDockWidgetArea) self.config_layout = QWidget() self.config_layout.setObjectName(u"config_layout") self.gridLayout = QGridLayout(self.config_layout) self.gridLayout.setObjectName(u"gridLayout") self.config_content_layout = QFormLayout() self.config_content_layout.setObjectName(u"config_content_layout") self.gridLayout.addLayout(self.config_content_layout, 0, 0, 1, 1) self.config_widget.setWidget(self.config_layout) MainWindow.addDockWidget(Qt.RightDockWidgetArea, self.config_widget) self.plugins_widget = QDockWidget(MainWindow) self.plugins_widget.setObjectName(u"plugins_widget") self.plugins_widget.setMinimumSize(QSize(250, 600)) self.plugins_widget.setAllowedAreas(Qt.LeftDockWidgetArea) self.dockWidgetContents = QWidget() self.dockWidgetContents.setObjectName(u"dockWidgetContents") self.plugins_widget.setWidget(self.dockWidgetContents) MainWindow.addDockWidget(Qt.LeftDockWidgetArea, self.plugins_widget) self.about_widget.raise_() self.log_widget.raise_() self.retranslateUi(MainWindow) self.usb_status.setDefault(False) QMetaObject.connectSlotsByName(MainWindow) # setupUi def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Contour ShuttleXpress", None)) self.action_Quit.setText(QCoreApplication.translate("MainWindow", u"&Quit", None)) #if QT_CONFIG(tooltip) self.log_button.setToolTip("") #endif // QT_CONFIG(tooltip) #if QT_CONFIG(statustip) self.log_button.setStatusTip(QCoreApplication.translate("MainWindow", u"Log", None)) #endif // QT_CONFIG(statustip) self.log_button.setText(QCoreApplication.translate("MainWindow", u"//", None)) #if QT_CONFIG(statustip) self.button_1.setStatusTip(QCoreApplication.translate("MainWindow", u"Button 1", None)) #endif // QT_CONFIG(statustip) self.button_1.setText("") #if QT_CONFIG(tooltip) self.usb_status.setToolTip("") #endif // QT_CONFIG(tooltip) #if QT_CONFIG(statustip) self.usb_status.setStatusTip(QCoreApplication.translate("MainWindow", u"USB connection status", None)) #endif // QT_CONFIG(statustip) #if QT_CONFIG(whatsthis) self.usb_status.setWhatsThis(QCoreApplication.translate("MainWindow", u"USB Status", None)) #endif // QT_CONFIG(whatsthis) #if QT_CONFIG(statustip) self.button_5.setStatusTip(QCoreApplication.translate("MainWindow", u"Button 5", None)) #endif // QT_CONFIG(statustip) self.button_5.setText("") #if QT_CONFIG(statustip) self.wheel_pos4.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 4", None)) #endif // QT_CONFIG(statustip) self.wheel_pos4.setText("") #if QT_CONFIG(statustip) self.wheel_cent0.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: center", None)) #endif // QT_CONFIG(statustip) self.wheel_cent0.setText("") #if QT_CONFIG(statustip) self.wheel_pos1.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 1", None)) #endif // QT_CONFIG(statustip) self.wheel_pos1.setText("") #if QT_CONFIG(statustip) self.wheel_pos2.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 2", None)) #endif // QT_CONFIG(statustip) self.wheel_pos2.setText("") #if QT_CONFIG(statustip) self.dial.setStatusTip(QCoreApplication.translate("MainWindow", u"Dial", None)) #endif // QT_CONFIG(statustip) #if QT_CONFIG(statustip) self.wheel_neg6.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 6", None)) #endif // QT_CONFIG(statustip) self.wheel_neg6.setText("") #if QT_CONFIG(statustip) self.wheel_pos5.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 5", None)) #endif // QT_CONFIG(statustip) self.wheel_pos5.setText("") #if QT_CONFIG(statustip) self.button_2.setStatusTip(QCoreApplication.translate("MainWindow", u"Button 2", None)) #endif // QT_CONFIG(statustip) self.button_2.setText("") #if QT_CONFIG(statustip) self.wheel_neg5.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 5", None)) #endif // QT_CONFIG(statustip) self.wheel_neg5.setText("") #if QT_CONFIG(statustip) self.wheel_pos6.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 6", None)) #endif // QT_CONFIG(statustip) self.wheel_pos6.setText("") #if QT_CONFIG(statustip) self.wheel_neg1.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 1", None)) #endif // QT_CONFIG(statustip) self.wheel_neg1.setText("") #if QT_CONFIG(statustip) self.button_4.setStatusTip(QCoreApplication.translate("MainWindow", u"Button 4", None)) #endif // QT_CONFIG(statustip) self.button_4.setText("") #if QT_CONFIG(statustip) self.wheel_pos7.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 7", None)) #endif // QT_CONFIG(statustip) self.wheel_pos7.setText("") #if QT_CONFIG(statustip) self.button_3.setStatusTip(QCoreApplication.translate("MainWindow", u"Button 3", None)) #endif // QT_CONFIG(statustip) self.button_3.setText("") #if QT_CONFIG(statustip) self.wheel_neg2.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 2", None)) #endif // QT_CONFIG(statustip) self.wheel_neg2.setText("") #if QT_CONFIG(statustip) self.wheel_pos3.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: right 3", None)) #endif // QT_CONFIG(statustip) self.wheel_pos3.setText("") #if QT_CONFIG(statustip) self.wheel_neg3.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 3", None)) #endif // QT_CONFIG(statustip) self.wheel_neg3.setText("") #if QT_CONFIG(statustip) self.wheel_neg4.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 4", None)) #endif // QT_CONFIG(statustip) self.wheel_neg4.setText(QCoreApplication.translate("MainWindow", u"-", None)) #if QT_CONFIG(statustip) self.wheel_neg7.setStatusTip(QCoreApplication.translate("MainWindow", u"Wheel position: left 7", None)) #endif // QT_CONFIG(statustip) self.wheel_neg7.setText("") #if QT_CONFIG(tooltip) self.about_button.setToolTip("") #endif // QT_CONFIG(tooltip) #if QT_CONFIG(statustip) self.about_button.setStatusTip(QCoreApplication.translate("MainWindow", u"About", None)) #endif // QT_CONFIG(statustip) self.about_button.setText(QCoreApplication.translate("MainWindow", u"?", None)) #if QT_CONFIG(tooltip) self.plug_button.setToolTip("") #endif // QT_CONFIG(tooltip) #if QT_CONFIG(statustip) self.plug_button.setStatusTip(QCoreApplication.translate("MainWindow", u"Configuration", None)) #endif // QT_CONFIG(statustip) self.plug_button.setText(QCoreApplication.translate("MainWindow", u"#", None)) #if QT_CONFIG(tooltip) self.conf_button.setToolTip("") #endif // QT_CONFIG(tooltip) #if QT_CONFIG(statustip) self.conf_button.setStatusTip(QCoreApplication.translate("MainWindow", u"Configuration", None)) #endif // QT_CONFIG(statustip) self.conf_button.setText(QCoreApplication.translate("MainWindow", u"=", None)) self.about_widget.setWindowTitle(QCoreApplication.translate("MainWindow", u"About", None)) self.about_text.setDocumentTitle("") self.log_widget.setWindowTitle(QCoreApplication.translate("MainWindow", u"Log", None)) self.log_clear_button.setText(QCoreApplication.translate("MainWindow", u"Clear", None)) self.config_widget.setWindowTitle(QCoreApplication.translate("MainWindow", u"Configuration", None)) self.plugins_widget.setWindowTitle(QCoreApplication.translate("MainWindow", u"Plugins", None))
class UIBuilder(object): """Constructs the UI for a main application window""" def setup(self, main_window: QMainWindow) -> None: """ Initialize the UI. :param main_window: An instance of the `QMainWindow` class. :type main_window: :class:`QMainWindow` """ main_window.setObjectName("main_window") main_window.setWindowTitle("TeaseAI") main_window.resize(1137, 751) main_window.setSizePolicy(*EXP_EXP) main_window.setTabShape(QTabWidget.Rounded) self.menubar = QMenuBar(main_window) self.menubar.setObjectName("menubar") self.menubar.setGeometry(0, 0, 1137, 23) self.file_menu = QMenu("File", self.menubar) self.file_menu.setObjectName("file_men") self.server_menu = QMenu("Server", self.menubar) self.server_menu.setObjectName("server_men") self.options_menu = QMenu("Options", self.menubar) self.options_menu.setObjectName("options_men") self.media_menu = QMenu("Media", self.menubar) self.media_menu.setObjectName("media_men") main_window.setMenuBar(self.menubar) self.exit = QAction("Exit", main_window) self.exit.setObjectName("exit") self.start_server = QAction("Start Server", main_window) self.start_server.setObjectName("start_server") self.connect_server = QAction("Connect to Server", main_window) self.connect_server.setObjectName("connect_server") self.kill_server = QAction("Kill Server", main_window) self.kill_server.setObjectName("kill_server") self.options = QAction("Options", main_window) self.options.setObjectName("options") self.start_webcam = QAction("Start Webcam", main_window) self.start_webcam.setObjectName("start_webcam") self.start_webcam.setCheckable(False) self.centralwidget = QWidget(main_window) self.centralwidget.setObjectName("centralwidget") self.centralwidget.setContentsMargins(QMargins(0, 0, 0, 0)) self.centralwidget.setSizePolicy(*EXP_EXP) self.grid_layout = QGridLayout(self.centralwidget) self.media = QFrame(self.centralwidget) self.media.setObjectName("media") self.media.setSizePolicy(*EXP_EXP) self.media.setMinimumSize(200, 200) self.media.setStyleSheet("background: #000;") self.grid_layout.addWidget(self.media, 0, 0, 5, 1) self.users_label = QLabel(" Online users:", self.centralwidget) self.users_label.setObjectName("users_label") self.users_label.setMinimumSize(300, 15) self.users_label.setMaximumSize(300, 15) self.grid_layout.addWidget(self.users_label, 0, 1, 1, 2) self.online = QPlainTextEdit("", self.centralwidget) self.online.setObjectName("online") self.online.setSizePolicy(*FIX_FIX) self.online.setMinimumSize(300, 50) self.online.setMaximumSize(300, 50) self.online.setStyleSheet("margin-left: 3px;" + SUNKEN) self.online.setLineWidth(2) self.online.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.online.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.online.setSizeAdjustPolicy(QAbstractScrollArea.AdjustIgnored) self.online.setReadOnly(True) self.grid_layout.addWidget(self.online, 1, 1, 1, 2) self.chat = QPlainTextEdit("", self.centralwidget) self.chat.setObjectName("chat") self.chat.setSizePolicy(*FIX_EXP) self.chat.setMinimumSize(300, 0) self.chat.setMaximumSize(300, INFINITE) self.chat.setStyleSheet("margin-bottom: 3px; margin-top: 8px;" + SUNKEN) self.chat.setLineWidth(2) self.chat.setReadOnly(True) self.chat.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.grid_layout.addWidget(self.chat, 2, 1, 1, 2) self.input = QLineEdit(self.centralwidget) self.input.setObjectName("input") self.input.setSizePolicy(*FIX_FIX) self.input.setMinimumSize(224, 30) self.input.setMaximumSize(224, 30) self.input.setStyleSheet(SUNKEN) self.input.setEchoMode(QLineEdit.Normal) self.input.setClearButtonEnabled(True) self.grid_layout.addWidget(self.input, 3, 1, 1, 1) self.submit = QPushButton("Submit", self.centralwidget) self.submit.setObjectName("submit") self.submit.setSizePolicy(*FIX_FIX) self.submit.setMinimumSize(70, 30) self.submit.setMaximumSize(70, 30) self.grid_layout.addWidget(self.submit, 3, 2, 1, 1) self.tabs = QTabWidget(self.centralwidget) self.tabs.setObjectName("tabs") self.tabs.setSizePolicy(*FIX_FIX) self.tabs.setMinimumSize(300, 150) self.tabs.setMaximumSize(300, 150) self.tab = QWidget() self.tab.setObjectName("tab") self.tabs.addTab(self.tab, "Actions") self.tab2 = QWidget() self.tab2.setObjectName("tab2") self.tabs.addTab(self.tab2, "My Media") self.tab3 = QWidget() self.tab3.setObjectName("tab3") self.tab3.setSizePolicy(*FIX_FIX) self.grid_layout2 = QGridLayout(self.tab3) self.grid_layout2.setHorizontalSpacing(0) self.grid_layout2.setVerticalSpacing(3) self.grid_layout2.setContentsMargins(3, -1, 3, -1) self.server_folder = QLineEdit(self.tab3) self.server_folder.setObjectName("server_folder") self.grid_layout2.addWidget(self.server_folder, 0, 0, 1, 3) self.srv_browse = QPushButton("BROWSE", self.tab3) self.srv_browse.setObjectName("srv_browse") self.srv_browse.setStyleSheet("background: transparent;\n" " color: #4d4940;\n" " font-size: 8pt;\n" " font-weight: 450;\n" " padding: 6px;\n") self.grid_layout2.addWidget(self.srv_browse, 0, 3, 1, 1) self.back_button = QPushButton("", self.tab3) self.back_button.setObjectName("back_button") self.back_button.setSizePolicy(*FIX_FIX) self.back_button.setMaximumSize(SEVENTY_FIVE) self.back_button.setCursor(QCursor(Qt.PointingHandCursor)) self.back_button.setStyleSheet("border: 0;\n" "background: transparent;") icon = QIcon() icon.addFile(":/newPrefix/back_button.png", SIXTY_FOUR, QIcon.Normal, QIcon.Off) self.back_button.setIcon(icon) self.back_button.setIconSize(SIXTY_FOUR) self.grid_layout2.addWidget(self.back_button, 1, 0, 1, 1) self.play_button = QPushButton("", self.tab3) self.play_button.setObjectName("play_button") self.play_button.setSizePolicy(*FIX_FIX) self.play_button.setMaximumSize(SEVENTY_FIVE) self.play_button.setCursor(QCursor(Qt.PointingHandCursor)) self.play_button.setStyleSheet("border: 0;\n" "background: transparent;") icon1 = QIcon() icon1.addFile(":/newPrefix/play_button.png", SIXTY_FOUR, QIcon.Normal, QIcon.Off) self.play_button.setIcon(icon1) self.play_button.setIconSize(SIXTY_FOUR) self.grid_layout2.addWidget(self.play_button, 1, 1, 1, 1) self.stop_button = QPushButton("", self.tab3) self.stop_button.setObjectName("stop_button") self.stop_button.setSizePolicy(*FIX_FIX) self.stop_button.setMaximumSize(SEVENTY_FIVE) self.stop_button.setCursor(QCursor(Qt.PointingHandCursor)) self.stop_button.setStyleSheet("border: 0;\n" "background: transparent;") icon2 = QIcon() icon2.addFile(":/newPrefix/stop_button.png", SIXTY_FOUR, QIcon.Normal, QIcon.Off) self.stop_button.setIcon(icon2) self.stop_button.setIconSize(SIXTY_FOUR) self.grid_layout2.addWidget(self.stop_button, 1, 2, 1, 1) self.fast_forward = QPushButton("", self.tab3) self.fast_forward.setObjectName("fast_forward") self.fast_forward.setSizePolicy(*FIX_FIX) self.fast_forward.setMaximumSize(SEVENTY_FIVE) self.fast_forward.setCursor(QCursor(Qt.PointingHandCursor)) self.fast_forward.setStyleSheet("border: 0;\n" "background: transparent;") icon3 = QIcon() icon3.addFile(":/newPrefix/fast_forward.png", SIXTY_FOUR, QIcon.Normal, QIcon.Off) self.fast_forward.setIcon(icon3) self.fast_forward.setIconSize(SIXTY_FOUR) self.grid_layout2.addWidget(self.fast_forward, 1, 3, 1, 1) self.tabs.addTab(self.tab3, "Server Media") self.grid_layout.addWidget(self.tabs, 4, 1, 1, 2) main_window.setCentralWidget(self.centralwidget) self.statusbar = QStatusBar(main_window) self.statusbar.setObjectName("statusbar") self.statusbar.setEnabled(True) self.statusbar.setStyleSheet("margin-bottom: 5px;") self.statusbar.setSizePolicy(*EXP_FIX) self.statusbar.setMinimumSize(INFINITE, 30) self.statusbar.setMaximumSize(INFINITE, 30) self.statusbar.setSizeGripEnabled(False) main_window.setStatusBar(self.statusbar) self.menubar.addAction(self.file_menu.menuAction()) self.menubar.addAction(self.server_menu.menuAction()) self.menubar.addAction(self.options_menu.menuAction()) self.menubar.addAction(self.media_menu.menuAction()) self.file_menu.addAction(self.exit) self.server_menu.addAction(self.start_server) self.server_menu.addAction(self.connect_server) self.server_menu.addAction(self.kill_server) self.options_menu.addAction(self.options) self.media_menu.addAction(self.start_webcam) self.exit.triggered.connect(main_window.close) self.tabs.setCurrentIndex(0) QMetaObject.connectSlotsByName(main_window) self.exit.setStatusTip("Exit the program.") self.start_server.setStatusTip("Initialize a local server instance.") self.connect_server.setStatusTip("Connect to a remote server.") self.kill_server.setStatusTip("Shut down a running local server.") self.options.setStatusTip("Open the options menu.") self.start_webcam.setStatusTip("Start webcam feed.") self.tooltip = QLabel("", self.statusbar) tooltip_policy = QSizePolicy(*EXP_FIX) tooltip_policy.setHorizontalStretch(100) self.tooltip.setSizePolicy(tooltip_policy) self.tooltip.setMinimumSize(INFINITE, 26) self.tooltip.setMaximumSize(INFINITE, 26) self.server_status = QLabel("Server status:", self.statusbar) self.server_status.setSizePolicy(*FIX_FIX) self.server_status.setMinimumSize(300, 26) self.server_status.setMaximumSize(300, 26) self.client_status = QLabel("Client status:", self.statusbar) self.client_status.setSizePolicy(*FIX_FIX) self.client_status.setMinimumSize(302, 26) self.client_status.setMaximumSize(302, 26) self.statusbar.addPermanentWidget(self.tooltip) self.statusbar.addPermanentWidget(self.server_status) self.statusbar.addPermanentWidget(self.client_status) self.tooltip.setStyleSheet(SUNKEN + "margin-left: 4px;\ margin-right: 0px;") self.client_status.setStyleSheet(SUNKEN + "margin-right: 7px;") self.server_status.setStyleSheet(SUNKEN + "margin-right: 2px;\ margin-left: 2px;") self.statusbar.messageChanged.connect(main_window.status_tip)
class UIDeleteROIWindow(): def setup_ui(self, delete_roi_window_instance, regions_of_interest, dataset_rtss, deleting_rois_structure_tuple): # Initialise the 2 lists for containing the ROI(s) that we are going to keep and delete respectively self.regions_of_interest_to_keep = [] self.regions_of_interest_to_delete = [] # This is for holding the original list of ROI(s) self.regions_of_interest_list = regions_of_interest # This is for holding the DICOM dataset of that specific patient self.dataset_rtss = dataset_rtss # Assigning new tuple for holding the deleting ROI(s) self.deleting_rois_structure_tuple = deleting_rois_structure_tuple # Initialise a DeleteROIWindow if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" stylesheet = open(resource_path(self.stylesheet_path)).read() window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) delete_roi_window_instance.setObjectName("DeleteRoiWindowInstance") delete_roi_window_instance.setWindowIcon(window_icon) delete_roi_window_instance.resize(800, 606) # Create a vertical box to hold all widgets self.delete_roi_window_instance_vertical_box = QVBoxLayout() self.delete_roi_window_instance_vertical_box.setObjectName( "DeleteRoiWindowInstanceVerticalBox") # Create a label for holding the window's title self.delete_roi_window_title = QLabel() self.delete_roi_window_title.setObjectName("DeleteRoiWindowTitle") self.delete_roi_window_title.setProperty("QLabelClass", "window-title") self.delete_roi_window_title.setAlignment(Qt.AlignLeft) self.delete_roi_window_instance_vertical_box.addWidget( self.delete_roi_window_title) # Create a label for holding the instruction of how to delete the ROIs self.delete_roi_window_instruction = QLabel() self.delete_roi_window_instruction.setObjectName( "DeleteRoiWindowInstruction") self.delete_roi_window_instruction.setAlignment(Qt.AlignCenter) self.delete_roi_window_instance_vertical_box.addWidget( self.delete_roi_window_instruction) # Create a horizontal box for holding the 2 lists and the move left, move right buttons self.delete_roi_window_keep_and_delete_box = QHBoxLayout() self.delete_roi_window_keep_and_delete_box.setObjectName( "DeleteRoiWindowKeepAndDeleteBox") # ================================= KEEP BOX ================================= # Create a vertical box for holding the label and the tree view for holding the ROIs that we are keeping self.delete_roi_window_keep_vertical_box = QVBoxLayout() self.delete_roi_window_keep_vertical_box.setObjectName( "DeleteRoiWindowKeepVerticalBox") # Create a label for the tree view with the list of ROIs to keep self.delete_roi_window_keep_tree_view_label = QLabel() self.delete_roi_window_keep_tree_view_label.setObjectName( "DeleteRoiWindowKeepTreeViewLabel") self.delete_roi_window_keep_tree_view_label.setProperty( "QLabelClass", ["tree-view-label", "tree-view-label-keep-delete"]) self.delete_roi_window_keep_tree_view_label.setAlignment( Qt.AlignCenter) self.delete_roi_window_keep_tree_view_label.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_keep_tree_view_label.resize( self.delete_roi_window_keep_tree_view_label.sizeHint().width(), self.delete_roi_window_keep_tree_view_label.sizeHint().height()) self.delete_roi_window_keep_vertical_box.addWidget( self.delete_roi_window_keep_tree_view_label) # Create a tree view for containing the list of ROIs to keep self.delete_roi_window_keep_tree_view = QTreeWidget() self.delete_roi_window_keep_tree_view.setObjectName( "DeleteRoiWindowKeepTreeView") self.delete_roi_window_keep_tree_view.setHeaderHidden(True) self.delete_roi_window_keep_tree_view.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_keep_tree_view.resize( self.delete_roi_window_keep_tree_view.sizeHint().width(), self.delete_roi_window_keep_tree_view.sizeHint().height()) self.delete_roi_window_keep_vertical_box.addWidget( self.delete_roi_window_keep_tree_view) self.delete_roi_window_keep_vertical_box.setStretch(1, 4) # Create a widget to hold the keep vertical box self.delete_roi_window_keep_widget = QWidget() self.delete_roi_window_keep_widget.setObjectName( "DeleteRoiWindowKeepWidget") self.delete_roi_window_keep_widget.setLayout( self.delete_roi_window_keep_vertical_box) self.delete_roi_window_keep_and_delete_box.addStretch(1) self.delete_roi_window_keep_and_delete_box.addWidget( self.delete_roi_window_keep_widget) # ================================= KEEP BOX ================================= # ================================= MOVE LEFT/RIGHT BOX ================================= # Create a vertical box for holding the 2 buttons for moving left and right self.delete_roi_window_move_left_right_vertical_box = QVBoxLayout() self.delete_roi_window_move_left_right_vertical_box.setObjectName( "DeleteRoiWindowMoveLeftRightVerticalBox") # Create Move Right Button / Delete Button self.move_right_button = QPushButton() self.move_right_button.setObjectName("MoveRightButton") self.move_right_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.move_right_button.resize( self.move_right_button.sizeHint().width(), self.move_right_button.sizeHint().height()) self.move_right_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.move_right_button.clicked.connect( self.move_right_button_onClicked) self.move_right_button.setProperty("QPushButtonClass", "fail-button") self.delete_roi_window_move_left_right_vertical_box.addStretch(1) self.delete_roi_window_move_left_right_vertical_box.addWidget( self.move_right_button) # Create Move Left Button / Keep Button self.move_left_button = QPushButton() self.move_left_button.setObjectName("MoveLeftButton") self.move_left_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.move_left_button.resize(self.move_left_button.sizeHint().width(), self.move_left_button.sizeHint().height()) self.move_left_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.move_left_button.clicked.connect(self.move_left_button_onClicked) self.move_left_button.setProperty("QPushButtonClass", "success-button") self.delete_roi_window_move_left_right_vertical_box.addWidget( self.move_left_button) self.delete_roi_window_move_left_right_vertical_box.addStretch(1) # Create a widget for holding the 2 buttons self.delete_roi_window_move_left_right_widget = QWidget() self.delete_roi_window_move_left_right_widget.setObjectName( "DeleteRoiWindowMoveLeftRightWidget") self.delete_roi_window_move_left_right_widget.setLayout( self.delete_roi_window_move_left_right_vertical_box) self.delete_roi_window_keep_and_delete_box.addWidget( self.delete_roi_window_move_left_right_widget) # ================================= MOVE LEFT/RIGHT BOX ================================= # ================================= DELETE BOX ================================= # Create a vertical box for holding the label and the tree view for holding the ROIs that we are deleting self.delete_roi_window_delete_vertical_box = QVBoxLayout() self.delete_roi_window_delete_vertical_box.setObjectName( "DeleteRoiWindowDeleteVerticalBox") # Create a label for the tree view with the list of ROIs to delete self.delete_roi_window_delete_tree_view_label = QLabel() self.delete_roi_window_delete_tree_view_label.setObjectName( "DeleteRoiWindowDeleteTreeViewLabel") self.delete_roi_window_delete_tree_view_label.setProperty( "QLabelClass", ["tree-view-label", "tree-view-label-keep-delete"]) self.delete_roi_window_delete_tree_view_label.setAlignment( Qt.AlignCenter) self.delete_roi_window_delete_tree_view_label.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_delete_tree_view_label.resize( self.delete_roi_window_delete_tree_view_label.sizeHint().width(), self.delete_roi_window_delete_tree_view_label.sizeHint().height()) self.delete_roi_window_delete_vertical_box.addWidget( self.delete_roi_window_delete_tree_view_label) # Create a tree view for containing the list of ROIs to delete self.delete_roi_window_delete_tree_view = QTreeWidget() self.delete_roi_window_delete_tree_view.setObjectName( "DeleteRoiWindowDeleteTreeView") self.delete_roi_window_delete_tree_view.setHeaderHidden(True) self.delete_roi_window_delete_tree_view.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_delete_tree_view.resize( self.delete_roi_window_delete_tree_view.sizeHint().width(), self.delete_roi_window_delete_tree_view.sizeHint().height()) self.delete_roi_window_delete_vertical_box.addWidget( self.delete_roi_window_delete_tree_view) self.delete_roi_window_delete_vertical_box.setStretch(1, 4) # Create a widget to hold the delete vertical box self.delete_roi_window_delete_widget = QWidget() self.delete_roi_window_delete_widget.setObjectName( "DeleteRoiWindowDeleteWidget") self.delete_roi_window_delete_widget.setLayout( self.delete_roi_window_delete_vertical_box) self.delete_roi_window_keep_and_delete_box.addWidget( self.delete_roi_window_delete_widget) self.delete_roi_window_keep_and_delete_box.addStretch(1) self.delete_roi_window_keep_and_delete_box.setStretch(1, 4) self.delete_roi_window_keep_and_delete_box.setStretch(3, 4) # ================================= DELETE BOX ================================= # Create a widget to hold the keep and delete box self.delete_roi_window_keep_and_delete_widget = QWidget() self.delete_roi_window_keep_and_delete_widget.setObjectName( "DeleteRoiWindowKeepAndDeleteWidget") self.delete_roi_window_keep_and_delete_widget.setLayout( self.delete_roi_window_keep_and_delete_box) self.delete_roi_window_instance_vertical_box.addWidget( self.delete_roi_window_keep_and_delete_widget) # Create a horizontal box to hold 2 action buttons for this window self.delete_roi_window_action_buttons_box = QHBoxLayout() self.delete_roi_window_action_buttons_box.setObjectName( "DeleteRoiWindowActionButtonsBox") # Create the cancel button self.delete_roi_window_cancel_button = QPushButton() self.delete_roi_window_cancel_button.setObjectName( "DeleteRoiWindowCancelButton") self.delete_roi_window_cancel_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_cancel_button.resize( self.delete_roi_window_cancel_button.sizeHint().width(), self.delete_roi_window_cancel_button.sizeHint().height()) self.delete_roi_window_cancel_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.delete_roi_window_cancel_button.clicked.connect( self.on_cancel_button_clicked) self.delete_roi_window_cancel_button.setProperty( "QPushButtonClass", "fail-button") self.delete_roi_window_action_buttons_box.addStretch(1) self.delete_roi_window_action_buttons_box.addWidget( self.delete_roi_window_cancel_button) # Create the confirm button self.delete_roi_window_confirm_button = QPushButton() self.delete_roi_window_confirm_button.setObjectName( "DeleteRoiWindowConfirmButton") self.delete_roi_window_confirm_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.delete_roi_window_confirm_button.resize( self.delete_roi_window_confirm_button.sizeHint().width(), self.delete_roi_window_confirm_button.sizeHint().height()) self.delete_roi_window_confirm_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.delete_roi_window_confirm_button.clicked.connect( self.confirm_button_onClicked) self.delete_roi_window_confirm_button.setEnabled(False) self.delete_roi_window_confirm_button.setProperty( "QPushButtonClass", "success-button") self.delete_roi_window_action_buttons_box.addWidget( self.delete_roi_window_confirm_button) # Create a widget to hold the action buttons self.delete_roi_window_action_buttons_widget = QWidget() self.delete_roi_window_action_buttons_widget.setObjectName( "DeleteRoiWindowActionButtonsWidget") self.delete_roi_window_action_buttons_widget.setLayout( self.delete_roi_window_action_buttons_box) self.delete_roi_window_instance_vertical_box.addWidget( self.delete_roi_window_action_buttons_widget) # Set text for all attributes self.retranslate_ui(delete_roi_window_instance) # Create a central widget to hold the vertical layout box self.delete_roi_window_instance_central_widget = QWidget() self.delete_roi_window_instance_central_widget.setObjectName( "DeleteRoiWindowInstanceCentralWidget") self.delete_roi_window_instance_central_widget.setLayout( self.delete_roi_window_instance_vertical_box) self.delete_roi_window_instance_vertical_box.setStretch(2, 4) # Set the central widget for the main window and style the window delete_roi_window_instance.setCentralWidget( self.delete_roi_window_instance_central_widget) delete_roi_window_instance.setStyleSheet(stylesheet) # Load the ROIs in self.display_rois_in_listViewKeep() # Set the selection mode to multi so that we can select multiple ROIs to delete self.delete_roi_window_keep_tree_view.setSelectionMode( QAbstractItemView.MultiSelection) self.delete_roi_window_delete_tree_view.setSelectionMode( QAbstractItemView.MultiSelection) QtCore.QMetaObject.connectSlotsByName(delete_roi_window_instance) def retranslate_ui(self, delete_roi_window_instance): _translate = QtCore.QCoreApplication.translate delete_roi_window_instance.setWindowTitle( _translate("DeleteRoiWindowInstance", "OnkoDICOM - Delete ROI(s)")) self.delete_roi_window_title.setText( _translate("DeleteRoiWindowTitle", "Delete ROI(s)")) self.delete_roi_window_instruction.setText( _translate( "DeleteRoiWindowInstruction", "Move the Regions of Interest to be deleted to the right-hand side or vice versa" )) self.delete_roi_window_keep_tree_view_label.setText( _translate("DeleteRoiWindowKeepTreeViewLabel", "To Keep")) self.delete_roi_window_delete_tree_view_label.setText( _translate("DeleteRoiWindowDeleteTreeViewLabel", "To Delete")) self.move_right_button.setText( _translate("MoveRightButton", "Move Right ->>>")) self.move_left_button.setText( _translate("MoveLeftButton", "<<<- Move Left")) self.delete_roi_window_cancel_button.setText( _translate("DeleteRoiWindowCancelButton", "Cancel")) self.delete_roi_window_confirm_button.setText( _translate("DeleteRoiWindowConfirmButton", "Confirm")) def on_cancel_button_clicked(self): self.close() def display_rois_in_listViewKeep(self): self.regions_of_interest_to_keep.clear() for roi_id, roi_dict in self.regions_of_interest_list.items(): self.regions_of_interest_to_keep.append(roi_dict['name']) self.delete_roi_window_keep_tree_view.clear() self.delete_roi_window_keep_tree_view.setIndentation(0) self.item = QTreeWidgetItem(["item"]) for index in self.regions_of_interest_to_keep: item = QTreeWidgetItem([index]) self.delete_roi_window_keep_tree_view.addTopLevelItem(item) def move_right_button_onClicked(self): root_item = self.delete_roi_window_keep_tree_view.invisibleRootItem() for index in range(root_item.childCount()): item = root_item.child(index) if item in self.delete_roi_window_keep_tree_view.selectedItems(): # This will get ROI name self.regions_of_interest_to_delete.append(item.text(0)) # Move to the right column list self.delete_roi_window_delete_tree_view.clear() self.delete_roi_window_delete_tree_view.setIndentation(0) for roi in self.regions_of_interest_to_delete: item = QTreeWidgetItem([roi]) self.delete_roi_window_delete_tree_view.addTopLevelItem(item) self.delete_roi_window_confirm_button.setEnabled(True) # Delete moved items from the left column list self.regions_of_interest_to_keep = [ x for x in self.regions_of_interest_to_keep if x not in self.regions_of_interest_to_delete ] self.delete_roi_window_keep_tree_view.clear() for index in self.regions_of_interest_to_keep: item = QTreeWidgetItem([index]) self.delete_roi_window_keep_tree_view.addTopLevelItem(item) def move_left_button_onClicked(self): root_item = self.delete_roi_window_delete_tree_view.invisibleRootItem() for index in range(root_item.childCount()): item = root_item.child(index) if item in self.delete_roi_window_delete_tree_view.selectedItems(): # This will get ROI name self.regions_of_interest_to_keep.append(item.text(0)) # Move to the left column list self.delete_roi_window_keep_tree_view.clear() self.delete_roi_window_keep_tree_view.setIndentation(0) for roi in self.regions_of_interest_to_keep: item = QTreeWidgetItem([roi]) self.delete_roi_window_keep_tree_view.addTopLevelItem(item) # Delete moved items from the right column list self.regions_of_interest_to_delete = [ x for x in self.regions_of_interest_to_delete if x not in self.regions_of_interest_to_keep ] self.delete_roi_window_delete_tree_view.clear() for index in self.regions_of_interest_to_delete: item = QTreeWidgetItem([index]) self.delete_roi_window_delete_tree_view.addTopLevelItem(item) if len(self.regions_of_interest_to_delete) == 0: self.delete_roi_window_confirm_button.setEnabled(False) def confirm_button_onClicked(self): confirmation_dialog = QMessageBox.information( self, 'Delete ROI(s)?', 'Region(s) of Interest in the To Delete table will be deleted. ' 'Would you like to continue?', QMessageBox.Yes | QMessageBox.No) if confirmation_dialog == QMessageBox.Yes: progress_window = DeleteROIProgressWindow( self, QtCore.Qt.WindowTitleHint) progress_window.signal_roi_deleted.connect(self.on_rois_deleted) progress_window.start_deleting(self.dataset_rtss, self.regions_of_interest_to_delete) progress_window.show() def on_rois_deleted(self, new_rtss): self.deleting_rois_structure_tuple.emit((new_rtss, { "delete": self.regions_of_interest_to_delete })) QMessageBox.about(self, "Saved", "Regions of interest successfully deleted!") self.close()
class UIOpenPatientWindow(object): patient_info_initialized = QtCore.Signal(object) def setup_ui(self, open_patient_window_instance): if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) open_patient_window_instance.setObjectName("OpenPatientWindowInstance") open_patient_window_instance.setWindowIcon(window_icon) open_patient_window_instance.resize(840, 530) # Create a vertical box for containing the other elements and layouts self.open_patient_window_instance_vertical_box = QVBoxLayout() self.open_patient_window_instance_vertical_box.setObjectName( "OpenPatientWindowInstanceVerticalBox") # Create a label to prompt the user to enter the path to the directory that contains the DICOM files self.open_patient_directory_prompt = QLabel() self.open_patient_directory_prompt.setObjectName( "OpenPatientDirectoryPrompt") self.open_patient_directory_prompt.setAlignment(Qt.AlignLeft) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_prompt) # Create a horizontal box to hold the input box for the directory and the choose button self.open_patient_directory_input_horizontal_box = QHBoxLayout() self.open_patient_directory_input_horizontal_box.setObjectName( "OpenPatientDirectoryInputHorizontalBox") # Create a textbox to contain the path to the directory that contains the DICOM files self.open_patient_directory_input_box = UIOpenPatientWindowDragAndDropEvent( self) self.open_patient_directory_input_box.setObjectName( "OpenPatientDirectoryInputBox") self.open_patient_directory_input_box.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_directory_input_box.returnPressed.connect( self.scan_directory_for_patient) self.open_patient_directory_input_horizontal_box.addWidget( self.open_patient_directory_input_box) # Create a choose button to open the file dialog self.open_patient_directory_choose_button = QPushButton() self.open_patient_directory_choose_button.setObjectName( "OpenPatientDirectoryChooseButton") self.open_patient_directory_choose_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_directory_choose_button.resize( self.open_patient_directory_choose_button.sizeHint().width(), self.open_patient_directory_input_box.height()) self.open_patient_directory_choose_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_directory_input_horizontal_box.addWidget( self.open_patient_directory_choose_button) self.open_patient_directory_choose_button.clicked.connect( self.choose_button_clicked) # Create a widget to hold the input fields self.open_patient_directory_input_widget = QWidget() self.open_patient_directory_input_horizontal_box.setStretch(0, 4) self.open_patient_directory_input_widget.setLayout( self.open_patient_directory_input_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_input_widget) # Create a horizontal box to hold the stop button and direction to the user on where to select the patient self.open_patient_appear_prompt_and_stop_horizontal_box = QHBoxLayout() self.open_patient_appear_prompt_and_stop_horizontal_box.setObjectName( "OpenPatientAppearPromptAndStopHorizontalBox") # Create a label to show direction on where the files will appear self.open_patient_directory_appear_prompt = QLabel() self.open_patient_directory_appear_prompt.setObjectName( "OpenPatientDirectoryAppearPrompt") self.open_patient_directory_appear_prompt.setAlignment(Qt.AlignLeft) self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget( self.open_patient_directory_appear_prompt) self.open_patient_appear_prompt_and_stop_horizontal_box.addStretch(1) # Create a button to stop searching self.open_patient_window_stop_button = QPushButton() self.open_patient_window_stop_button.setObjectName( "OpenPatientWindowStopButton") self.open_patient_window_stop_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_stop_button.resize( self.open_patient_window_stop_button.sizeHint().width(), self.open_patient_window_stop_button.sizeHint().height()) self.open_patient_window_stop_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_stop_button.clicked.connect( self.stop_button_clicked) self.open_patient_window_stop_button.setProperty( "QPushButtonClass", "fail-button") self.open_patient_window_stop_button.setVisible( False) # Button doesn't show until a search commences self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget( self.open_patient_window_stop_button) # Create a widget to hold the layout self.open_patient_appear_prompt_and_stop_widget = QWidget() self.open_patient_appear_prompt_and_stop_widget.setLayout( self.open_patient_appear_prompt_and_stop_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_appear_prompt_and_stop_widget) # Create a tree view list to list out all patients in the directory selected above self.open_patient_window_patients_tree = QTreeWidget() self.open_patient_window_patients_tree.setObjectName( "OpenPatientWindowPatientsTree") self.open_patient_window_patients_tree.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_patients_tree.resize( self.open_patient_window_patients_tree.sizeHint().width(), self.open_patient_window_patients_tree.sizeHint().height()) self.open_patient_window_patients_tree.setHeaderHidden(False) self.open_patient_window_patients_tree.setHeaderLabels([""]) self.open_patient_window_patients_tree.itemChanged.connect( self.tree_item_changed) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_window_patients_tree) self.last_patient = None # Create a label to show what would happen if they select the patient self.open_patient_directory_result_label = QtWidgets.QLabel() self.open_patient_directory_result_label.setObjectName( "OpenPatientDirectoryResultLabel") self.open_patient_directory_result_label.setAlignment(Qt.AlignLeft) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_result_label) # Create a horizontal box to hold the Cancel and Open button self.open_patient_window_patient_open_actions_horizontal_box = QHBoxLayout( ) self.open_patient_window_patient_open_actions_horizontal_box.setObjectName( "OpenPatientWindowPatientOpenActionsHorizontalBox") self.open_patient_window_patient_open_actions_horizontal_box.addStretch( 1) # Add a button to go back/exit from the application self.open_patient_window_exit_button = QPushButton() self.open_patient_window_exit_button.setObjectName( "OpenPatientWindowExitButton") self.open_patient_window_exit_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_exit_button.resize( self.open_patient_window_stop_button.sizeHint().width(), self.open_patient_window_stop_button.sizeHint().height()) self.open_patient_window_exit_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_exit_button.clicked.connect( self.exit_button_clicked) self.open_patient_window_exit_button.setProperty( "QPushButtonClass", "fail-button") self.open_patient_window_patient_open_actions_horizontal_box.addWidget( self.open_patient_window_exit_button) # Add a button to confirm opening of the patient self.open_patient_window_confirm_button = QPushButton() self.open_patient_window_confirm_button.setObjectName( "OpenPatientWindowConfirmButton") self.open_patient_window_confirm_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_confirm_button.resize( self.open_patient_window_confirm_button.sizeHint().width(), self.open_patient_window_confirm_button.sizeHint().height()) self.open_patient_window_confirm_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_confirm_button.setDisabled(True) self.open_patient_window_confirm_button.clicked.connect( self.confirm_button_clicked) self.open_patient_window_confirm_button.setProperty( "QPushButtonClass", "success-button") self.open_patient_window_patient_open_actions_horizontal_box.addWidget( self.open_patient_window_confirm_button) # Create a widget to house all of the actions button for open patient window self.open_patient_window_patient_open_actions_widget = QWidget() self.open_patient_window_patient_open_actions_widget.setLayout( self.open_patient_window_patient_open_actions_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_window_patient_open_actions_widget) # Set the vertical box fourth element, the tree view, to stretch out as far as possible self.open_patient_window_instance_vertical_box.setStretch( 3, 4) # Stretch the treeview out as far as possible self.open_patient_window_instance_central_widget = QWidget() self.open_patient_window_instance_central_widget.setObjectName( "OpenPatientWindowInstanceCentralWidget") self.open_patient_window_instance_central_widget.setLayout( self.open_patient_window_instance_vertical_box) # Create threadpool for multithreading self.threadpool = QThreadPool() print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) # Create interrupt event for stopping the directory search self.interrupt_flag = threading.Event() # Bind all texts into the buttons and labels self.retranslate_ui(open_patient_window_instance) # Set the central widget, ready for display open_patient_window_instance.setCentralWidget( self.open_patient_window_instance_central_widget) # Set the current stylesheet to the instance and connect it back to the caller through slot _stylesheet = open(resource_path(self.stylesheet_path)).read() open_patient_window_instance.setStyleSheet(_stylesheet) QtCore.QMetaObject.connectSlotsByName(open_patient_window_instance) def retranslate_ui(self, open_patient_window_instance): _translate = QtCore.QCoreApplication.translate open_patient_window_instance.setWindowTitle( _translate("OpenPatientWindowInstance", "OnkoDICOM - Select Patient")) self.open_patient_directory_prompt.setText( _translate( "OpenPatientWindowInstance", "Choose the path of the folder containing DICOM files to load Patient's details:" )) self.open_patient_directory_input_box.setPlaceholderText( _translate( "OpenPatientWindowInstance", "Enter DICOM Files Path (For example, C:\path\\to\your\DICOM\Files)" )) self.open_patient_directory_choose_button.setText( _translate("OpenPatientWindowInstance", "Choose")) self.open_patient_directory_appear_prompt.setText( _translate( "OpenPatientWindowInstance", "Patient File directory shown below once file path chosen. Please select the file(s) you want to open:" )) self.open_patient_directory_result_label.setText( "The selected directory(s) above will be opened in the OnkoDICOM program." ) self.open_patient_window_stop_button.setText( _translate("OpenPatientWindowInstance", "Stop Search")) self.open_patient_window_exit_button.setText( _translate("OpenPatientWindowInstance", "Exit")) self.open_patient_window_confirm_button.setText( _translate("OpenPatientWindowInstance", "Confirm")) def exit_button_clicked(self): QCoreApplication.exit(0) def scan_directory_for_patient(self): # Reset tree view header and last patient self.open_patient_window_patients_tree.setHeaderLabels([""]) self.last_patient = None self.filepath = self.open_patient_directory_input_box.text() # Proceed if a folder was selected if self.filepath != "": # Update the QTreeWidget to reflect data being loaded # First, clear the widget of any existing data self.open_patient_window_patients_tree.clear() # Next, update the tree widget self.open_patient_window_patients_tree.addTopLevelItem( QTreeWidgetItem(["Loading selected directory..."])) # The choose button is disabled until the thread finishes executing self.open_patient_directory_choose_button.setEnabled(False) # Reveals the Stop Search button for the duration of the search self.open_patient_window_stop_button.setVisible(True) # The interrupt flag is then un-set if a previous search has been stopped. self.interrupt_flag.clear() # Then, create a new thread that will load the selected folder worker = Worker(DICOMDirectorySearch.get_dicom_structure, self.filepath, self.interrupt_flag, progress_callback=True) worker.signals.result.connect(self.on_search_complete) worker.signals.progress.connect(self.search_progress) # Execute the thread self.threadpool.start(worker) def choose_button_clicked(self): """ Executes when the choose button is clicked. Gets filepath from the user and loads all files and subdirectories. """ # Get folder path from pop up dialog box self.filepath = QtWidgets.QFileDialog.getExistingDirectory( None, 'Select patient folder...', '') self.open_patient_directory_input_box.setText(self.filepath) self.scan_directory_for_patient() def stop_button_clicked(self): self.interrupt_flag.set() def search_progress(self, progress_update): """ Current progress of the file search. """ self.open_patient_window_patients_tree.clear() self.open_patient_window_patients_tree.addTopLevelItem( QTreeWidgetItem([ "Loading selected directory... (%s files searched)" % progress_update ])) def on_search_complete(self, dicom_structure): """ Executes once the directory search is complete. :param dicom_structure: DICOMStructure object constructed by the directory search. """ self.open_patient_directory_choose_button.setEnabled(True) self.open_patient_window_stop_button.setVisible(False) self.open_patient_window_patients_tree.clear() if dicom_structure is None: # dicom_structure will be None if function was interrupted. return for patient_item in dicom_structure.get_tree_items_list(): self.open_patient_window_patients_tree.addTopLevelItem( patient_item) if len(dicom_structure.patients) == 0: QMessageBox.about(self, "No files found", "Selected directory contains no DICOM files.") def tree_item_changed(self, item, _): """ Executes when a tree item is checked or unchecked. If a different patient is checked, uncheck the previous patient. Inform user about missing DICOM files. """ selected_patient = item # If the item is not top-level, bubble up to see which top-level item this item belongs to if self.open_patient_window_patients_tree.invisibleRootItem( ).indexOfChild(item) == -1: while self.open_patient_window_patients_tree.invisibleRootItem( ).indexOfChild(selected_patient) == -1: selected_patient = selected_patient.parent() # Uncheck previous patient if a different patient is selected if item.checkState( 0 ) == Qt.CheckState.Checked and self.last_patient != selected_patient: if self.last_patient is not None: self.last_patient.setCheckState(0, Qt.CheckState.Unchecked) self.last_patient.setSelected(False) self.last_patient = selected_patient # Get the types of all selected leaves self.selected_series_types = set() for checked_item in self.get_checked_leaves(): series_type = checked_item.dicom_object.get_series_type() if type(series_type) == str: self.selected_series_types.add(series_type) else: self.selected_series_types.update(series_type) # Check the existence of IMAGE, RTSTRUCT and RTDOSE files if len(list({'CT', 'MR', 'PT'} & self.selected_series_types)) == 0: header = "Cannot proceed without an image file." self.open_patient_window_confirm_button.setDisabled(True) elif 'RTSTRUCT' not in self.selected_series_types: header = "DVH and Radiomics calculations are not available without a RTSTRUCT file." elif 'RTDOSE' not in self.selected_series_types: header = "DVH calculations are not available without a RTDOSE file." else: header = "" self.open_patient_window_patients_tree.setHeaderLabel(header) if len(list({'CT', 'MR', 'PT'} & self.selected_series_types)) != 0: self.open_patient_window_confirm_button.setDisabled(False) def confirm_button_clicked(self): """ Begins loading of the selected files. """ selected_files = [] for item in self.get_checked_leaves(): selected_files += item.dicom_object.get_files() self.progress_window = ProgressWindow( self, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint) self.progress_window.signal_loaded.connect(self.on_loaded) self.progress_window.signal_error.connect(self.on_loading_error) self.progress_window.start_loading(selected_files) self.progress_window.exec_() def on_loaded(self, results): """ Executes when the progress bar finishes loaded the selected files. """ if results[0] is True: # Will be NoneType if loading was interrupted. self.patient_info_initialized.emit( results[1]) # Emits the progress window. def on_loading_error(self, error_code): """ Error handling for progress window. """ if error_code == 0: QMessageBox.about( self.progress_window, "Unable to open selection", "Selected files cannot be opened as they are not a DICOM-RT set." ) self.progress_window.close() elif error_code == 1: QMessageBox.about( self.progress_window, "Unable to open selection", "Selected files cannot be opened as they contain unsupported DICOM classes." ) self.progress_window.close() def get_checked_leaves(self): """ :return: A list of all QTreeWidgetItems in the QTreeWidget that are both leaves and checked. """ checked_items = [] def recurse(parent_item: QTreeWidgetItem): for i in range(parent_item.childCount()): child = parent_item.child(i) grand_children = child.childCount() if grand_children > 0: recurse(child) else: if child.checkState(0) == Qt.Checked: checked_items.append(child) recurse(self.open_patient_window_patients_tree.invisibleRootItem()) return checked_items
class UIImageFusionWindow(object): image_fusion_info_initialized = QtCore.Signal(object) def setup_ui(self, open_image_fusion_select_instance): """Sets up a UI""" if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) open_image_fusion_select_instance.setObjectName( "OpenPatientWindowInstance") open_image_fusion_select_instance.setWindowIcon(window_icon) open_image_fusion_select_instance.resize(840, 530) # Create a vertical box for containing the other elements and layouts self.open_patient_window_instance_vertical_box = QVBoxLayout() self.open_patient_window_instance_vertical_box.setObjectName( "OpenPatientWindowInstanceVerticalBox") # Create a label to prompt the user to enter the path to the # directory that contains the DICOM files self.open_patient_directory_prompt = QLabel() self.open_patient_directory_prompt.setObjectName( "OpenPatientDirectoryPrompt") self.open_patient_directory_prompt.setAlignment(Qt.AlignLeft) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_prompt) # Create a horizontal box to hold the input box for the directory # and the choose button self.open_patient_directory_input_horizontal_box = QHBoxLayout() self.open_patient_directory_input_horizontal_box.setObjectName( "OpenPatientDirectoryInputHorizontalBox") # Create a textbox to contain the path to the directory that contains # the DICOM files self.open_patient_directory_input_box = \ UIImageFusionWindowDragAndDropEvent(self) self.open_patient_directory_input_box.setObjectName( "OpenPatientDirectoryInputBox") self.open_patient_directory_input_box.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_directory_input_box.returnPressed.connect( self.scan_directory_for_patient) self.open_patient_directory_input_horizontal_box.addWidget( self.open_patient_directory_input_box) # Create a choose button to open the file dialog self.open_patient_directory_choose_button = QPushButton() self.open_patient_directory_choose_button.setObjectName( "OpenPatientDirectoryChooseButton") self.open_patient_directory_choose_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_directory_choose_button.resize( self.open_patient_directory_choose_button.sizeHint().width(), self.open_patient_directory_input_box.height()) self.open_patient_directory_choose_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_directory_input_horizontal_box.addWidget( self.open_patient_directory_choose_button) self.open_patient_directory_choose_button.clicked.connect( self.choose_button_clicked) # Create a widget to hold the input fields self.open_patient_directory_input_widget = QWidget() self.open_patient_directory_input_horizontal_box.setStretch(0, 4) self.open_patient_directory_input_widget.setLayout( self.open_patient_directory_input_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_input_widget) # Create a horizontal box to hold the stop button and direction to # the user on where to select the patient self.open_patient_appear_prompt_and_stop_horizontal_box = QHBoxLayout() self.open_patient_appear_prompt_and_stop_horizontal_box.setObjectName( "OpenPatientAppearPromptAndStopHorizontalBox") # Create a label to show direction on where the files will appear self.open_patient_directory_appear_prompt = QLabel() self.open_patient_directory_appear_prompt.setObjectName( "OpenPatientDirectoryAppearPrompt") self.open_patient_directory_appear_prompt.setAlignment(Qt.AlignLeft) self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget( self.open_patient_directory_appear_prompt) self.open_patient_appear_prompt_and_stop_horizontal_box.addStretch(1) # Create a button to stop searching self.open_patient_window_stop_button = QPushButton() self.open_patient_window_stop_button.setObjectName( "OpenPatientWindowStopButton") self.open_patient_window_stop_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_stop_button.resize( self.open_patient_window_stop_button.sizeHint().width(), self.open_patient_window_stop_button.sizeHint().height()) self.open_patient_window_stop_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_stop_button.clicked.connect( self.stop_button_clicked) self.open_patient_window_stop_button.setProperty( "QPushButtonClass", "fail-button") self.open_patient_window_stop_button.setVisible(False) self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget( self.open_patient_window_stop_button) # Create a widget to hold the layout self.open_patient_appear_prompt_and_stop_widget = QWidget() self.open_patient_appear_prompt_and_stop_widget.setLayout( self.open_patient_appear_prompt_and_stop_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_appear_prompt_and_stop_widget) # Create a tree view list to list out all patients in the directory # selected above self.open_patient_window_patients_tree = QTreeWidget() self.open_patient_window_patients_tree.setObjectName( "OpenPatientWindowPatientsTree") self.open_patient_window_patients_tree.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_patients_tree.resize( self.open_patient_window_patients_tree.sizeHint().width(), self.open_patient_window_patients_tree.sizeHint().height()) self.open_patient_window_patients_tree.setHeaderHidden(False) self.open_patient_window_patients_tree.setHeaderLabels([""]) self.open_patient_window_patients_tree.itemChanged.connect( self.tree_item_clicked) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_window_patients_tree) self.last_patient = None # Create a label to show what would happen if they select the patient self.open_patient_directory_result_label = QtWidgets.QLabel() self.open_patient_directory_result_label.setObjectName( "OpenPatientDirectoryResultLabel") self.open_patient_directory_result_label.setAlignment(Qt.AlignLeft) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_directory_result_label) # Create a horizontal box to hold the Cancel and Open button self.open_patient_window_patient_open_actions_horizontal_box = \ QHBoxLayout() self.open_patient_window_patient_open_actions_horizontal_box. \ setObjectName("OpenPatientWindowPatientOpenActionsHorizontalBox") self.open_patient_window_patient_open_actions_horizontal_box. \ addStretch(1) # Add a button to go back/close from the application self.open_patient_window_close_button = QPushButton() self.open_patient_window_close_button.setObjectName( "OpenPatientWindowcloseButton") self.open_patient_window_close_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_close_button.resize( self.open_patient_window_stop_button.sizeHint().width(), self.open_patient_window_stop_button.sizeHint().height()) self.open_patient_window_close_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_close_button.clicked.connect( self.close_button_clicked) self.open_patient_window_close_button.setProperty( "QPushButtonClass", "fail-button") self.open_patient_window_patient_open_actions_horizontal_box. \ addWidget(self.open_patient_window_close_button) # Add a button to confirm opening of the patient self.open_patient_window_confirm_button = QPushButton() self.open_patient_window_confirm_button.setObjectName( "OpenPatientWindowConfirmButton") self.open_patient_window_confirm_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.open_patient_window_confirm_button.resize( self.open_patient_window_confirm_button.sizeHint().width(), self.open_patient_window_confirm_button.sizeHint().height()) self.open_patient_window_confirm_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.open_patient_window_confirm_button.setDisabled(True) self.open_patient_window_confirm_button.clicked.connect( self.confirm_button_clicked) self.open_patient_window_confirm_button.setProperty( "QPushButtonClass", "success-button") self.open_patient_window_patient_open_actions_horizontal_box. \ addWidget( self.open_patient_window_confirm_button) # Create a widget to house all of the actions button for open patient # window self.open_patient_window_patient_open_actions_widget = QWidget() self.open_patient_window_patient_open_actions_widget.setLayout( self.open_patient_window_patient_open_actions_horizontal_box) self.open_patient_window_instance_vertical_box.addWidget( self.open_patient_window_patient_open_actions_widget) # Set the vertical box fourth element, the tree view, to stretch # out as far as possible self.open_patient_window_instance_vertical_box.setStretch(3, 4) self.open_patient_window_instance_central_widget = QWidget() self.open_patient_window_instance_central_widget.setObjectName( "OpenPatientWindowInstanceCentralWidget") self.open_patient_window_instance_central_widget.setLayout( self.open_patient_window_instance_vertical_box) # Create threadpool for multithreading self.threadpool = QThreadPool() # print("Multithreading with maximum %d threads" % self.threadpool. # maxThreadCount()) # Create interrupt event for stopping the directory search self.interrupt_flag = threading.Event() # Bind all texts into the buttons and labels self.retranslate_ui(open_image_fusion_select_instance) # Set the central widget, ready for display open_image_fusion_select_instance.setCentralWidget( self.open_patient_window_instance_central_widget) # Set the current stylesheet to the instance and connect it back # to the caller through slot _stylesheet = open(resource_path(self.stylesheet_path)).read() open_image_fusion_select_instance.setStyleSheet(_stylesheet) QtCore.QMetaObject.connectSlotsByName( open_image_fusion_select_instance) def retranslate_ui(self, open_image_fusion_select_instance): """Translates UI""" _translate = QtCore.QCoreApplication.translate open_image_fusion_select_instance.setWindowTitle( _translate("OpenPatientWindowInstance", "OnkoDICOM - Select Patient")) self.open_patient_directory_prompt.setText(_translate( "OpenPatientWindowInstance", "Choose an image to merge with:")) self.open_patient_directory_input_box.setPlaceholderText( _translate("OpenPatientWindowInstance", "Enter DICOM Files Path (For example, " "C:\path\\to\your\DICOM\Files)")) self.open_patient_directory_choose_button.setText(_translate( "OpenPatientWindowInstance", "Choose")) self.open_patient_directory_appear_prompt.setText(_translate( "OpenPatientWindowInstance", "Please select below the image set you wish to overlay:")) self.open_patient_directory_result_label. \ setText("The selected imageset(s) above will be " "co-registered with the current imageset.") self.open_patient_window_stop_button.setText(_translate( "OpenPatientWindowInstance", "Stop Search")) self.open_patient_window_close_button.setText(_translate( "OpenPatientWindowInstance", "Close")) self.open_patient_window_confirm_button.setText(_translate( "OpenPatientWindowInstance", "Confirm")) def update_patient(self): self.clear_checked_leaves() self.patient_dict_container = PatientDictContainer() self.patient = self.patient_dict_container.get("basic_info") self.patient_id = self.patient['id'] dataset = self.patient_dict_container.dataset[0] self.patient_current_image_series_uid = \ dataset.get("SeriesInstanceUID") def clear_checked_leaves(self): """ Resets all leaves to their unchecked state """ def recurse(parent_item: QTreeWidgetItem): for i in range(parent_item.childCount()): child = parent_item.child(i) grand_children = child.childCount() if grand_children > 0: recurse(child) else: if child.checkState(0) == Qt.Checked: child.setCheckState(0, Qt.CheckState.Unchecked) child.setSelected(False) recurse(self.open_patient_window_patients_tree.invisibleRootItem()) self.open_patient_window_patients_tree.collapseAll() def close_button_clicked(self): """Closes the window.""" self.close() def scan_directory_for_patient(self): # Reset tree view header and last patient self.open_patient_window_confirm_button.setDisabled(True) self.open_patient_window_patients_tree.setHeaderLabels([""]) self.last_patient = None self.filepath = self.open_patient_directory_input_box.text() # Proceed if a folder was selected if self.filepath != "": # Update the QTreeWidget to reflect data being loaded # First, clear the widget of any existing data self.open_patient_window_patients_tree.clear() # Next, update the tree widget self.open_patient_window_patients_tree.addTopLevelItem( QTreeWidgetItem(["Loading selected directory..."])) # The choose button is disabled until the thread finishes executing self.open_patient_directory_choose_button.setEnabled(False) # Reveals the Stop Search button for the duration of the search self.open_patient_window_stop_button.setVisible(True) # The interrupt flag is then un-set if a previous search has been # stopped. self.interrupt_flag.clear() # Then, create a new thread that will load the selected folder worker = Worker(DICOMDirectorySearch.get_dicom_structure, self.filepath, self.interrupt_flag, progress_callback=True) worker.signals.result.connect(self.on_search_complete) worker.signals.progress.connect(self.search_progress) # Execute the thread self.threadpool.start(worker) def choose_button_clicked(self): """ Executes when the choose button is clicked. Gets filepath from the user and loads all files and subdirectories. """ # Get folder path from pop up dialog box self.filepath = QtWidgets.QFileDialog.getExistingDirectory( None, 'Select patient folder...', '') self.open_patient_directory_input_box.setText(self.filepath) self.scan_directory_for_patient() def stop_button_clicked(self): self.interrupt_flag.set() def search_progress(self, progress_update): """ Current progress of the file search. """ self.open_patient_window_patients_tree.clear() self.open_patient_window_patients_tree.addTopLevelItem( QTreeWidgetItem(["Loading selected directory... " "(%s files searched)" % progress_update])) def on_search_complete(self, dicom_structure): """ Executes once the directory search is complete. :param dicom_structure: DICOMStructure object constructed by the directory search. """ self.open_patient_directory_choose_button.setEnabled(True) self.open_patient_window_stop_button.setVisible(False) self.open_patient_window_patients_tree.clear() # dicom_structure will be None if function was interrupted. if dicom_structure is None: return for patient_item in dicom_structure.get_tree_items_list(): self.open_patient_window_patients_tree.addTopLevelItem( patient_item) patient_item.setExpanded(True) # Display all studies # Display all image sets for i in range(patient_item.childCount()): study = patient_item.child(i) study.setExpanded(True) if len(dicom_structure.patients) == 0: QMessageBox.about(self, "No files found", "Selected directory contains no DICOM files.") def tree_item_clicked(self, item, _): """ Executes when a tree item is checked or unchecked. If a different patient is checked, uncheck the previous patient. Inform user about missing DICOM files. """ # If patient is only selected, but not checked, set it to "focus" to # coincide with stylesheet. And if the selected item is an image set, # display its child branches. if item.checkState(0) == Qt.CheckState.Unchecked: self.open_patient_window_patients_tree.setCurrentItem(item) else: # Otherwise don't "focus", then set patient as selected self.open_patient_window_patients_tree.setCurrentItem(None) item.setSelected(True) # Expand or collapse the tree branch if item is an image series # Only collapse if the selected image series is expanded but unchecked # Otherwise, expand its tree branch to show RT files is_expanded = False \ if (item.isExpanded() is True and item.checkState(0) == Qt.CheckState.Unchecked) else True self.display_a_tree_branch(item, is_expanded) selected_patient = item # If the item is not top-level, bubble up to see which top-level item # this item belongs to if self.open_patient_window_patients_tree.invisibleRootItem(). \ indexOfChild(item) == -1: while self.open_patient_window_patients_tree.invisibleRootItem(). \ indexOfChild(selected_patient) == -1: selected_patient = selected_patient.parent() # Uncheck previous patient if a different patient is selected if item.checkState(0) == Qt.CheckState.Checked and self.last_patient \ != selected_patient: if self.last_patient is not None: last_patient_checked_items = self.get_checked_nodes( self.last_patient) for checked_item in last_patient_checked_items: checked_item.setCheckState(0, Qt.Unchecked) self.last_patient = selected_patient # Check selected items and display warning messages self.check_selected_items(selected_patient) def display_a_tree_branch(self, node, is_expanded): # TO DO: # Could Team 23 please update the defintion of this docstring as # well as same function presented in OpenPatientWindow. """ Displays a tree branch Parameters: node : root node the tree is_expanded (boolean): flag for checking if a particular node/leaf is expanded. """ node.setExpanded(is_expanded) if node.childCount() > 0: for i in range(node.childCount()): self.display_a_tree_branch(node.child(i), is_expanded) else: return def check_selected_items(self, selected_patient): """ Check and display warning messages based on the existence and quantity of image series, RTSTRUCT, RTPLAN, RTDOSE and SR files Parameters: selected_patient (DICOMStructure): DICOM Object of patient """ # Get the types of all selected leaves & Get the names of all selected # studies checked_nodes = self.get_checked_nodes( self.open_patient_window_patients_tree.invisibleRootItem()) selected_series_types = [checked_node.dicom_object.get_series_type() for checked_node in checked_nodes] selected_series_id = [checked_node.dicom_object.series_uid for checked_node in checked_nodes] # Total number of selected image series total_selected_image_series = selected_series_types.count('CT') + \ selected_series_types.count('MR') + \ selected_series_types.count('PT') # Check the existence of IMAGE, RTSTRUCT, RTPLAN and RTDOSE files proceed = True if total_selected_image_series < 1: header = "Cannot proceed without an image." proceed = False elif total_selected_image_series > 1: header = "Cannot proceed with more than 1 selected image." proceed = False elif selected_patient.dicom_object.patient_id.strip() != \ self.patient_id: header = "Cannot proceed with different patient." proceed = False elif self.patient_current_image_series_uid in selected_series_id: header = "Cannot fuse with the same series." proceed = False elif not self.check_selected_items_referencing(checked_nodes): # Check that selected items properly reference each other header = "Selected series do not reference each other." proceed = False elif 'RTSTRUCT' not in selected_series_types and \ self.check_existing_rtss(checked_nodes): header = "The associated RTSTRUCT must be selected." proceed = False elif 'RTDOSE' in selected_series_types: header = "Cannot fuse with a RTDOSE file." proceed = False else: header = "" self.open_patient_window_confirm_button.setDisabled(not proceed) # Set the tree header self.open_patient_window_patients_tree.setHeaderLabel(header) def check_selected_items_referencing(self, items): """ Check if selected tree items properly reference each other. :param items: List of selected DICOMWidgetItems. :return: True if the selected items belong to the same tree branch. """ # Dictionary of series of different file types series = { "IMAGE": None, "RTSTRUCT": None, "RTPLAN": None, "RTDOSE": None, "SR": None } for item in items: series_type = item.dicom_object.get_series_type() if series_type in series: series[series_type] = item else: series["IMAGE"] = item # Check if the RTSTRUCT, RTPLAN, and RTDOSE are a child item of the # image series if series["IMAGE"]: if series["RTSTRUCT"] and series["RTSTRUCT"].parent() != \ series["IMAGE"]: return False if series["RTPLAN"] and \ series["RTPLAN"].parent().parent() != series["IMAGE"]: return False if series["SR"] and series["SR"].parent() != series["IMAGE"]: return False return True def check_existing_rtss(self, items): """ Check for existing rtss :return: bool, whether there is a rtss associated with the selected image series """ image_series = ['CT', 'MR', 'PT'] for item in items: if item.dicom_object.get_series_type() in image_series: for i in range(item.childCount()): if item.child(i).dicom_object: return True return False def get_checked_nodes(self, root): """ :param root: QTreeWidgetItem as a root. :return: A list of all QTreeWidgetItems in the QTreeWidget that are checked under the root. """ checked_items = [] def recurse(parent_item: QTreeWidgetItem): for i in range(parent_item.childCount()): child = parent_item.child(i) if int(child.flags()) & int(Qt.ItemIsUserCheckable) and \ child.checkState(0) == Qt.Checked: checked_items.append(child) grand_children = child.childCount() if grand_children > 0: recurse(child) recurse(root) return checked_items def confirm_button_clicked(self): """ Begins loading of the selected files. """ selected_files = [] for item in self.get_checked_nodes( self.open_patient_window_patients_tree.invisibleRootItem()): selected_files += item.dicom_object.get_files() self.progress_window = ImageFusionProgressWindow(self) self.progress_window.signal_loaded.connect(self.on_loaded) self.progress_window.signal_error.connect(self.on_loading_error) self.progress_window.start_loading(selected_files) def on_loaded(self, results): """ Executes when the progress bar finishes loaded the selected files. """ if results[0] is True: # Will be NoneType if loading was interrupted. self.image_fusion_info_initialized.emit(results[1]) def on_loading_error(self, exception): """ Error handling for progress window. """ if type(exception[1]) == ImageLoading.NotRTSetError: QMessageBox.about(self.progress_window, "Unable to open selection", "Selected files cannot be opened as they are not" " a DICOM-RT set.") self.progress_window.close() elif type(exception[1]) == ImageLoading.NotAllowedClassError: QMessageBox.about(self.progress_window, "Unable to open selection", "Selected files cannot be opened as they contain" " unsupported DICOM classes.") self.progress_window.close()
class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.resize(514, 693) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") self.pushButton = QPushButton(self.centralwidget) self.pushButton.setObjectName(u"pushButton") self.pushButton.setCursor(QCursor(Qt.PointingHandCursor)) self.gridLayout.addWidget(self.pushButton, 0, 1, 1, 1) self.tabWidget = QTabWidget(self.centralwidget) self.tabWidget.setObjectName(u"tabWidget") self.tabWidget.setStyleSheet(u"") self.tab = QWidget() self.tab.setObjectName(u"tab") self.gridLayout_2 = QGridLayout(self.tab) self.gridLayout_2.setObjectName(u"gridLayout_2") self.tableWidget = QTableWidget(self.tab) if (self.tableWidget.columnCount() < 3): self.tableWidget.setColumnCount(3) __qtablewidgetitem = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) __qtablewidgetitem1 = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) __qtablewidgetitem2 = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2) self.tableWidget.setObjectName(u"tableWidget") self.tableWidget.setStyleSheet(u"") self.tableWidget.horizontalHeader().setCascadingSectionResizes(False) self.tableWidget.verticalHeader().setVisible(False) self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 1) self.tabWidget.addTab(self.tab, "") self.tab_2 = QWidget() self.tab_2.setObjectName(u"tab_2") self.gridLayout_3 = QGridLayout(self.tab_2) self.gridLayout_3.setObjectName(u"gridLayout_3") self.tableWidget_2 = QTableWidget(self.tab_2) self.tableWidget_2.setObjectName(u"tableWidget_2") self.gridLayout_3.addWidget(self.tableWidget_2, 0, 0, 1, 1) self.tabWidget.addTab(self.tab_2, "") self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 2) self.lineEdit = QLineEdit(self.centralwidget) self.lineEdit.setObjectName(u"lineEdit") self.lineEdit.setReadOnly(True) self.gridLayout.addWidget(self.lineEdit, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") self.menubar.setGeometry(QRect(0, 0, 514, 22)) MainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName(u"statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QMetaObject.connectSlotsByName(MainWindow) # setupUi def retranslateUi(self, MainWindow): MainWindow.setWindowTitle( QCoreApplication.translate("MainWindow", u"HyperV_controller", None)) self.pushButton.setText( QCoreApplication.translate("MainWindow", u"\u5237\u65b0", None)) ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) ___qtablewidgetitem.setText( QCoreApplication.translate("MainWindow", u"\u540d\u79f0", None)) ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) ___qtablewidgetitem1.setText( QCoreApplication.translate("MainWindow", u"\u72b6\u6001", None)) self.tabWidget.setTabText( self.tabWidget.indexOf(self.tab), QCoreApplication.translate("MainWindow", u"\u865a\u62df\u673a", None)) self.tabWidget.setTabText( self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("MainWindow", u"\u529f\u80fd", None))
class UIFirstTimeWelcomeWindow(object): configured = QtCore.Signal(str) # the ui constructor function def setup_ui(self, first_time_welcome_window_instance): self.filepath = "" if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" window_icon = QtGui.QIcon() window_icon.addPixmap( QtGui.QPixmap(resource_path("res/images/icon.ico")), QtGui.QIcon.Normal, QtGui.QIcon.Off) # adding icon first_time_welcome_window_instance.setObjectName( "FirstTimeWelcomeWindowInstance") first_time_welcome_window_instance.setWindowIcon(window_icon) first_time_welcome_window_instance.setFixedSize(840, 530) # Create a vertical layout to manage layout in a vertical manner self.window_vertical_layout_box = QVBoxLayout() self.window_vertical_layout_box.setObjectName( "FirstTimeWelcomeWindowInstanceVerticalLayoutBox") # Create a horizontal box to hold the Onko logo & welcome message self.first_time_welcome_logo_message_horizontal_box = QHBoxLayout() self.first_time_welcome_logo_message_horizontal_box.setObjectName( "FirstTimeWelcomeLogoMessageBox") # Set up the Logo Holder self.logo_holder = QtWidgets.QHBoxLayout() self.first_time_welcome_logo = QtWidgets.QLabel() self.first_time_welcome_logo.setPixmap( QtGui.QPixmap(resource_path("res/images/image.png"))) self.first_time_welcome_logo.setScaledContents(True) self.first_time_welcome_logo.setObjectName( "FirstTimeWelcomeWindowLogo") self.first_time_welcome_logo.setFixedSize(240, 130) self.logo_holder.addWidget(self.first_time_welcome_logo) self.first_time_welcome_logo_message_horizontal_box.addLayout( self.logo_holder) # Create a vertical box to hold the welcome message self.first_time_welcome_message_vertical_box = QVBoxLayout() self.first_time_welcome_message_vertical_box.setObjectName( "FirstTimeWelcomeWindowWelcomeMessage") # Set up the Label self.first_time_welcome_message_label = QtWidgets.QLabel() self.first_time_welcome_message_label.setObjectName( "FirstTimeWelcomeWindowLabel") self.first_time_welcome_message_label.setAlignment(Qt.AlignLeft) self.first_time_welcome_message_vertical_box.addWidget( self.first_time_welcome_message_label) # Set up the Slogan self.first_time_welcome_message_slogan = QtWidgets.QLabel() self.first_time_welcome_message_slogan.setObjectName( "FirstTimeWelcomeWindowSlogan") self.first_time_welcome_message_slogan.setAlignment(Qt.AlignLeft) self.first_time_welcome_message_slogan.setWordWrap(True) self.first_time_welcome_message_vertical_box.addWidget( self.first_time_welcome_message_slogan) self.first_time_welcome_message_slogan_widget = QWidget() self.first_time_welcome_message_slogan_widget.setLayout( self.first_time_welcome_message_vertical_box) self.first_time_welcome_logo_message_horizontal_box.addWidget( self.first_time_welcome_message_slogan_widget) self.first_time_welcome_logo_message_widget = QWidget() self.first_time_welcome_logo_message_widget.setLayout( self.first_time_welcome_logo_message_horizontal_box) self.window_vertical_layout_box.addWidget( self.first_time_welcome_logo_message_widget) # Create a label to prompt the user to enter the path to the default directory self.first_time_welcome_default_dir_prompt = QtWidgets.QLabel() self.first_time_welcome_default_dir_prompt.setObjectName( "FirstTimeWelcomeWindowPrompt") self.first_time_welcome_default_dir_prompt.setAlignment(Qt.AlignLeft) self.window_vertical_layout_box.addWidget( self.first_time_welcome_default_dir_prompt) # Create a horizontal box to hold the input box for the directory and the choose button self.first_time_welcome_input_horizontal_box = QHBoxLayout() self.first_time_welcome_input_horizontal_box.setObjectName( "FirstTimeWelcomeWindowInputHorizontalBox") # Create a textbox to contain the path to the default directory self.first_time_welcome_input_box = UIFirstTimeUserDragAndDropEvent( self) self.first_time_welcome_input_box.setObjectName( "FirstTimeWelcomeWindowInputBox") self.first_time_welcome_input_box.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.first_time_welcome_input_horizontal_box.addWidget( self.first_time_welcome_input_box) # Create a choose button to open the file dialog self.first_time_welcome_choose_button = QPushButton() self.first_time_welcome_choose_button.setObjectName( "FirstTimeWelcomeWindowChooseButton") self.first_time_welcome_choose_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.first_time_welcome_choose_button.resize( self.first_time_welcome_choose_button.sizeHint().width(), self.first_time_welcome_input_box.height()) self.first_time_welcome_choose_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.first_time_welcome_input_horizontal_box.addWidget( self.first_time_welcome_choose_button) self.first_time_welcome_choose_button.clicked.connect( self.choose_button_clicked) # Create a widget to hold the input field self.first_time_welcome_input_widget = QWidget() self.first_time_welcome_input_horizontal_box.setStretch(0, 4) self.first_time_welcome_input_widget.setLayout( self.first_time_welcome_input_horizontal_box) self.window_vertical_layout_box.addWidget( self.first_time_welcome_input_widget) self.window_vertical_layout_box.addStretch(1) # Create widgets for the clinical data CSV file path self.clinical_data_csv_dir_label = QtWidgets.QLabel() self.clinical_data_csv_dir_label.setObjectName("ClinicalDataCSVPrompt") self.clinical_data_csv_dir_label.setAlignment(Qt.AlignLeft) self.window_vertical_layout_box.addWidget( self.clinical_data_csv_dir_label) # Create a horizontal box to hold the input box for the # directory and the choose button self.clinical_data_csv_horizontal_box = QHBoxLayout() self.clinical_data_csv_horizontal_box.setObjectName( "ClinicalDataCSVHorizontalBox") # Create a textbox to contain the path to the default directory self.clinical_data_csv_input_box = \ UIFirstTimeUserDragAndDropEvent(self) self.clinical_data_csv_input_box.setObjectName( "ClinicalDataCSVInputBox") self.clinical_data_csv_input_box.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.clinical_data_csv_horizontal_box.addWidget( self.clinical_data_csv_input_box) # Create a choose button to open the file dialog self.clinical_data_csv_choose_button = QPushButton() self.clinical_data_csv_choose_button.setObjectName( "ClinicalDataCSVChooseButton") self.clinical_data_csv_choose_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.clinical_data_csv_choose_button.resize( self.clinical_data_csv_choose_button.sizeHint().width(), self.clinical_data_csv_input_box.height()) self.clinical_data_csv_choose_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.clinical_data_csv_horizontal_box.addWidget( self.clinical_data_csv_choose_button) self.clinical_data_csv_choose_button.clicked.connect( self.change_clinical_data_csv_button_clicked) # Create a widget to hold the input field self.clinical_data_input_widget = QWidget() self.clinical_data_csv_horizontal_box.setStretch(0, 4) self.clinical_data_input_widget.setLayout( self.clinical_data_csv_horizontal_box) self.window_vertical_layout_box.addWidget( self.clinical_data_input_widget) self.window_vertical_layout_box.addStretch(1) # Create a horizontal box to hold the Skip and Confirm button self.first_time_window_configure_actions_horizontal_box = QHBoxLayout() self.first_time_window_configure_actions_horizontal_box.setObjectName( "FirstTimeWelcomeWindowConfigureActionsHorizontalBox") self.first_time_window_configure_actions_horizontal_box.addStretch(1) # Add a button to skip the configuration setting self.skip_button = QPushButton() self.skip_button.setObjectName("SkipButton") self.skip_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.skip_button.resize(self.skip_button.sizeHint().width(), self.skip_button.sizeHint().height()) self.skip_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.skip_button.setProperty("QPushButtonClass", "fail-button") self.first_time_window_configure_actions_horizontal_box.addWidget( self.skip_button) # Add a button to save the default directory self.save_dir_button = QPushButton() self.save_dir_button.setObjectName("SaveDirButton") self.save_dir_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.save_dir_button.resize(self.save_dir_button.sizeHint().width(), self.save_dir_button.sizeHint().height()) self.save_dir_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.save_dir_button.clicked.connect(self.save_options) self.save_dir_button.setProperty("QPushButtonClass", "success-button") self.first_time_window_configure_actions_horizontal_box.addWidget( self.save_dir_button) # Create a widget to house all of the actions button for first-time window self.first_time_window_configure_actions_widget = QWidget() self.first_time_window_configure_actions_widget.setLayout( self.first_time_window_configure_actions_horizontal_box) self.window_vertical_layout_box.addWidget( self.first_time_window_configure_actions_widget) self.first_time_window_instance_central_widget = QWidget() self.first_time_window_instance_central_widget.setLayout( self.window_vertical_layout_box) first_time_welcome_window_instance.setCentralWidget( self.first_time_window_instance_central_widget) # Set the current stylesheet to the instance and connect it back to the caller through slot _stylesheet = open(resource_path(self.stylesheet_path)).read() first_time_welcome_window_instance.setStyleSheet(_stylesheet) self.retranslate_ui(first_time_welcome_window_instance) QtCore.QMetaObject.connectSlotsByName( first_time_welcome_window_instance) # this function inserts all the text in the first time page def retranslate_ui(self, first_time_welcome_window_instance): _translate = QtCore.QCoreApplication.translate first_time_welcome_window_instance.setWindowTitle( _translate("FirstTimeWelcomeWindowInstance", "OnkoDICOM - First-time User Setting")) self.first_time_welcome_message_label.setText( _translate("FirstTimeWelcomeWindowInstance", "Welcome to OnkoDICOM!")) self.first_time_welcome_message_slogan.setText( _translate( "FirstTimeWelcomeWindowInstance", "OnkoDICOM - the solution for producing data for analysis from your oncology plans and scans." )) self.first_time_welcome_default_dir_prompt.setText( _translate( "FirstTimeWelcomeWindowInstance", "Choose the path of the default directory containing all DICOM files:" )) self.first_time_welcome_input_box.setPlaceholderText( _translate( "FirstTimeWelcomeWindowInstance", "Enter DICOM Files Path (For example, C:\path\\to\your\DICOM\Files)" )) self.first_time_welcome_choose_button.setText( _translate("FirstTimeWelcomeWindowInstance", "Choose")) # Clinical data CSV widgets self.clinical_data_csv_dir_label.setText( _translate( "FirstTimeWelcomeWindowInstance", "Choose the CSV file containing patient clinical data:")) self.clinical_data_csv_input_box.setPlaceholderText( _translate("FirstTimeWelcomeWindowInstance", "Enter CSV File Path (for example, C:\CSV\\file.csv)")) self.clinical_data_csv_choose_button.setText( _translate("FirstTimeWelcomeWindowInstance", "Choose")) self.save_dir_button.setText( _translate("FirstTimeWelcomeWindowInstance", "Confirm")) self.skip_button.setText( _translate("FirstTimeWelcomeWindowInstance", "Skip")) def save_options(self): """ Saves options selected in the first time welcome window. """ self.filepath = self.first_time_welcome_input_box.text() self.csv_path = self.clinical_data_csv_input_box.text() if self.filepath == "" and self.csv_path == "": QMessageBox.about(self, "Unable to proceed", "No directories selected.") elif not os.path.exists(self.filepath) or not \ os.path.exists(self.csv_path): QMessageBox.about(self, "Unable to proceed", "Directories do not exist") else: config = Configuration() try: config.update_default_directory(self.filepath) # Update CSV path if it exists if self.csv_path != "" and os.path.exists(self.csv_path): config.update_clinical_data_csv_dir(self.csv_path) except SqlError: config.set_up_config_db() QMessageBox.critical( self, "Config file error", "Failed to access configuration file.\nPlease try again.") else: self.configured.emit(self.filepath) def choose_button_clicked(self): """ Executes when the choose button is clicked. Gets filepath from the user and loads all files and subdirectories. """ # Get folder path from pop up dialog box self.filepath = QtWidgets.QFileDialog.getExistingDirectory( None, 'Select default directory...', '') self.first_time_welcome_input_box.setText(self.filepath) def change_clinical_data_csv_button_clicked(self): """ Executes when the choose button is clicked. Gets filepath from the user. """ # Get folder path from pop up dialog box self.csv_path = QtWidgets.QFileDialog.getOpenFileName( None, "Open Clinical Data File", "", "CSV data files (*.csv)")[0] if len(self.csv_path) > 0: self.clinical_data_csv_input_box.setText(self.csv_path)
class UIManipulateROIWindow: def setup_ui(self, manipulate_roi_window_instance, rois, dataset_rtss, roi_color, signal_roi_manipulated): self.patient_dict_container = PatientDictContainer() self.rois = rois self.dataset_rtss = dataset_rtss self.signal_roi_manipulated = signal_roi_manipulated self.roi_color = roi_color self.roi_names = [] # Names of selected ROIs self.all_roi_names = [] # Names of all existing ROIs for roi_id, roi_dict in self.rois.items(): self.all_roi_names.append(roi_dict['name']) # Operation names self.single_roi_operation_names = [ "Expand", "Contract", "Inner Rind (annulus)", "Outer Rind (annulus)" ] self.multiple_roi_operation_names = [ "Union", "Intersection", "Difference" ] self.operation_names = self.multiple_roi_operation_names + \ self.single_roi_operation_names self.new_ROI_contours = None self.manipulate_roi_window_instance = manipulate_roi_window_instance self.dicom_view = DicomAxialView(metadata_formatted=True, is_four_view=True) self.dicom_preview = DicomAxialView(metadata_formatted=True, is_four_view=True) self.dicom_view.slider.valueChanged.connect( self.dicom_view_slider_value_changed) self.dicom_preview.slider.valueChanged.connect( self.dicom_preview_slider_value_changed) self.init_layout() QtCore.QMetaObject.connectSlotsByName(manipulate_roi_window_instance) def retranslate_ui(self, manipulate_roi_window_instance): _translate = QtCore.QCoreApplication.translate manipulate_roi_window_instance.setWindowTitle( _translate("ManipulateRoiWindowInstance", "OnkoDICOM - Draw Region Of Interest")) self.first_roi_name_label.setText( _translate("FirstROINameLabel", "ROI 1: ")) self.first_roi_name_dropdown_list.setPlaceholderText("ROI 1") self.first_roi_name_dropdown_list.addItems(self.all_roi_names) self.operation_name_label.setText( _translate("OperationNameLabel", "Operation")) self.operation_name_dropdown_list.setPlaceholderText("Operation") self.operation_name_dropdown_list.addItems(self.operation_names) self.second_roi_name_label.setText( _translate("SecondROINameLabel", "ROI 2: ")) self.second_roi_name_dropdown_list.setPlaceholderText("ROI 2") self.second_roi_name_dropdown_list.addItems(self.all_roi_names) self.manipulate_roi_window_instance_draw_button.setText( _translate("ManipulateRoiWindowInstanceDrawButton", "Draw")) self.manipulate_roi_window_instance_save_button.setText( _translate("ManipulateRoiWindowInstanceSaveButton", "Save")) self.manipulate_roi_window_instance_cancel_button.setText( _translate("ManipulateRoiWindowInstanceCancelButton", "Cancel")) self.margin_label.setText(_translate("MarginLabel", "Margin (mm): ")) self.new_roi_name_label.setText( _translate("NewROINameLabel", "New ROI Name")) self.ROI_view_box_label.setText("ROI") self.preview_box_label.setText("Preview") def init_layout(self): """ Initialize the layout for the DICOM View tab. Add the view widget and the slider in the layout. Add the whole container 'tab2_view' as a tab in the main page. """ # Initialise a ManipulateROIWindow if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" stylesheet = open(resource_path(self.stylesheet_path)).read() window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) self.manipulate_roi_window_instance.setObjectName( "ManipulateRoiWindowInstance") self.manipulate_roi_window_instance.setWindowIcon(window_icon) # Creating a form box to hold all buttons and input fields self.manipulate_roi_window_input_container_box = QFormLayout() self.manipulate_roi_window_input_container_box.setObjectName( "ManipulateRoiWindowInputContainerBox") self.manipulate_roi_window_input_container_box.setLabelAlignment( Qt.AlignLeft) # Create a label for denoting the first ROI name self.first_roi_name_label = QLabel() self.first_roi_name_label.setObjectName("FirstROINameLabel") self.first_roi_name_dropdown_list = QComboBox() # Create an dropdown list for ROI name self.first_roi_name_dropdown_list.setObjectName( "FirstROINameDropdownList") self.first_roi_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.first_roi_name_dropdown_list.resize( self.first_roi_name_dropdown_list.sizeHint().width(), self.first_roi_name_dropdown_list.sizeHint().height()) self.first_roi_name_dropdown_list.activated.connect( self.update_selected_rois) self.manipulate_roi_window_input_container_box.addRow( self.first_roi_name_label, self.first_roi_name_dropdown_list) # Create a label for denoting the operation self.operation_name_label = QLabel() self.operation_name_label.setObjectName("OperationNameLabel") self.operation_name_dropdown_list = QComboBox() # Create an dropdown list for operation name self.operation_name_dropdown_list.setObjectName( "OperationNameDropdownList") self.operation_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.operation_name_dropdown_list.resize( self.operation_name_dropdown_list.sizeHint().width(), self.operation_name_dropdown_list.sizeHint().height()) self.operation_name_dropdown_list.activated.connect( self.operation_changed) self.manipulate_roi_window_input_container_box.addRow( self.operation_name_label, self.operation_name_dropdown_list) # Create a label for denoting the second ROI name self.second_roi_name_label = QLabel() self.second_roi_name_label.setObjectName("SecondROINameLabel") self.second_roi_name_label.setVisible(False) self.second_roi_name_dropdown_list = QComboBox() # Create an dropdown list for ROI name self.second_roi_name_dropdown_list.setObjectName( "SecondROINameDropdownList") self.second_roi_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.second_roi_name_dropdown_list.resize( self.second_roi_name_dropdown_list.sizeHint().width(), self.second_roi_name_dropdown_list.sizeHint().height()) self.second_roi_name_dropdown_list.setVisible(False) self.second_roi_name_dropdown_list.activated.connect( self.update_selected_rois) self.manipulate_roi_window_input_container_box.addRow( self.second_roi_name_label, self.second_roi_name_dropdown_list) # Create a label for denoting the margin self.margin_label = QLabel() self.margin_label.setObjectName("MarginLabel") self.margin_label.setVisible(False) # Create input for the new ROI name self.margin_line_edit = QLineEdit() self.margin_line_edit.setObjectName("MarginInput") self.margin_line_edit.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.margin_line_edit.resize(self.margin_line_edit.sizeHint().width(), self.margin_line_edit.sizeHint().height()) self.margin_line_edit.setVisible(False) self.margin_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.manipulate_roi_window_input_container_box.addRow( self.margin_label, self.margin_line_edit) # Create a label for denoting the new ROI name self.new_roi_name_label = QLabel() self.new_roi_name_label.setObjectName("NewROINameLabel") # Create input for the new ROI name self.new_roi_name_line_edit = QLineEdit() self.new_roi_name_line_edit.setObjectName("NewROINameInput") self.new_roi_name_line_edit.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.new_roi_name_line_edit.resize( self.new_roi_name_line_edit.sizeHint().width(), self.new_roi_name_line_edit.sizeHint().height()) self.manipulate_roi_window_input_container_box.addRow( self.new_roi_name_label, self.new_roi_name_line_edit) # Create a spacer between inputs and buttons spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) spacer.setFocusPolicy(Qt.NoFocus) self.manipulate_roi_window_input_container_box.addRow(spacer) # Create a warning message when missing inputs self.warning_message = QWidget() self.warning_message.setContentsMargins(8, 5, 8, 5) warning_message_layout = QHBoxLayout() warning_message_layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignLeft) warning_message_icon = QLabel() warning_message_icon.setPixmap( QtGui.QPixmap( resource_path("res/images/btn-icons/alert_icon.png"))) warning_message_layout.addWidget(warning_message_icon) self.warning_message_text = QLabel() self.warning_message_text.setStyleSheet("color: red") warning_message_layout.addWidget(self.warning_message_text) self.warning_message.setLayout(warning_message_layout) self.warning_message.setVisible(False) self.manipulate_roi_window_input_container_box.addRow( self.warning_message) # Create a draw button self.manipulate_roi_window_instance_draw_button = QPushButton() self.manipulate_roi_window_instance_draw_button.setObjectName( "ManipulateRoiWindowInstanceDrawButton") self.manipulate_roi_window_instance_draw_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_draw_button.resize( self.manipulate_roi_window_instance_draw_button.sizeHint().width(), self.manipulate_roi_window_instance_draw_button.sizeHint().height( )) self.manipulate_roi_window_instance_draw_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.manipulate_roi_window_instance_draw_button.clicked.connect( self.onDrawButtonClicked) self.manipulate_roi_window_input_container_box.addRow( self.manipulate_roi_window_instance_draw_button) # Create a horizontal box for saving and cancel the drawing self.manipulate_roi_window_cancel_save_box = QHBoxLayout() self.manipulate_roi_window_cancel_save_box.setObjectName( "ManipulateRoiWindowCancelSaveBox") # Create an exit button to cancel the drawing # Add a button to go back/exit from the application self.manipulate_roi_window_instance_cancel_button = QPushButton() self.manipulate_roi_window_instance_cancel_button.setObjectName( "ManipulateRoiWindowInstanceCancelButton") self.manipulate_roi_window_instance_cancel_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_cancel_button.resize( self.manipulate_roi_window_instance_cancel_button.sizeHint().width( ), self.manipulate_roi_window_instance_cancel_button.sizeHint(). height()) self.manipulate_roi_window_instance_cancel_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.manipulate_roi_window_instance_cancel_button.clicked.connect( self.onCancelButtonClicked) self.manipulate_roi_window_instance_cancel_button.setProperty( "QPushButtonClass", "fail-button") icon_cancel = QtGui.QIcon() icon_cancel.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/cancel_icon.png'))) self.manipulate_roi_window_instance_cancel_button.setIcon(icon_cancel) self.manipulate_roi_window_cancel_save_box.addWidget( self.manipulate_roi_window_instance_cancel_button) # Create a save button to save all the changes self.manipulate_roi_window_instance_save_button = QPushButton() self.manipulate_roi_window_instance_save_button.setObjectName( "ManipulateRoiWindowInstanceSaveButton") self.manipulate_roi_window_instance_save_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_save_button.resize( self.manipulate_roi_window_instance_save_button.sizeHint().width(), self.manipulate_roi_window_instance_save_button.sizeHint().height( )) self.manipulate_roi_window_instance_save_button.setProperty( "QPushButtonClass", "success-button") icon_save = QtGui.QIcon() icon_save.addPixmap( QtGui.QPixmap(resource_path('res/images/btn-icons/save_icon.png'))) self.manipulate_roi_window_instance_save_button.setIcon(icon_save) self.manipulate_roi_window_instance_save_button.clicked.connect( self.onSaveClicked) self.manipulate_roi_window_cancel_save_box.addWidget( self.manipulate_roi_window_instance_save_button) self.manipulate_roi_window_input_container_box.addRow( self.manipulate_roi_window_cancel_save_box) # Creating a horizontal box to hold the ROI view and the preview self.manipulate_roi_window_instance_view_box = QHBoxLayout() self.manipulate_roi_window_instance_view_box.setObjectName( "ManipulateRoiWindowInstanceViewBoxes") # Font for the ROI view and preview's labels font = QFont() font.setBold(True) font.setPixelSize(20) # Creating the ROI view self.ROI_view_box_layout = QVBoxLayout() self.ROI_view_box_label = QLabel() self.ROI_view_box_label.setFont(font) self.ROI_view_box_label.setAlignment(Qt.AlignHCenter) self.ROI_view_box_layout.addWidget(self.ROI_view_box_label) self.ROI_view_box_layout.addWidget(self.dicom_view) self.ROI_view_box_widget = QWidget() self.ROI_view_box_widget.setLayout(self.ROI_view_box_layout) # Creating the preview self.preview_box_layout = QVBoxLayout() self.preview_box_label = QLabel() self.preview_box_label.setFont(font) self.preview_box_label.setAlignment(Qt.AlignHCenter) self.preview_box_layout.addWidget(self.preview_box_label) self.preview_box_layout.addWidget(self.dicom_preview) self.preview_box_widget = QWidget() self.preview_box_widget.setLayout(self.preview_box_layout) # Add View and Slider into horizontal box self.manipulate_roi_window_instance_view_box.addWidget( self.ROI_view_box_widget) self.manipulate_roi_window_instance_view_box.addWidget( self.preview_box_widget) # Create a widget to hold the image slice box self.manipulate_roi_window_instance_view_widget = QWidget() self.manipulate_roi_window_instance_view_widget.setObjectName( "ManipulateRoiWindowInstanceActionWidget") self.manipulate_roi_window_instance_view_widget.setLayout( self.manipulate_roi_window_instance_view_box) # Create a horizontal box for containing the input fields and the # viewports self.manipulate_roi_window_main_box = QHBoxLayout() self.manipulate_roi_window_main_box.setObjectName( "ManipulateRoiWindowMainBox") self.manipulate_roi_window_main_box.addLayout( self.manipulate_roi_window_input_container_box, 1) self.manipulate_roi_window_main_box.addWidget( self.manipulate_roi_window_instance_view_widget, 11) # Create a new central widget to hold the horizontal box layout self.manipulate_roi_window_instance_central_widget = QWidget() self.manipulate_roi_window_instance_central_widget.setObjectName( "ManipulateRoiWindowInstanceCentralWidget") self.manipulate_roi_window_instance_central_widget.setLayout( self.manipulate_roi_window_main_box) self.retranslate_ui(self.manipulate_roi_window_instance) self.manipulate_roi_window_instance.setStyleSheet(stylesheet) self.manipulate_roi_window_instance.setCentralWidget( self.manipulate_roi_window_instance_central_widget) QtCore.QMetaObject.connectSlotsByName( self.manipulate_roi_window_instance) def dicom_view_slider_value_changed(self): """ Display selected ROIs in dropbox when moving to another image slice """ self.display_selected_roi() if self.dicom_preview.slider.value() != self.dicom_view.slider.value(): self.dicom_preview.slider.setValue(self.dicom_view.slider.value()) def dicom_preview_slider_value_changed(self): """ Display generated ROI when moving to another image slice """ self.draw_roi() if self.dicom_preview.slider.value() != self.dicom_view.slider.value(): self.dicom_view.slider.setValue(self.dicom_preview.slider.value()) def onCancelButtonClicked(self): """ This function is used for canceling the drawing """ self.close() def onDrawButtonClicked(self): """ Function triggered when the Draw button is pressed from the menu. """ # Hide warning message self.warning_message.setVisible(False) # Check inputs selected_operation = self.operation_name_dropdown_list.currentText() roi_1 = self.first_roi_name_dropdown_list.currentText() roi_2 = self.second_roi_name_dropdown_list.currentText() new_roi_name = self.new_roi_name_line_edit.text() # Check the selected inputs and execute the operations if roi_1 != "" and new_roi_name != "" and \ self.margin_line_edit.text() != "" and \ selected_operation in self.single_roi_operation_names: # Single ROI operations dict_rois_contours = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), [roi_1], self.patient_dict_container.get("pixluts")) roi_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_1]) margin = float(self.margin_line_edit.text()) if selected_operation == self.single_roi_operation_names[0]: new_geometry = ROI.scale_roi(roi_geometry, margin) elif selected_operation == self.single_roi_operation_names[1]: new_geometry = ROI.scale_roi(roi_geometry, -margin) elif selected_operation == self.single_roi_operation_names[2]: new_geometry = ROI.rind_roi(roi_geometry, -margin) else: new_geometry = ROI.rind_roi(roi_geometry, margin) self.new_ROI_contours = ROI.geometry_to_roi(new_geometry) self.draw_roi() return True elif roi_1 != "" and roi_2 != "" and new_roi_name != "" and \ selected_operation in self.multiple_roi_operation_names: # Multiple ROI operations dict_rois_contours = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), [roi_1, roi_2], self.patient_dict_container.get("pixluts")) roi_1_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_1]) roi_2_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_2]) # Execute the selected operation new_geometry = ROI.manipulate_rois(roi_1_geometry, roi_2_geometry, selected_operation.upper()) self.new_ROI_contours = ROI.geometry_to_roi(new_geometry) self.draw_roi() return True self.warning_message_text.setText("Not all values are specified.") self.warning_message.setVisible(True) return False def onSaveClicked(self): """ Save the new ROI """ # Get the name of the new ROI new_roi_name = self.new_roi_name_line_edit.text() # If the new ROI hasn't been drawn, draw the new ROI. Then if the new # ROI is drawn successfully, proceed to save the new ROI. if self.new_ROI_contours is None: if not self.onDrawButtonClicked(): return # Get a dict to convert SOPInstanceUID to slice id slice_ids_dict = get_dict_slice_to_uid(PatientDictContainer()) # Transform new_ROI_contours to a list of roi information rois_to_save = {} for uid, contour_sequence in self.new_ROI_contours.items(): slider_id = slice_ids_dict[uid] location = self.patient_dict_container.filepaths[slider_id] ds = pydicom.dcmread(location) slice_info = {'coords': contour_sequence, 'ds': ds} rois_to_save[slider_id] = slice_info roi_list = ROI.convert_hull_list_to_contours_data( rois_to_save, self.patient_dict_container) connectSaveROIProgress(self, roi_list, self.dataset_rtss, new_roi_name, self.roi_saved) def draw_roi(self): """ Draw the new ROI """ # Get the new ROI's name new_roi_name = self.new_roi_name_line_edit.text() # Check if the new ROI contour is None if self.new_ROI_contours is None: return # Get the info required to draw the new ROI slider_id = self.dicom_preview.slider.value() curr_slice = self.patient_dict_container.get("dict_uid")[slider_id] # Calculate the new ROI's polygon dict_ROI_contours = {} dict_ROI_contours[new_roi_name] = self.new_ROI_contours polygons = ROI.calc_roi_polygon(new_roi_name, curr_slice, dict_ROI_contours) # Set the new ROI color color = QtGui.QColor() color.setRgb(90, 250, 175, 200) pen_color = QtGui.QColor(color.red(), color.green(), color.blue()) pen = QtGui.QPen(pen_color) pen.setStyle(QtCore.Qt.PenStyle(1)) pen.setWidthF(2.0) # Draw the new ROI self.dicom_preview.update_view() for i in range(len(polygons)): self.dicom_preview.scene.addPolygon(polygons[i], pen, QtGui.QBrush(color)) def update_selected_rois(self): """ Get the names of selected ROIs """ # Hide warning message self.warning_message.setVisible(False) self.roi_names = [] if self.first_roi_name_dropdown_list.currentText() != "": self.roi_names.append( self.first_roi_name_dropdown_list.currentText()) if self.second_roi_name_dropdown_list.currentText() != "" and \ self.second_roi_name_dropdown_list.isVisible(): self.roi_names.append( self.second_roi_name_dropdown_list.currentText()) self.dict_rois_contours_axial = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), self.roi_names, self.patient_dict_container.get("pixluts")) self.display_selected_roi() def display_selected_roi(self): """ Display selected ROIs """ # Get the info required to display the selected ROIs slider_id = self.dicom_view.slider.value() curr_slice = self.patient_dict_container.get("dict_uid")[slider_id] self.rois = self.patient_dict_container.get("rois") # Display the selected ROIs self.dicom_view.update_view() for roi_id, roi_dict in self.rois.items(): roi_name = roi_dict['name'] if roi_name in self.roi_names: polygons = ROI.calc_roi_polygon(roi_name, curr_slice, self.dict_rois_contours_axial) self.dicom_view.draw_roi_polygons(roi_id, polygons, self.roi_color) def operation_changed(self): """ Change the form when users select different operations """ # Hide warning message self.warning_message.setVisible(False) selected_operation = self.operation_name_dropdown_list.currentText() if selected_operation in self.single_roi_operation_names: self.second_roi_name_label.setVisible(False) self.second_roi_name_dropdown_list.setVisible(False) self.margin_label.setVisible(True) self.margin_line_edit.setVisible(True) self.update_selected_rois() else: self.second_roi_name_label.setVisible(True) self.second_roi_name_dropdown_list.setVisible(True) self.margin_label.setVisible(False) self.margin_line_edit.setVisible(False) self.update_selected_rois() def roi_saved(self, new_rtss): """ Create a new ROI in Structure Tab and notify user """ new_roi_name = self.new_roi_name_line_edit.text() self.signal_roi_manipulated.emit((new_rtss, {"draw": new_roi_name})) QMessageBox.about(self.manipulate_roi_window_instance, "Saved", "New contour successfully created!") self.close()
class Ui_Dialog(object): def setupUi(self, Dialog): if not Dialog.objectName(): Dialog.setObjectName(u"Dialog") Dialog.resize(1136, 733) self.formLayout = QFormLayout(Dialog) self.formLayout.setObjectName(u"formLayout") self.tableWidget = QTableWidget(Dialog) if (self.tableWidget.columnCount() < 4): self.tableWidget.setColumnCount(4) __qtablewidgetitem = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) __qtablewidgetitem1 = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) __qtablewidgetitem2 = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2) __qtablewidgetitem3 = QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3) self.tableWidget.setObjectName(u"tableWidget") self.tableWidget.setMinimumSize(QSize(0, 450)) self.tableWidget.verticalHeader().setVisible(False) self.formLayout.setWidget(1, QFormLayout.SpanningRole, self.tableWidget) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.textEdit = QTextEdit(Dialog) self.textEdit.setObjectName(u"textEdit") self.textEdit.setReadOnly(True) self.horizontalLayout.addWidget(self.textEdit) self.verticalLayout = QVBoxLayout() self.verticalLayout.setObjectName(u"verticalLayout") self.pushButton = QPushButton(Dialog) self.pushButton.setObjectName(u"pushButton") sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) self.pushButton.setSizePolicy(sizePolicy) self.pushButton.setCursor(QCursor(Qt.PointingHandCursor)) self.verticalLayout.addWidget(self.pushButton) self.pushButton_2 = QPushButton(Dialog) self.pushButton_2.setObjectName(u"pushButton_2") sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth()) self.pushButton_2.setSizePolicy(sizePolicy) self.pushButton_2.setCursor(QCursor(Qt.PointingHandCursor)) self.verticalLayout.addWidget(self.pushButton_2) self.horizontalLayout.addLayout(self.verticalLayout) self.formLayout.setLayout(0, QFormLayout.SpanningRole, self.horizontalLayout) self.buttonBox = QDialogButtonBox(Dialog) self.buttonBox.setObjectName(u"buttonBox") self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.formLayout.setWidget(2, QFormLayout.FieldRole, self.buttonBox) self.retranslateUi(Dialog) self.buttonBox.accepted.connect(Dialog.accept) self.buttonBox.rejected.connect(Dialog.reject) QMetaObject.connectSlotsByName(Dialog) # setupUi def retranslateUi(self, Dialog): Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"popup_hyperv", None)) ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) ___qtablewidgetitem.setText(QCoreApplication.translate("Dialog", u"\u529f\u80fd", None)); ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) ___qtablewidgetitem1.setText(QCoreApplication.translate("Dialog", u"\u8bf4\u660e", None)); ___qtablewidgetitem2 = self.tableWidget.horizontalHeaderItem(2) ___qtablewidgetitem2.setText(QCoreApplication.translate("Dialog", u"\u5f53\u524d\u503c", None)); ___qtablewidgetitem3 = self.tableWidget.horizontalHeaderItem(3) ___qtablewidgetitem3.setText(QCoreApplication.translate("Dialog", u"\u4fee\u6539", None)); self.pushButton.setText(QCoreApplication.translate("Dialog", u"\u5237\u65b0", None)) self.pushButton_2.setText(QCoreApplication.translate("Dialog", u"\u4fee\u6539", None))