def init_ui(self): ''' Helper function to initialize UI widgets ''' # set up the frame object cw = QtGui.QWidget() self.setCentralWidget(cw) self.frame_widget = FrameWidget(self.frame.radius) self.available_shapes_widget = AvailableShapesWidget() self.info_widget = InfoWidget() self.frame.set_frame_widget(self.frame_widget) self.frame.set_available_shapes_widget(self.available_shapes_widget) self.frame.set_info_widget(self.info_widget) # Exit action exit_action = QtGui.QAction(QtGui.QIcon.fromTheme("exit"), '&Exit', self) exit_action.setShortcut('Ctrl+Q') exit_action.setStatusTip('Exit application') exit_action.triggered.connect(self.close) # Create a menubar #menubar = self.menuBar() #file_menu = menubar.addMenu('&File') #file_menu.addAction(exit_action) # Create a toolbar self.toolbar = self.addToolBar('Exit') self.toolbar.addAction(exit_action) # Create a statusbar self.statusBar() self.statuslabel = QtGui.QLabel("Algorithm is <b>stopped</b>") self.statusBar().addPermanentWidget(self.statuslabel) self.frame.set_statuslabel(self.statuslabel) # Button to move shapes back to the right reset_button = QtGui.QPushButton('Reset', self) reset_button.clicked.connect(self.frame.reset_shapes) reset_button.resize(reset_button.sizeHint()) reset_button.setStatusTip("Move all fitted shapes to the available shapes") # Button to run algorithm run_button = QtGui.QPushButton("Run") run_button.clicked.connect(self.run_frame_widget_algorithm) run_button.setStatusTip("Run the currently selected algorithm") # Button to stop algorithm stop_button = QtGui.QPushButton("Stop") stop_button.clicked.connect(self.frame.request_stop) stop_button.setStatusTip("Stop the currently running algorithm") # Button to generate shapes generate_button = QtGui.QPushButton('Generate\nshapes', self) generate_button.clicked.connect(self.generate_shapes) generate_button.setStatusTip('Generate new shapes') # Button to shuffle shapes shuffle_button = QtGui.QPushButton("Shuffle") shuffle_button.clicked.connect(self.frame.shuffle_available_shapes) shuffle_button.setStatusTip('Shuffle available shapes') # Button to clear shapes clear_button = QtGui.QPushButton("Clear shapes") clear_button.clicked.connect(self.frame.clear_available_shapes) clear_button.setStatusTip("Clear all shapes if algorithm is not running") # Button to sort shapes sort_button = QtGui.QPushButton("Sort by size") sort_button.clicked.connect(self.sort_available_shapes) sort_button.setStatusTip("Sort the available shapes by size") # Combobox to choose algorithm algolabel = QtGui.QLabel() algolabel.setText("Algorithm:") self.algocombo = QtGui.QComboBox() self.algocombo.addItems(self.frame.get_algorithms()) self.algocombo.setStatusTip("Choose the algorithm for packing") # Checkboxes, spinboxes and labels for shape generation self.rectcheckbox = QtGui.QCheckBox() self.rectcheckbox.setText('Generate') self.rectcheckbox.setChecked(True) self.circcheckbox = QtGui.QCheckBox() self.circcheckbox.setText('Generate') self.circcheckbox.setChecked(True) self.rectspinbox = QtGui.QSpinBox() self.rectspinbox.setMinimum(0) self.rectspinbox.setMaximum(50) self.rectspinbox.setValue(5) self.circspinbox = QtGui.QSpinBox() self.circspinbox.setMinimum(0) self.circspinbox.setMaximum(50) self.circspinbox.setValue(5) self.circspinbox.accelerated = True self.circmaxspinbox = QtGui.QSpinBox() self.circmaxspinbox.setMinimum(10) self.circmaxspinbox.setMaximum(self.frame.radius * 2) self.circmaxspinbox.setValue(self.frame.radius) self.circminspinbox = QtGui.QSpinBox() self.circminspinbox.setMinimum(10) self.circminspinbox.setMaximum(self.frame.radius * 2) self.circminspinbox.setValue(10) self.circmaxspinbox.valueChanged.connect(self.cminChange) self.circminspinbox.valueChanged.connect(self.cmaxChange) self.rectmaxspinbox = QtGui.QSpinBox() self.rectmaxspinbox.setMinimum(10) self.rectmaxspinbox.setMaximum(self.frame.radius * 2) self.rectmaxspinbox.setValue(self.frame.radius) self.rectminspinbox = QtGui.QSpinBox() self.rectminspinbox.setMinimum(10) self.rectminspinbox.setMaximum(self.frame.radius * 2) self.rectminspinbox.setValue(10) self.rectmaxspinbox.valueChanged.connect(self.rminChange) self.rectminspinbox.valueChanged.connect(self.rmaxChange) rectlabel = QtGui.QLabel() rectlabel.setText("<b>rectangles</b> with sides from") circlabel = QtGui.QLabel() circlabel.setText("<b>circles</b> with diameters from") tolabel1 = QtGui.QLabel() tolabel1.setText("to") tolabel2 = QtGui.QLabel() tolabel2.setText("to") emptylabel = QtGui.QLabel() emptylabel.setText("") # Grid layout for shape generation gengrid = QtGui.QGridLayout() gengrid.addWidget(self.rectcheckbox, 0, 0) gengrid.addWidget(self.circcheckbox, 1, 0) gengrid.addWidget(self.rectspinbox, 0, 1) gengrid.addWidget(self.circspinbox, 1, 1) gengrid.addWidget(rectlabel, 0, 2) gengrid.addWidget(circlabel, 1, 2) gengrid.addWidget(self.rectminspinbox, 0, 3) gengrid.addWidget(self.circminspinbox, 1, 3) gengrid.addWidget(tolabel1, 0, 4) gengrid.addWidget(tolabel2, 1, 4) gengrid.addWidget(self.rectmaxspinbox, 0, 5) gengrid.addWidget(self.circmaxspinbox, 1, 5) gengrid.addWidget(generate_button, 0, 6, 2, 1) gengrid.addWidget(emptylabel, 0, 7) gengrid.setColumnStretch(7, 1) # HBox for run, stop and reset buttons hbox = QtGui.QHBoxLayout() hbox.addWidget(run_button) hbox.addWidget(stop_button) hbox.addWidget(reset_button) hbox.addStretch(1) # HBox for algorithm combobox and label hboxalgo = QtGui.QHBoxLayout() hboxalgo.addWidget(algolabel) hboxalgo.addWidget(self.algocombo) hboxalgo.addStretch(1) # VBox for left pane vboxmain = QtGui.QVBoxLayout() vboxmain.addWidget(self.frame_widget) vboxmain.addWidget(self.info_widget) vboxmain.addLayout(hboxalgo) vboxmain.addLayout(hbox) # Checkbox for reverse sorting and HBox for buttons self.reversecheck = QtGui.QCheckBox() self.reversecheck.setText('Reverse') self.reversecheck.setChecked(False) self.reversecheck.setStatusTip("Sort in reverse") hboxshape = QtGui.QHBoxLayout() hboxshape.addWidget(self.reversecheck) hboxshape.addWidget(sort_button) hboxshape.addWidget(shuffle_button) hboxshape.addWidget(clear_button) hboxshape.addStretch(1) # ScrollArea for available_shapes_widget and VBox for right pane aswscroll = QtGui.QScrollArea() aswscroll.setWidget(self.available_shapes_widget) aswscroll.setMinimumWidth(430) aswscroll.setWidgetResizable(True) vboxright = QtGui.QVBoxLayout() vboxright.addWidget(aswscroll) vboxright.addLayout(hboxshape) vboxright.addLayout(gengrid) # HBox to split UI in two panes hboxmain = QtGui.QHBoxLayout() hboxmain.addLayout(vboxmain) hboxmain.addLayout(vboxright) hboxmain.setStretch(1,1) # Central widget self.centralWidget().setLayout(hboxmain) # Set window title and show main window first and widgets after that # to avoid extra windows popping up self.setWindowTitle('Packman') self.show() self.center() self.frame_widget.show() self.available_shapes_widget.show() self.info_widget.show()
class MainWindow(QtGui.QMainWindow): ''' Creates a main window with the required widgets to handle showing shapes and running algorithms for fitting shapes. Inherits QtGui.QMainWindow. ''' def __init__(self, frame): ''' Initialize an instance and set the frame which handles algorithms and fitting to frame, and the radius to radius. @param frame: the frame which will handle fitting @type frame: Frame ''' super(MainWindow, self).__init__() self.frame = frame self.init_ui() def init_ui(self): ''' Helper function to initialize UI widgets ''' # set up the frame object cw = QtGui.QWidget() self.setCentralWidget(cw) self.frame_widget = FrameWidget(self.frame.radius) self.available_shapes_widget = AvailableShapesWidget() self.info_widget = InfoWidget() self.frame.set_frame_widget(self.frame_widget) self.frame.set_available_shapes_widget(self.available_shapes_widget) self.frame.set_info_widget(self.info_widget) # Exit action exit_action = QtGui.QAction(QtGui.QIcon.fromTheme("exit"), '&Exit', self) exit_action.setShortcut('Ctrl+Q') exit_action.setStatusTip('Exit application') exit_action.triggered.connect(self.close) # Create a menubar #menubar = self.menuBar() #file_menu = menubar.addMenu('&File') #file_menu.addAction(exit_action) # Create a toolbar self.toolbar = self.addToolBar('Exit') self.toolbar.addAction(exit_action) # Create a statusbar self.statusBar() self.statuslabel = QtGui.QLabel("Algorithm is <b>stopped</b>") self.statusBar().addPermanentWidget(self.statuslabel) self.frame.set_statuslabel(self.statuslabel) # Button to move shapes back to the right reset_button = QtGui.QPushButton('Reset', self) reset_button.clicked.connect(self.frame.reset_shapes) reset_button.resize(reset_button.sizeHint()) reset_button.setStatusTip("Move all fitted shapes to the available shapes") # Button to run algorithm run_button = QtGui.QPushButton("Run") run_button.clicked.connect(self.run_frame_widget_algorithm) run_button.setStatusTip("Run the currently selected algorithm") # Button to stop algorithm stop_button = QtGui.QPushButton("Stop") stop_button.clicked.connect(self.frame.request_stop) stop_button.setStatusTip("Stop the currently running algorithm") # Button to generate shapes generate_button = QtGui.QPushButton('Generate\nshapes', self) generate_button.clicked.connect(self.generate_shapes) generate_button.setStatusTip('Generate new shapes') # Button to shuffle shapes shuffle_button = QtGui.QPushButton("Shuffle") shuffle_button.clicked.connect(self.frame.shuffle_available_shapes) shuffle_button.setStatusTip('Shuffle available shapes') # Button to clear shapes clear_button = QtGui.QPushButton("Clear shapes") clear_button.clicked.connect(self.frame.clear_available_shapes) clear_button.setStatusTip("Clear all shapes if algorithm is not running") # Button to sort shapes sort_button = QtGui.QPushButton("Sort by size") sort_button.clicked.connect(self.sort_available_shapes) sort_button.setStatusTip("Sort the available shapes by size") # Combobox to choose algorithm algolabel = QtGui.QLabel() algolabel.setText("Algorithm:") self.algocombo = QtGui.QComboBox() self.algocombo.addItems(self.frame.get_algorithms()) self.algocombo.setStatusTip("Choose the algorithm for packing") # Checkboxes, spinboxes and labels for shape generation self.rectcheckbox = QtGui.QCheckBox() self.rectcheckbox.setText('Generate') self.rectcheckbox.setChecked(True) self.circcheckbox = QtGui.QCheckBox() self.circcheckbox.setText('Generate') self.circcheckbox.setChecked(True) self.rectspinbox = QtGui.QSpinBox() self.rectspinbox.setMinimum(0) self.rectspinbox.setMaximum(50) self.rectspinbox.setValue(5) self.circspinbox = QtGui.QSpinBox() self.circspinbox.setMinimum(0) self.circspinbox.setMaximum(50) self.circspinbox.setValue(5) self.circspinbox.accelerated = True self.circmaxspinbox = QtGui.QSpinBox() self.circmaxspinbox.setMinimum(10) self.circmaxspinbox.setMaximum(self.frame.radius * 2) self.circmaxspinbox.setValue(self.frame.radius) self.circminspinbox = QtGui.QSpinBox() self.circminspinbox.setMinimum(10) self.circminspinbox.setMaximum(self.frame.radius * 2) self.circminspinbox.setValue(10) self.circmaxspinbox.valueChanged.connect(self.cminChange) self.circminspinbox.valueChanged.connect(self.cmaxChange) self.rectmaxspinbox = QtGui.QSpinBox() self.rectmaxspinbox.setMinimum(10) self.rectmaxspinbox.setMaximum(self.frame.radius * 2) self.rectmaxspinbox.setValue(self.frame.radius) self.rectminspinbox = QtGui.QSpinBox() self.rectminspinbox.setMinimum(10) self.rectminspinbox.setMaximum(self.frame.radius * 2) self.rectminspinbox.setValue(10) self.rectmaxspinbox.valueChanged.connect(self.rminChange) self.rectminspinbox.valueChanged.connect(self.rmaxChange) rectlabel = QtGui.QLabel() rectlabel.setText("<b>rectangles</b> with sides from") circlabel = QtGui.QLabel() circlabel.setText("<b>circles</b> with diameters from") tolabel1 = QtGui.QLabel() tolabel1.setText("to") tolabel2 = QtGui.QLabel() tolabel2.setText("to") emptylabel = QtGui.QLabel() emptylabel.setText("") # Grid layout for shape generation gengrid = QtGui.QGridLayout() gengrid.addWidget(self.rectcheckbox, 0, 0) gengrid.addWidget(self.circcheckbox, 1, 0) gengrid.addWidget(self.rectspinbox, 0, 1) gengrid.addWidget(self.circspinbox, 1, 1) gengrid.addWidget(rectlabel, 0, 2) gengrid.addWidget(circlabel, 1, 2) gengrid.addWidget(self.rectminspinbox, 0, 3) gengrid.addWidget(self.circminspinbox, 1, 3) gengrid.addWidget(tolabel1, 0, 4) gengrid.addWidget(tolabel2, 1, 4) gengrid.addWidget(self.rectmaxspinbox, 0, 5) gengrid.addWidget(self.circmaxspinbox, 1, 5) gengrid.addWidget(generate_button, 0, 6, 2, 1) gengrid.addWidget(emptylabel, 0, 7) gengrid.setColumnStretch(7, 1) # HBox for run, stop and reset buttons hbox = QtGui.QHBoxLayout() hbox.addWidget(run_button) hbox.addWidget(stop_button) hbox.addWidget(reset_button) hbox.addStretch(1) # HBox for algorithm combobox and label hboxalgo = QtGui.QHBoxLayout() hboxalgo.addWidget(algolabel) hboxalgo.addWidget(self.algocombo) hboxalgo.addStretch(1) # VBox for left pane vboxmain = QtGui.QVBoxLayout() vboxmain.addWidget(self.frame_widget) vboxmain.addWidget(self.info_widget) vboxmain.addLayout(hboxalgo) vboxmain.addLayout(hbox) # Checkbox for reverse sorting and HBox for buttons self.reversecheck = QtGui.QCheckBox() self.reversecheck.setText('Reverse') self.reversecheck.setChecked(False) self.reversecheck.setStatusTip("Sort in reverse") hboxshape = QtGui.QHBoxLayout() hboxshape.addWidget(self.reversecheck) hboxshape.addWidget(sort_button) hboxshape.addWidget(shuffle_button) hboxshape.addWidget(clear_button) hboxshape.addStretch(1) # ScrollArea for available_shapes_widget and VBox for right pane aswscroll = QtGui.QScrollArea() aswscroll.setWidget(self.available_shapes_widget) aswscroll.setMinimumWidth(430) aswscroll.setWidgetResizable(True) vboxright = QtGui.QVBoxLayout() vboxright.addWidget(aswscroll) vboxright.addLayout(hboxshape) vboxright.addLayout(gengrid) # HBox to split UI in two panes hboxmain = QtGui.QHBoxLayout() hboxmain.addLayout(vboxmain) hboxmain.addLayout(vboxright) hboxmain.setStretch(1,1) # Central widget self.centralWidget().setLayout(hboxmain) # Set window title and show main window first and widgets after that # to avoid extra windows popping up self.setWindowTitle('Packman') self.show() self.center() self.frame_widget.show() self.available_shapes_widget.show() self.info_widget.show() def run_frame_widget_algorithm(self): ''' Call frame.run_algorithm with the appropriate algorithm index and change the permanent label in the statusbar to show that an algorithm is running''' self.frame.run_algorithm(self.algocombo.currentIndex()) self.statuslabel.setText("Algorithm is <b>running</b>") def generate_shapes(self): ''' Call frame.generate_shapes with the appropriate parameters as set by the user in the interface. ''' if not self.rectcheckbox.isChecked(): num_rects = 0 else: num_rects = self.rectspinbox.value() if not self.circcheckbox.isChecked(): num_circs = 0 else: num_circs = self.circspinbox.value() self.frame.generate_shapes(num_rects, num_circs, self.rectminspinbox.value(), self.rectmaxspinbox.value(), self.circminspinbox.value(), self.circmaxspinbox.value()) def sort_available_shapes(self): ''' Call frame.sort_available_shapes with the appropriate parameter to tell if shapes should be sorted descending by size or ascending by size ''' self.frame.sort_available_shapes(not self.reversecheck.isChecked()) def cminChange(self, cmax): ''' Set value of min circle number spinbox to the value of the max circle number spinbox if the latter is smaller than the former. ''' self.circminspinbox.setValue(min(self.circminspinbox.value(), cmax)) def cmaxChange(self, cmin): ''' Set value of max circle number spinbox to the value of the min circle number spinbox if the latter is greater than the former. ''' self.circmaxspinbox.setValue(max(cmin, self.circmaxspinbox.value())) def rminChange(self, rmax): ''' Set value of min rectangle number spinbox to the value of the max circle number spinbox if the latter is smaller than the former. ''' self.rectminspinbox.setValue(min(self.rectminspinbox.value(), rmax)) def rmaxChange(self, rmin): ''' Set value of max rectangle number spinbox to the value of the min circle number spinbox if the latter is greater than the former. ''' self.rectmaxspinbox.setValue(max(rmin, self.rectmaxspinbox.value())) def closeEvent(self, event): ''' Called when trying to close programme. Shows a dialog box asking the user to confirm the decision. ''' reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure you want to quit?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: self.frame.request_end() event.accept() else: event.ignore() def keyPressEvent(self, e): ''' Called when Escape is pressed to close programme. ''' if e.key() == QtCore.Qt.Key_Escape: self.close() def center(self): ''' Center self on screen. ''' qr = self.frameGeometry() cp = QtGui.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())