def __init__(self, parent, top): super(QWidget, self).__init__(parent) self.top = top hlayout = QHBoxLayout() self.layout = QGridLayout() hlayout.addLayout(self.layout) hlayout.setAlignment(hlayout, Qt.Alignment.AlignTop) self.setLayout(hlayout) self.row = 0 self.__addLabel__("Gateway Services") self.__addLabel__("Gateway Host Name/IP Address") self.gatewayHostName = QLineEdit(self) self.__addInput__(self.gatewayHostName) self.__addLabel__("Exercise Data Server Host Name/IP Address") self.productionEDS = QLineEdit(self) self.prodEnable = QRadioButton("Production") self.prodEnable.setChecked(True) self.prodEnable.toggled.connect(self.radioProdClicked) self.prodEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.productionEDS, self.prodEnable) self.testEDS = QLineEdit(self) self.testEnable = QRadioButton("Test") self.testEnable.toggled.connect(self.radioTestClicked) self.testEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.testEDS, self.testEnable) self.__addLabel__("Messaging Port") self.messagePort = QLineEdit("61616") self.__addInput__(self.messagePort)
def __init__(self): super(MainWidget, self).__init__() self.resize(500, 600) self.setWindowTitle("喜马拉雅下载 by[Zero] " + __VERSION__) self.mainlayout = QVBoxLayout() self.setLayout(self.mainlayout) self.groupbox = QGroupBox("选择类型") self.groupbox.setFixedHeight(50) hlayout = QHBoxLayout(self.groupbox) self.signal_m4a = QRadioButton("单个下载") self.mut_m4a = QRadioButton("专辑下载") self.vip_signal_m4a = QRadioButton("VIP单个下载") self.vip_m4a = QRadioButton("VIP专辑下载") hlayout.addWidget(self.signal_m4a) hlayout.addWidget(self.mut_m4a) hlayout.addWidget(self.vip_signal_m4a) hlayout.addWidget(self.vip_m4a) self.mainlayout.addWidget(self.groupbox) frame01 = QFrame(self) child_layout = QVBoxLayout() print(self.width()) label01 = QLabel("链 接", self) label02 = QLabel("下载目录", self) self.url_lineedit = QLineEdit(self) self.dir_lineedit = QLineEdit(self) hlayout01 = QHBoxLayout() hlayout01.addWidget(label01, 1) hlayout01.addWidget(self.url_lineedit, 9) hlayout02 = QHBoxLayout() hlayout02.addWidget(label02, 1) hlayout02.addWidget(self.dir_lineedit, 9) child_layout.addLayout(hlayout01) child_layout.addLayout(hlayout02) child_layout.setContentsMargins( 5, 0, 5, 0) #(int left, int top, int right, int bottom) frame01.setLayout(child_layout) self.download_progressbar = QProgressBar() self.download_progressbar.setAlignment( QtCore.Qt.Alignment.AlignCenter) #文字居中 self.download_progressbar.setValue(88) self.download_btn = QPushButton("开始下载") self.show_plaintextedit = QPlainTextEdit() self.show_plaintextedit.setMinimumHeight(400) self.mainlayout.addWidget(frame01) self.mainlayout.addWidget(self.download_progressbar) self.mainlayout.addWidget(self.download_btn) self.mainlayout.addWidget(self.show_plaintextedit) self.mainlayout.addStretch() ### 设置stylesheet self.download_btn.setStyleSheet( 'QPushButton:pressed{ text-align: center;background-color:red;}')
class SettingsDialog(QDialog): def __init__(self): """ Dialog to manage the settings of the application """ super().__init__() self.setWindowTitle("Settings") self.setFixedSize(310, 250) # Create the general settings widgets for managing the text color, # text alignment, and author of the app's content # NOTE: Altering the default CSS attributes, such as the color, of a # widget can change its appearance. Hence, the button may appear # rectangular depending upon your platform self.text_color_button = QPushButton() self.text_color_button.setStyleSheet( "background-color: #000000") # Black self.text_color_button.clicked.connect(self.selectTextColor) self.align_left = QRadioButton(text="Left") # Default self.align_left.setChecked(True) self.align_center = QRadioButton(text="Center") self.align_center.setChecked(False) self.align_right = QRadioButton(text="Right") self.align_right.setChecked(False) # Layout and container for alignment radio buttons align_v_box = QVBoxLayout() align_v_box.setContentsMargins(0, 5, 0, 0) align_v_box.addWidget(self.align_left) align_v_box.addWidget(self.align_center) align_v_box.addWidget(self.align_right) align_frame = QFrame() align_frame.setFrameShape(QFrame.Shape.NoFrame) align_frame.setLayout(align_v_box) self.author_name = QLineEdit() self.author_name.setMinimumWidth(160) self.button_box = QDialogButtonBox( QDialogButtonBox.StandardButtons.Ok | QDialogButtonBox.StandardButtons.Cancel) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) dialog_layout = QFormLayout() dialog_layout.addRow("<b>Text Color:</b>", self.text_color_button) dialog_layout.addRow(HorizontalSeparator()) dialog_layout.addRow("<b>Text Alignment:</b>", align_frame) dialog_layout.addRow(HorizontalSeparator()) dialog_layout.addRow("<b>Author:</b>", self.author_name) dialog_layout.addWidget(self.button_box) self.setLayout(dialog_layout) def selectTextColor(self): """Change the background color of the QPushButton to reflect the selected color. This is used to set the text color of the main window's QLineEdit.""" color = QColorDialog.getColor() # Returns QColor object # Use color.name() to get the color in the format "#RRGGBB" self.text_color_button.setStyleSheet( f"background-color: {color.name()}")
def initGui(self): self.setWindowTitle('Selección de vuelo.') self.setFixedSize(500, 400) self.lbl_seleccion_vuelo = QLabel('Seleccione la clase de su vuelo:', self) self.lbl_seleccion_vuelo.move(50, 70) self.lbl_seleccion_vuelo.setFixedWidth(200) self.rbtn_1_clase = QRadioButton('Primera Clase.', self) self.rbtn_1_clase.move(50, 130) self.rbtn_1_clase.setFixedWidth(250) self.rbtn_1_clase.toggled.connect(self.seleccionar_clase) self.rbtn_2_clase = QRadioButton('Clase Negocios. ', self) self.rbtn_2_clase.move(50, 160) self.rbtn_2_clase.setFixedWidth(250) self.rbtn_2_clase.toggled.connect(self.seleccionar_clase) self.rbtn_3_clase = QRadioButton('Clase Económica.', self) self.rbtn_3_clase.move(50, 190) self.rbtn_3_clase.setFixedWidth(250) self.rbtn_3_clase.toggled.connect(self.seleccionar_clase) self.lbl_resultado_titulo = QLabel('Resultado:', self) self.lbl_resultado_titulo.move(50, 250) self.lbl_resultado = QLabel(self) self.lbl_resultado.move(50, 280) self.lbl_resultado.setFixedWidth(400)
def enterQuestionCodePageUI(self): layout = QFormLayout() self.enterQuestionCodePage.currPlayerTurnDisplay = QLabel() layout.addRow(self.enterQuestionCodePage.currPlayerTurnDisplay) enterColorLayout = QFormLayout() enterColorButtonGroup = QButtonGroup(self.enterQuestionCodePage) self.enterQuestionCodePage.yellowRadio = QRadioButton() self.enterQuestionCodePage.blueRadio = QRadioButton() self.enterQuestionCodePage.redRadio = QRadioButton() self.enterQuestionCodePage.yellowRadio.toggled.connect( self.enterColorRadioToggle) self.enterQuestionCodePage.blueRadio.toggled.connect( self.enterColorRadioToggle) self.enterQuestionCodePage.redRadio.toggled.connect( self.enterColorRadioToggle) enterColorButtonGroup.addButton(self.enterQuestionCodePage.yellowRadio) enterColorButtonGroup.addButton(self.enterQuestionCodePage.blueRadio) enterColorButtonGroup.addButton(self.enterQuestionCodePage.redRadio) enterColorLayout.addRow("Yellow", self.enterQuestionCodePage.yellowRadio) enterColorLayout.addRow("Blue", self.enterQuestionCodePage.blueRadio) enterColorLayout.addRow("Red", self.enterQuestionCodePage.redRadio) combLayout = QHBoxLayout() combLayout.addLayout(enterColorLayout) layout.addRow(combLayout) self.enterQuestionCodePage.submitQuestionCodeButton = QPushButton( "&Submit Code!") self.enterQuestionCodePage.submitQuestionCodeButton.clicked.connect( self.submitQuestionCode) layout.addRow(self.enterQuestionCodePage.submitQuestionCodeButton) self.enterQuestionCodePage.setLayout(layout)
def __init__(self): super(Window, self).__init__() self.groupBox = QGroupBox("What is your favorite sport ?") self.radiobtn3 = QRadioButton("BasketBall") self.radiobtn3.setIcon(QIcon("")) self.radiobtn2 = QRadioButton("Swimming") self.radiobtn2.setIcon(QIcon("")) self.radiobtn1 = QRadioButton("FootBall") self.radiobtn1.setIcon(QIcon("")) self.label = QLabel("You Have Selected FootBall") self.title = " " self.left = 100 self.top = 200 self.width = 400 self.height = 300 self.InitWindow()
class Services(QWidget): def __init__(self, parent, top): super(QWidget, self).__init__(parent) self.top = top hlayout = QHBoxLayout() self.layout = QGridLayout() hlayout.addLayout(self.layout) hlayout.setAlignment(hlayout, Qt.Alignment.AlignTop) self.setLayout(hlayout) self.row = 0 self.__addLabel__("Gateway Services") self.__addLabel__("Gateway Host Name/IP Address") self.gatewayHostName = QLineEdit(self) self.__addInput__(self.gatewayHostName) self.__addLabel__("Exercise Data Server Host Name/IP Address") self.productionEDS = QLineEdit(self) self.prodEnable = QRadioButton("Production") self.prodEnable.setChecked(True) self.prodEnable.toggled.connect(self.radioProdClicked) self.prodEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.productionEDS, self.prodEnable) self.testEDS = QLineEdit(self) self.testEnable = QRadioButton("Test") self.testEnable.toggled.connect(self.radioTestClicked) self.testEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.testEDS, self.testEnable) self.__addLabel__("Messaging Port") self.messagePort = QLineEdit("61616") self.__addInput__(self.messagePort) def radioProdClicked(self): if self.sender().isChecked(): self.testEnable.setChecked(False) def radioTestClicked(self): if self.sender().isChecked(): self.prodEnable.setChecked(False) def __addLabel__(self, label): lbl = QLabel(label) self.layout.addWidget(lbl, self.row, 0, 1, -1) self.row += 1 def __addInput__(self, input): self.layout.addWidget(input, self.row, 0, 1, 4) self.row += 1 def __addInputAndRadio__(self, input, radio): hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.addWidget(input) hbox.addWidget(radio) widget = QWidget(self) widget.setLayout(hbox) self.layout.addWidget(widget, self.row, 0, 1, -1) self.row += 1 def tabName(self): return 'Services'
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) # region Create CartPole instance and load initial settings # Create CartPole instance self.initial_state = create_cartpole_state() self.CartPoleInstance = CartPole(initial_state=self.initial_state) # Set timescales self.CartPoleInstance.dt_simulation = dt_simulation self.CartPoleInstance.dt_controller = controller_update_interval self.CartPoleInstance.dt_save = save_interval # set other settings self.CartPoleInstance.set_controller(controller_init) self.CartPoleInstance.stop_at_90 = stop_at_90_init self.set_random_experiment_generator_init_params() # endregion # region Decide whether to save the data in "CartPole memory" or not self.save_history = save_history_init self.show_experiment_summary = show_experiment_summary_init if self.save_history or self.show_experiment_summary: self.CartPoleInstance.save_data_in_cart = True else: self.CartPoleInstance.save_data_in_cart = False # endregion # region Other variables initial values as provided in gui_default_parameters.py # Start user controlled experiment/ start random experiment/ load and replay - on start button self.simulator_mode = simulator_mode_init self.slider_on_click = slider_on_click_init # Update slider on click/update slider while hoovering over it self.speedup = speedup_init # Default simulation speed-up # endregion # region Initialize loop-timer # This timer allows to relate the simulation time to user time # And (if your computer is fast enough) run simulation # slower or faster than real-time by predefined factor (speedup) self.looper = loop_timer( dt_target=(self.CartPoleInstance.dt_simulation / self.speedup)) # endregion # region Variables controlling the state of various processes (DO NOT MODIFY) self.terminate_experiment_or_replay_thread = False # True: gives signal causing thread to terminate self.pause_experiment_or_replay_thread = False # True: gives signal causing the thread to pause self.run_set_labels_thread = True # True if gauges (labels) keep being repeatedly updated # Stop threads by setting False # Flag indicating if the "START! / STOP!" button should act as start or as stop when pressed. # Can take values "START!" or "STOP!" self.start_or_stop_action = "START!" # Flag indicating whether the pause button should pause or unpause. self.pause_or_unpause_action = "PAUSE" # Flag indicating that saving of experiment recording to csv file has finished self.experiment_or_replay_thread_terminated = False self.user_time_counter = 0 # Measures the user time # Slider instant value (which is draw in GUI) differs from value saved in CartPole instance # if the option updating slider "on-click" is enabled. self.slider_instant_value = self.CartPoleInstance.slider_value self.noise = 'OFF' self.CartPoleInstance.NoiseAdderInstance.noise_mode = self.noise # endregion # region Create GUI Layout # region - Create container for top level layout layout = QVBoxLayout() # endregion # region - Change geometry of the main window self.setGeometry(300, 300, 2500, 1000) # endregion # region - Matplotlib figures (CartPole drawing and Slider) # Draw Figure self.fig = Figure( figsize=(25, 10) ) # Regulates the size of Figure in inches, before scaling to window size. self.canvas = FigureCanvas(self.fig) self.fig.AxCart = self.canvas.figure.add_subplot(211) self.fig.AxSlider = self.canvas.figure.add_subplot(212) self.fig.AxSlider.set_ylim(0, 1) self.CartPoleInstance.draw_constant_elements(self.fig, self.fig.AxCart, self.fig.AxSlider) # Attach figure to the layout lf = QVBoxLayout() lf.addWidget(self.canvas) # endregion # region - Radio buttons selecting current controller self.rbs_controllers = [] for controller_name in self.CartPoleInstance.controller_names: self.rbs_controllers.append(QRadioButton(controller_name)) # Ensures that radio buttons are exclusive self.controllers_buttons_group = QButtonGroup() for button in self.rbs_controllers: self.controllers_buttons_group.addButton(button) lr_c = QVBoxLayout() lr_c.addStretch(1) for rb in self.rbs_controllers: rb.clicked.connect(self.RadioButtons_controller_selection) lr_c.addWidget(rb) lr_c.addStretch(1) self.rbs_controllers[self.CartPoleInstance.controller_idx].setChecked( True) # endregion # region - Create central part of the layout for figures and radio buttons and add it to the whole layout lc = QHBoxLayout() lc.addLayout(lf) lc.addLayout(lr_c) layout.addLayout(lc) # endregion # region - Gauges displaying current values of various states and parameters (time, velocity, angle,...) # First row ld = QHBoxLayout() # User time self.labTime = QLabel("User's time (s): ") self.timer = QTimer() self.timer.setInterval(100) # Tick every 1/10 of the second self.timer.timeout.connect(self.set_user_time_label) self.timer.start() ld.addWidget(self.labTime) # Speed, angle, motor power (Q) self.labSpeed = QLabel('Speed (m/s):') self.labAngle = QLabel('Angle (deg):') self.labMotor = QLabel('') self.labTargetPosition = QLabel('') ld.addWidget(self.labSpeed) ld.addWidget(self.labAngle) ld.addWidget(self.labMotor) ld.addWidget(self.labTargetPosition) layout.addLayout(ld) # Second row of labels # Simulation time, Measured (real) speed-up, slider-value ld2 = QHBoxLayout() self.labTimeSim = QLabel('Simulation Time (s):') ld2.addWidget(self.labTimeSim) self.labSpeedUp = QLabel('Speed-up (measured):') ld2.addWidget(self.labSpeedUp) self.labSliderInstant = QLabel('') ld2.addWidget(self.labSliderInstant) layout.addLayout(ld2) # endregion # region - Buttons "START!" / "STOP!", "PAUSE", "QUIT" self.bss = QPushButton("START!") self.bss.pressed.connect(self.start_stop_button) self.bp = QPushButton("PAUSE") self.bp.pressed.connect(self.pause_unpause_button) bq = QPushButton("QUIT") bq.pressed.connect(self.quit_application) lspb = QHBoxLayout() # Sub-Layout for Start/Stop and Pause Buttons lspb.addWidget(self.bss) lspb.addWidget(self.bp) # endregion # region - Sliders setting initial state and buttons for kicking the pole # Sliders setting initial position and angle lb = QVBoxLayout() # Layout for buttons lb.addLayout(lspb) lb.addWidget(bq) ip = QHBoxLayout() # Layout for initial position sliders self.initial_position_slider = QSlider( orientation=Qt.Orientation.Horizontal) self.initial_position_slider.setRange( -int(float(1000 * TrackHalfLength)), int(float(1000 * TrackHalfLength))) self.initial_position_slider.setValue(0) self.initial_position_slider.setSingleStep(1) self.initial_position_slider.valueChanged.connect( self.update_initial_position) self.initial_angle_slider = QSlider( orientation=Qt.Orientation.Horizontal) self.initial_angle_slider.setRange(-int(float(100 * np.pi)), int(float(100 * np.pi))) self.initial_angle_slider.setValue(0) self.initial_angle_slider.setSingleStep(1) self.initial_angle_slider.valueChanged.connect( self.update_initial_angle) ip.addWidget(QLabel("Initial position:")) ip.addWidget(self.initial_position_slider) ip.addWidget(QLabel("Initial angle:")) ip.addWidget(self.initial_angle_slider) ip.addStretch(0.01) # Slider setting latency self.LATENCY_SLIDER_RANGE_INT = 1000 self.latency_slider = QSlider(orientation=Qt.Orientation.Horizontal) self.latency_slider.setRange(0, self.LATENCY_SLIDER_RANGE_INT) self.latency_slider.setValue( int(self.CartPoleInstance.LatencyAdderInstance.latency * self.LATENCY_SLIDER_RANGE_INT / self.CartPoleInstance.LatencyAdderInstance.max_latency)) self.latency_slider.setSingleStep(1) self.latency_slider.valueChanged.connect(self.update_latency) ip.addWidget(QLabel("Latency:")) ip.addWidget(self.latency_slider) self.labLatency = QLabel('Latency (ms): {:.1f}'.format( self.CartPoleInstance.LatencyAdderInstance.latency * 1000)) ip.addWidget(self.labLatency) # Buttons activating noise self.rbs_noise = [] for mode_name in ['ON', 'OFF']: self.rbs_noise.append(QRadioButton(mode_name)) # Ensures that radio buttons are exclusive self.noise_buttons_group = QButtonGroup() for button in self.rbs_noise: self.noise_buttons_group.addButton(button) lr_n = QHBoxLayout() lr_n.addWidget(QLabel('Noise:')) for rb in self.rbs_noise: rb.clicked.connect(self.RadioButtons_noise_on_off) lr_n.addWidget(rb) self.rbs_noise[1].setChecked(True) ip.addStretch(0.01) ip.addLayout(lr_n) ip.addStretch(0.01) # Buttons giving kick to the pole kick_label = QLabel("Kick pole:") kick_left_button = QPushButton() kick_left_button.setText("Left") kick_left_button.adjustSize() kick_left_button.clicked.connect(self.kick_pole) kick_right_button = QPushButton() kick_right_button.setText("Right") kick_right_button.adjustSize() kick_right_button.clicked.connect(self.kick_pole) ip.addWidget(kick_label) ip.addWidget(kick_left_button) ip.addWidget(kick_right_button) lb.addLayout(ip) layout.addLayout(lb) # endregion # region - Text boxes and Combobox to provide settings concerning generation of random experiment l_generate_trace = QHBoxLayout() l_generate_trace.addWidget(QLabel('Random experiment settings:')) l_generate_trace.addWidget(QLabel('Length (s):')) self.textbox_length = QLineEdit() l_generate_trace.addWidget(self.textbox_length) l_generate_trace.addWidget(QLabel('Turning Points (m):')) self.textbox_turning_points = QLineEdit() l_generate_trace.addWidget(self.textbox_turning_points) l_generate_trace.addWidget(QLabel('Interpolation:')) self.cb_interpolation = QComboBox() self.cb_interpolation.addItems( ['0-derivative-smooth', 'linear', 'previous']) self.cb_interpolation.currentIndexChanged.connect( self.cb_interpolation_selectionchange) self.cb_interpolation.setCurrentText( self.CartPoleInstance.interpolation_type) l_generate_trace.addWidget(self.cb_interpolation) layout.addLayout(l_generate_trace) # endregion # region - Textbox to provide csv file name for saving or loading data l_text = QHBoxLayout() textbox_title = QLabel('CSV file name:') self.textbox = QLineEdit() l_text.addWidget(textbox_title) l_text.addWidget(self.textbox) layout.addLayout(l_text) # endregion # region - Make strip of layout for checkboxes l_cb = QHBoxLayout() # endregion # region - Textbox to provide the target speed-up value l_text_speedup = QHBoxLayout() tx_speedup_title = QLabel('Speed-up (target):') self.tx_speedup = QLineEdit() l_text_speedup.addWidget(tx_speedup_title) l_text_speedup.addWidget(self.tx_speedup) self.tx_speedup.setText(str(self.speedup)) l_cb.addLayout(l_text_speedup) self.wrong_speedup_msg = QMessageBox() self.wrong_speedup_msg.setWindowTitle("Speed-up value problem") self.wrong_speedup_msg.setIcon(QMessageBox.Icon.Critical) # endregion # region - Checkboxes # region -- Checkbox: Save/don't save experiment recording self.cb_save_history = QCheckBox('Save results', self) if self.save_history: self.cb_save_history.toggle() self.cb_save_history.toggled.connect(self.cb_save_history_f) l_cb.addWidget(self.cb_save_history) # endregion # region -- Checkbox: Display plots showing dynamic evolution of the system as soon as experiment terminates self.cb_show_experiment_summary = QCheckBox('Show experiment summary', self) if self.show_experiment_summary: self.cb_show_experiment_summary.toggle() self.cb_show_experiment_summary.toggled.connect( self.cb_show_experiment_summary_f) l_cb.addWidget(self.cb_show_experiment_summary) # endregion # region -- Checkbox: Block pole if it reaches +/-90 deg self.cb_stop_at_90_deg = QCheckBox('Stop-at-90-deg', self) if self.CartPoleInstance.stop_at_90: self.cb_stop_at_90_deg.toggle() self.cb_stop_at_90_deg.toggled.connect(self.cb_stop_at_90_deg_f) l_cb.addWidget(self.cb_stop_at_90_deg) # endregion # region -- Checkbox: Update slider on click/update slider while hoovering over it self.cb_slider_on_click = QCheckBox('Update slider on click', self) if self.slider_on_click: self.cb_slider_on_click.toggle() self.cb_slider_on_click.toggled.connect(self.cb_slider_on_click_f) l_cb.addWidget(self.cb_slider_on_click) # endregion # endregion # region - Radio buttons selecting simulator mode: user defined experiment, random experiment, replay # List available simulator modes - constant self.available_simulator_modes = [ 'Slider-Controlled Experiment', 'Random Experiment', 'Replay' ] self.rbs_simulator_mode = [] for mode_name in self.available_simulator_modes: self.rbs_simulator_mode.append(QRadioButton(mode_name)) # Ensures that radio buttons are exclusive self.simulator_mode_buttons_group = QButtonGroup() for button in self.rbs_simulator_mode: self.simulator_mode_buttons_group.addButton(button) lr_sm = QHBoxLayout() lr_sm.addStretch(1) lr_sm.addWidget(QLabel('Simulator mode:')) for rb in self.rbs_simulator_mode: rb.clicked.connect(self.RadioButtons_simulator_mode) lr_sm.addWidget(rb) lr_sm.addStretch(1) self.rbs_simulator_mode[self.available_simulator_modes.index( self.simulator_mode)].setChecked(True) l_cb.addStretch(1) l_cb.addLayout(lr_sm) l_cb.addStretch(1) # endregion # region - Add checkboxes to layout layout.addLayout(l_cb) # endregion # region - Create an instance of a GUI window w = QWidget() w.setLayout(layout) self.setCentralWidget(w) self.show() self.setWindowTitle('CartPole Simulator') # endregion # endregion # region Open controller-specific popup windows self.open_additional_controller_widget() # endregion # region Activate functions capturing mouse movements and clicks over the slider # This line links function capturing the mouse position on the canvas of the Figure self.canvas.mpl_connect("motion_notify_event", self.on_mouse_movement) # This line links function capturing the mouse position on the canvas of the Figure click self.canvas.mpl_connect("button_press_event", self.on_mouse_click) # endregion # region Introducing multithreading # To ensure smooth functioning of the app, # the calculations and redrawing of the figures have to be done in a different thread # than the one capturing the mouse position and running the animation self.threadpool = QThreadPool() # endregion # region Starts a thread repeatedly redrawing gauges (labels) of the GUI # It runs till the QUIT button is pressed worker_labels = Worker(self.set_labels_thread) self.threadpool.start(worker_labels) # endregion # region Start animation repeatedly redrawing changing elements of matplotlib figures (CartPole drawing and slider) # This animation runs ALWAYS when the GUI is open # The buttons of GUI only decide if new parameters are calculated or not self.anim = self.CartPoleInstance.run_animation(self.fig)
class Window(QDialog): def __init__(self): super(Window, self).__init__() self.groupBox = QGroupBox("What is your favorite sport ?") self.radiobtn3 = QRadioButton("BasketBall") self.radiobtn3.setIcon(QIcon("")) self.radiobtn2 = QRadioButton("Swimming") self.radiobtn2.setIcon(QIcon("")) self.radiobtn1 = QRadioButton("FootBall") self.radiobtn1.setIcon(QIcon("")) self.label = QLabel("You Have Selected FootBall") self.title = " " self.left = 100 self.top = 200 self.width = 400 self.height = 300 self.InitWindow() def InitWindow(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.radioButton() vbox = QVBoxLayout() vbox.addWidget(self.groupBox) vbox.addWidget(self.label) self.setLayout(vbox) self.show() def radioButton(self): hbox = QHBoxLayout() self.radiobtn1.setChecked(True) self.radiobtn1.toggled.connect(self.OnRadioButton) hbox.addWidget(self.radiobtn1) self.radiobtn2.setChecked(False) self.radiobtn2.toggled.connect(self.OnRadioButton) hbox.addWidget(self.radiobtn2) self.radiobtn3.setChecked(False) self.radiobtn2.toggled.connect(self.OnRadioButton) hbox.addWidget(self.radiobtn3) self.groupBox.setLayout(hbox) def OnRadioButton(self): # Which radioBtn send message radioBtn = self.sender() if radioBtn.isChecked(): self.label.setText("You Have Selected " + radioBtn.text())
class ventanaPrincipal(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.initGui() def initGui(self): self.setWindowTitle('Selección de vuelo.') self.setFixedSize(500, 400) self.lbl_seleccion_vuelo = QLabel('Seleccione la clase de su vuelo:', self) self.lbl_seleccion_vuelo.move(50, 70) self.lbl_seleccion_vuelo.setFixedWidth(200) self.rbtn_1_clase = QRadioButton('Primera Clase.', self) self.rbtn_1_clase.move(50, 130) self.rbtn_1_clase.setFixedWidth(250) self.rbtn_1_clase.toggled.connect(self.seleccionar_clase) self.rbtn_2_clase = QRadioButton('Clase Negocios. ', self) self.rbtn_2_clase.move(50, 160) self.rbtn_2_clase.setFixedWidth(250) self.rbtn_2_clase.toggled.connect(self.seleccionar_clase) self.rbtn_3_clase = QRadioButton('Clase Económica.', self) self.rbtn_3_clase.move(50, 190) self.rbtn_3_clase.setFixedWidth(250) self.rbtn_3_clase.toggled.connect(self.seleccionar_clase) self.lbl_resultado_titulo = QLabel('Resultado:', self) self.lbl_resultado_titulo.move(50, 250) self.lbl_resultado = QLabel(self) self.lbl_resultado.move(50, 280) self.lbl_resultado.setFixedWidth(400) def seleccionar_clase(self): costo_vuelo = 0 clase = '' if self.rbtn_1_clase.isChecked(): costo_vuelo = '2.000.0' clase = 'Primera Clase' elif self.rbtn_2_clase.isChecked(): costo_vuelo = '1.500.0' clase = 'Clase de Negocios' elif self.rbtn_3_clase.isChecked(): costo_vuelo = '1.000.0' clase = 'Clase Económica' self.lbl_resultado.setText( f'El costo de su tiquete de {clase}, es de USD ${costo_vuelo}')
def __init__(self): super(MPPIOptionsWindow, self).__init__() self.horizon_steps = controller_mppi.mpc_samples self.num_rollouts = controller_mppi.num_rollouts self.dd_weight = controller_mppi.dd_weight self.ep_weight = controller_mppi.ep_weight self.ekp_weight = controller_mppi.ekp_weight * 1.0e1 self.ekc_weight = controller_mppi.ekc_weight * 1.0e-1 self.cc_weight = controller_mppi.cc_weight * 1.0e-2 self.ccrc_weight = controller_mppi.ccrc_weight * 1.0e-2 self.R = controller_mppi.R # How much to punish Q self.LBD = controller_mppi.LBD # Cost parameter lambda self.NU = controller_mppi.NU # Exploration variance layout = QVBoxLayout() ### Set Horizon Length horizon_options_layout = QVBoxLayout() self.horizon_label = QLabel("") self.horizon_label.setAlignment(Qt.AlignmentFlag.AlignCenter) horizon_options_layout.addWidget(self.horizon_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(10, 300) slider.setValue(self.horizon_steps) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(10) slider.setSingleStep(10) horizon_options_layout.addWidget(slider) slider.valueChanged.connect(self.horizon_length_changed) ### Set Number of Rollouts rollouts_options_layout = QVBoxLayout() self.rollouts_label = QLabel("") self.rollouts_label.setAlignment(Qt.AlignmentFlag.AlignCenter) rollouts_options_layout.addWidget(self.rollouts_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(10, 3000) slider.setValue(self.num_rollouts) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(10) slider.setSingleStep(10) rollouts_options_layout.addWidget(slider) slider.valueChanged.connect(self.num_rollouts_changed) ### Set Cost Weights cost_weight_layout = QVBoxLayout() # Distance difference cost self.dd_weight_label = QLabel("") self.dd_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.dd_weight_label) self.dd_label = QLabel("") self.dd_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.dd_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 990) slider.setValue(self.dd_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(10) slider.setSingleStep(10) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.dd_weight_changed) # Potential energy cost self.ep_weight_label = QLabel("") self.ep_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ep_weight_label) self.ep_label = QLabel("") self.ep_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ep_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 1e5 - 1e3) slider.setValue(self.ep_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(1e3) slider.setSingleStep(1e3) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.ep_weight_changed) # Pole kinetic energy cost self.ekp_weight_label = QLabel("") self.ekp_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ekp_weight_label) self.ekp_label = QLabel("") self.ekp_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ekp_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 99) slider.setValue(self.ekp_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(1) slider.setSingleStep(1) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.ekp_weight_changed) # Cart kinetic energy cost self.ekc_weight_label = QLabel("") self.ekc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ekc_weight_label) self.ekc_label = QLabel("") self.ekc_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ekc_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 99) slider.setValue(self.ekc_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(1) slider.setSingleStep(1) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.ekc_weight_changed) # Control cost self.cc_weight_label = QLabel("") self.cc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.cc_weight_label) self.cc_label = QLabel("") self.cc_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.cc_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 99) slider.setValue(self.cc_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(1) slider.setSingleStep(1) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.cc_weight_changed) # Control change rate cost self.ccrc_weight_label = QLabel("") self.ccrc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ccrc_weight_label) self.ccrc_label = QLabel("") self.ccrc_label.setAlignment(Qt.AlignmentFlag.AlignCenter) cost_weight_layout.addWidget(self.ccrc_label) slider = QSlider(orientation=Qt.Orientation.Horizontal) slider.setRange(0, 99) slider.setValue(self.ccrc_weight) slider.setTickPosition(QSlider.TickPosition.TicksBelow) slider.setTickInterval(1) slider.setSingleStep(1) cost_weight_layout.addWidget(slider) slider.valueChanged.connect(self.ccrc_weight_changed) ### Set some more MPPI constants mppi_constants_layout = QVBoxLayout() # Quadratic cost penalty R textbox = QLineEdit() textbox.setText(str(self.R)) textbox.textChanged.connect(self.R_changed) h_layout = QHBoxLayout() h_layout.addWidget(QLabel("Quadratic input cost penalty R =")) h_layout.addWidget(textbox) mppi_constants_layout.addLayout(h_layout) # Quadratic cost penalty LBD textbox = QLineEdit() textbox.setText(str(self.LBD)) textbox.textChanged.connect(self.LBD_changed) h_layout = QHBoxLayout() h_layout.addWidget(QLabel("Importance of higher-cost rollouts LBD =")) h_layout.addWidget(textbox) mppi_constants_layout.addLayout(h_layout) # Quadratic cost penalty NU textbox = QLineEdit() textbox.setText(str(self.NU)) textbox.textChanged.connect(self.NU_changed) h_layout = QHBoxLayout() h_layout.addWidget(QLabel("Exploration variance NU =")) h_layout.addWidget(textbox) mppi_constants_layout.addLayout(h_layout) # Sampling type h_layout = QHBoxLayout() btn1 = QRadioButton("iid") if btn1.text() == controller_mppi.SAMPLING_TYPE: btn1.setChecked(True) btn1.toggled.connect(lambda: self.toggle_button(btn1)) h_layout.addWidget(btn1) btn2 = QRadioButton("random_walk") if btn2.text() == controller_mppi.SAMPLING_TYPE: btn2.setChecked(True) btn2.toggled.connect(lambda: self.toggle_button(btn2)) h_layout.addWidget(btn2) btn3 = QRadioButton("uniform") if btn3.text() == controller_mppi.SAMPLING_TYPE: btn3.setChecked(True) btn3.toggled.connect(lambda: self.toggle_button(btn3)) h_layout.addWidget(btn3) btn4 = QRadioButton("repeated") if btn4.text() == controller_mppi.SAMPLING_TYPE: btn4.setChecked(True) btn4.toggled.connect(lambda: self.toggle_button(btn4)) h_layout.addWidget(btn4) btn5 = QRadioButton("interpolated") if btn5.text() == controller_mppi.SAMPLING_TYPE: btn5.setChecked(True) btn5.toggled.connect(lambda: self.toggle_button(btn5)) h_layout.addWidget(btn5) mppi_constants_layout.addWidget(QLabel("Sampling type:")) mppi_constants_layout.addLayout(h_layout) ### Put together layout self.update_labels() self.update_slider_labels() layout.addLayout(horizon_options_layout) layout.addLayout(rollouts_options_layout) layout.addLayout(cost_weight_layout) layout.addLayout(mppi_constants_layout) self.setLayout(layout) self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint) self.setGeometry(0, 0, 400, 50) self.show() self.setWindowTitle("MPPI Options") self.timer = QTimer() self.timer.timeout.connect(self.update_labels) self.timer.start(100)
def __init__(self): super().__init__() self.setFixedSize(800, 410) self.setWindowTitle("PyLX16A Servo Testing Software") self.port_selection_box = QComboBox(self) self.port_selection_box.setFixedSize(200, 27) self.port_selection_box.move(30, 65) port_selection_box_label = QLabel("Select Port:", self) port_selection_box_label.move(30, 35) self.port_selection_box_refresh_button = QPushButton("Refresh", self) self.port_selection_box_refresh_button.setFixedSize(60, 23) self.port_selection_box_refresh_button.move(170, 38) self.id_selection_box = QListWidget(self) self.id_selection_box.setFixedSize(200, 200) self.id_selection_box.move(30, 135) id_selection_box_label = QLabel("Connected Servos:", self) id_selection_box_label.setFixedWidth(200) id_selection_box_label.move(30, 105) self.id_selection_box_refresh_button = QPushButton("Refresh", self) self.id_selection_box_refresh_button.setFixedSize(60, 23) self.id_selection_box_refresh_button.move(170, 108) self.set_id_line_edit = QLineEdit(self) self.set_id_line_edit.setFixedSize(50, 27) self.set_id_line_edit.move(80, 355) set_id_line_edit_label = QLabel("Set ID:", self) set_id_line_edit_label.move(30, 355) set_id_line_edit_label.setFixedSize(50, 27) self.set_id_button = QPushButton("Change ID!", self) self.set_id_button.setFixedSize(85, 27) self.set_id_button.move(145, 355) self.position_slider = QSlider(Qt.Orientation.Horizontal, self) self.position_slider.setMinimum(0) self.position_slider.setMaximum(240) self.position_slider.setFixedWidth(200) self.position_slider.move(300, 55) self.position_slider_readout = QLabel("0.00°", self) self.position_slider_readout.setFixedWidth(50) self.position_slider_readout.move(450, 30) self.position_slider_readout.setAlignment( Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) position_slider_label = QLabel("Angle (degrees):", self) position_slider_label.move(300, 30) self.position_offset_slider = QSlider(Qt.Orientation.Horizontal, self) self.position_offset_slider.setMinimum(-30) self.position_offset_slider.setMaximum(30) self.position_offset_slider.setFixedWidth(200) self.position_offset_slider.move(300, 125) self.position_offset_slider_readout = QLabel("0.00°", self) self.position_offset_slider_readout.setFixedWidth(50) self.position_offset_slider_readout.move(450, 100) self.position_offset_slider_readout.setAlignment( Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) position_offset_slider_label = QLabel("Angle offset (degrees):", self) position_offset_slider_label.setFixedWidth(200) position_offset_slider_label.move(300, 100) self.angle_lower_limit_textentry = QLineEdit(self) self.angle_lower_limit_textentry.setFixedWidth(50) self.angle_lower_limit_textentry.move(450, 175) self.angle_lower_limit_textentry.setValidator( QIntValidator(0, 240, self)) self.angle_upper_limit_textentry = QLineEdit(self) self.angle_upper_limit_textentry.setFixedWidth(50) self.angle_upper_limit_textentry.move(450, 210) self.angle_upper_limit_textentry.setValidator( QIntValidator(0, 240, self)) self.angle_lower_limit_textentry_label = QLabel( "Lower Limit (degrees):", self) self.angle_lower_limit_textentry_label.move(300, 175) self.angle_lower_limit_textentry_label.setFixedWidth(150) self.angle_upper_limit_textentry_label = QLabel( "Upper Limit (degrees):", self) self.angle_upper_limit_textentry_label.move(300, 210) self.angle_upper_limit_textentry_label.setFixedWidth(150) self.vin_lower_limit_textentry = QLineEdit(self) self.vin_lower_limit_textentry.setFixedWidth(50) self.vin_lower_limit_textentry.move(450, 265) self.vin_lower_limit_textentry.setValidator( QIntValidator(4500, 12000, self)) self.vin_upper_limit_textentry = QLineEdit(self) self.vin_upper_limit_textentry.setFixedWidth(50) self.vin_upper_limit_textentry.move(450, 300) self.vin_upper_limit_textentry.setValidator( QIntValidator(4500, 12000, self)) self.vin_lower_limit_textentry_label = QLabel( "Voltage Lower Limit (mV):", self) self.vin_lower_limit_textentry_label.move(300, 265) self.vin_lower_limit_textentry_label.setFixedWidth(150) self.vin_upper_limit_textentry_label = QLabel( "Voltage Upper Limit (mV):", self) self.vin_upper_limit_textentry_label.move(300, 300) self.vin_upper_limit_textentry_label.setFixedWidth(150) self.temp_limit_textentry = QLineEdit(self) self.temp_limit_textentry.setFixedWidth(50) self.temp_limit_textentry.move(450, 355) self.temp_limit_textentry.setValidator(QIntValidator(50, 100, self)) self.temp_limit_textentry_label = QLabel("Temp Limit (°C):", self) self.temp_limit_textentry_label.move(300, 355) self.temp_limit_textentry_label.setFixedWidth(150) self.servo_mode_radio_button = QRadioButton("Servo Mode", self) self.servo_mode_radio_button.move(565, 50) self.motor_mode_radio_button = QRadioButton("Motor Mode", self) self.motor_mode_radio_button.move(565, 75) self.motor_speed_slider = QSlider(Qt.Orientation.Horizontal, self) self.motor_speed_slider.setMinimum(-1000) self.motor_speed_slider.setMaximum(1000) self.motor_speed_slider.setFixedWidth(200) self.motor_speed_slider.move(565, 125) motor_speed_slider_label = QLabel("Motor Speed:", self) motor_speed_slider_label.move(565, 100) self.torque_enabled_checkbox = QCheckBox("Torque Enabled", self) self.torque_enabled_checkbox.move(565, 175) self.torque_enabled_checkbox.setFixedWidth(200) self.led_enabled_checkbox = QCheckBox("LED Enabled", self) self.led_enabled_checkbox.move(565, 210) self.led_enabled_checkbox.setFixedWidth(200) self.led_over_temp_checkbox = QCheckBox("LED Over Temperature", self) self.led_over_temp_checkbox.move(565, 258) self.led_over_temp_checkbox.setFixedWidth(200) self.led_over_voltage_checkbox = QCheckBox("LED Over Voltage", self) self.led_over_voltage_checkbox.move(565, 283) self.led_over_voltage_checkbox.setFixedWidth(200) self.led_rotor_locked_checkbox = QCheckBox("LED Rotor Locked", self) self.led_rotor_locked_checkbox.move(565, 308) self.led_rotor_locked_checkbox.setFixedWidth(200) self.physical_position_readout = QLabel("--°", self) self.physical_position_readout.move(565, 367) self.physical_position_readout.setFixedWidth(200) self.physical_position_readout_label = QLabel("Position", self) self.physical_position_readout_label.move(565, 347) self.temperature_readout = QLabel("-- °C", self) self.temperature_readout.move(635, 367) self.temperature_readout.setFixedWidth(200) self.temperature_readout_label = QLabel("Temperature", self) self.temperature_readout_label.move(635, 347) self.voltage_readout = QLabel("-- V", self) self.voltage_readout.move(730, 367) self.voltage_readout.setFixedWidth(200) self.voltage_readout_label = QLabel("Voltage", self) self.voltage_readout_label.move(730, 347) self.readout_update_timer = QTimer(self) self.readout_update_timer.timeout.connect(self.update_readouts) self.readout_update_timer.start(250) self.active_servo: LX16A = None self.position_slider.setValue(0) self.position_offset_slider.setValue(0) self.motor_speed_slider.setValue(0) self.id_selection_box_refresh_button.setEnabled(False) self.disable_widgets() self.port_selection_box.currentTextChanged.connect( self.port_selection_box_changed) self.port_selection_box_refresh_button.clicked.connect( self.port_refresh_button_clicked) self.id_selection_box.currentTextChanged.connect( self.id_selection_box_changed) self.id_selection_box_refresh_button.clicked.connect( self.id_refresh_button_clicked) self.set_id_button.pressed.connect(self.id_updated) self.position_slider.sliderMoved.connect(self.position_slider_updated) self.position_offset_slider.sliderMoved.connect( self.position_offset_slider_updated) self.angle_lower_limit_textentry.textChanged.connect( self.angle_lower_limit_updated) self.angle_upper_limit_textentry.textChanged.connect( self.angle_upper_limit_updated) self.vin_lower_limit_textentry.textChanged.connect( self.vin_lower_limit_updated) self.vin_upper_limit_textentry.textChanged.connect( self.vin_upper_limit_updated) self.temp_limit_textentry.textChanged.connect(self.temp_limit_updated) self.servo_mode_radio_button.toggled.connect( self.servo_mode_radio_button_toggled) self.motor_mode_radio_button.toggled.connect( self.motor_mode_radio_button_toggled) self.motor_speed_slider.valueChanged.connect( self.motor_speed_slider_updated) self.torque_enabled_checkbox.stateChanged.connect( self.torque_enabled_checkbox_toggled) self.led_enabled_checkbox.stateChanged.connect( self.led_enabled_checkbox_toggled) self.led_over_temp_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.led_over_voltage_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.led_rotor_locked_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.scan_for_ports()
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setFixedSize(800, 410) self.setWindowTitle("PyLX16A Servo Testing Software") self.port_selection_box = QComboBox(self) self.port_selection_box.setFixedSize(200, 27) self.port_selection_box.move(30, 65) port_selection_box_label = QLabel("Select Port:", self) port_selection_box_label.move(30, 35) self.port_selection_box_refresh_button = QPushButton("Refresh", self) self.port_selection_box_refresh_button.setFixedSize(60, 23) self.port_selection_box_refresh_button.move(170, 38) self.id_selection_box = QListWidget(self) self.id_selection_box.setFixedSize(200, 200) self.id_selection_box.move(30, 135) id_selection_box_label = QLabel("Connected Servos:", self) id_selection_box_label.setFixedWidth(200) id_selection_box_label.move(30, 105) self.id_selection_box_refresh_button = QPushButton("Refresh", self) self.id_selection_box_refresh_button.setFixedSize(60, 23) self.id_selection_box_refresh_button.move(170, 108) self.set_id_line_edit = QLineEdit(self) self.set_id_line_edit.setFixedSize(50, 27) self.set_id_line_edit.move(80, 355) set_id_line_edit_label = QLabel("Set ID:", self) set_id_line_edit_label.move(30, 355) set_id_line_edit_label.setFixedSize(50, 27) self.set_id_button = QPushButton("Change ID!", self) self.set_id_button.setFixedSize(85, 27) self.set_id_button.move(145, 355) self.position_slider = QSlider(Qt.Orientation.Horizontal, self) self.position_slider.setMinimum(0) self.position_slider.setMaximum(240) self.position_slider.setFixedWidth(200) self.position_slider.move(300, 55) self.position_slider_readout = QLabel("0.00°", self) self.position_slider_readout.setFixedWidth(50) self.position_slider_readout.move(450, 30) self.position_slider_readout.setAlignment( Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) position_slider_label = QLabel("Angle (degrees):", self) position_slider_label.move(300, 30) self.position_offset_slider = QSlider(Qt.Orientation.Horizontal, self) self.position_offset_slider.setMinimum(-30) self.position_offset_slider.setMaximum(30) self.position_offset_slider.setFixedWidth(200) self.position_offset_slider.move(300, 125) self.position_offset_slider_readout = QLabel("0.00°", self) self.position_offset_slider_readout.setFixedWidth(50) self.position_offset_slider_readout.move(450, 100) self.position_offset_slider_readout.setAlignment( Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) position_offset_slider_label = QLabel("Angle offset (degrees):", self) position_offset_slider_label.setFixedWidth(200) position_offset_slider_label.move(300, 100) self.angle_lower_limit_textentry = QLineEdit(self) self.angle_lower_limit_textentry.setFixedWidth(50) self.angle_lower_limit_textentry.move(450, 175) self.angle_lower_limit_textentry.setValidator( QIntValidator(0, 240, self)) self.angle_upper_limit_textentry = QLineEdit(self) self.angle_upper_limit_textentry.setFixedWidth(50) self.angle_upper_limit_textentry.move(450, 210) self.angle_upper_limit_textentry.setValidator( QIntValidator(0, 240, self)) self.angle_lower_limit_textentry_label = QLabel( "Lower Limit (degrees):", self) self.angle_lower_limit_textentry_label.move(300, 175) self.angle_lower_limit_textentry_label.setFixedWidth(150) self.angle_upper_limit_textentry_label = QLabel( "Upper Limit (degrees):", self) self.angle_upper_limit_textentry_label.move(300, 210) self.angle_upper_limit_textentry_label.setFixedWidth(150) self.vin_lower_limit_textentry = QLineEdit(self) self.vin_lower_limit_textentry.setFixedWidth(50) self.vin_lower_limit_textentry.move(450, 265) self.vin_lower_limit_textentry.setValidator( QIntValidator(4500, 12000, self)) self.vin_upper_limit_textentry = QLineEdit(self) self.vin_upper_limit_textentry.setFixedWidth(50) self.vin_upper_limit_textentry.move(450, 300) self.vin_upper_limit_textentry.setValidator( QIntValidator(4500, 12000, self)) self.vin_lower_limit_textentry_label = QLabel( "Voltage Lower Limit (mV):", self) self.vin_lower_limit_textentry_label.move(300, 265) self.vin_lower_limit_textentry_label.setFixedWidth(150) self.vin_upper_limit_textentry_label = QLabel( "Voltage Upper Limit (mV):", self) self.vin_upper_limit_textentry_label.move(300, 300) self.vin_upper_limit_textentry_label.setFixedWidth(150) self.temp_limit_textentry = QLineEdit(self) self.temp_limit_textentry.setFixedWidth(50) self.temp_limit_textentry.move(450, 355) self.temp_limit_textentry.setValidator(QIntValidator(50, 100, self)) self.temp_limit_textentry_label = QLabel("Temp Limit (°C):", self) self.temp_limit_textentry_label.move(300, 355) self.temp_limit_textentry_label.setFixedWidth(150) self.servo_mode_radio_button = QRadioButton("Servo Mode", self) self.servo_mode_radio_button.move(565, 50) self.motor_mode_radio_button = QRadioButton("Motor Mode", self) self.motor_mode_radio_button.move(565, 75) self.motor_speed_slider = QSlider(Qt.Orientation.Horizontal, self) self.motor_speed_slider.setMinimum(-1000) self.motor_speed_slider.setMaximum(1000) self.motor_speed_slider.setFixedWidth(200) self.motor_speed_slider.move(565, 125) motor_speed_slider_label = QLabel("Motor Speed:", self) motor_speed_slider_label.move(565, 100) self.torque_enabled_checkbox = QCheckBox("Torque Enabled", self) self.torque_enabled_checkbox.move(565, 175) self.torque_enabled_checkbox.setFixedWidth(200) self.led_enabled_checkbox = QCheckBox("LED Enabled", self) self.led_enabled_checkbox.move(565, 210) self.led_enabled_checkbox.setFixedWidth(200) self.led_over_temp_checkbox = QCheckBox("LED Over Temperature", self) self.led_over_temp_checkbox.move(565, 258) self.led_over_temp_checkbox.setFixedWidth(200) self.led_over_voltage_checkbox = QCheckBox("LED Over Voltage", self) self.led_over_voltage_checkbox.move(565, 283) self.led_over_voltage_checkbox.setFixedWidth(200) self.led_rotor_locked_checkbox = QCheckBox("LED Rotor Locked", self) self.led_rotor_locked_checkbox.move(565, 308) self.led_rotor_locked_checkbox.setFixedWidth(200) self.physical_position_readout = QLabel("--°", self) self.physical_position_readout.move(565, 367) self.physical_position_readout.setFixedWidth(200) self.physical_position_readout_label = QLabel("Position", self) self.physical_position_readout_label.move(565, 347) self.temperature_readout = QLabel("-- °C", self) self.temperature_readout.move(635, 367) self.temperature_readout.setFixedWidth(200) self.temperature_readout_label = QLabel("Temperature", self) self.temperature_readout_label.move(635, 347) self.voltage_readout = QLabel("-- V", self) self.voltage_readout.move(730, 367) self.voltage_readout.setFixedWidth(200) self.voltage_readout_label = QLabel("Voltage", self) self.voltage_readout_label.move(730, 347) self.readout_update_timer = QTimer(self) self.readout_update_timer.timeout.connect(self.update_readouts) self.readout_update_timer.start(250) self.active_servo: LX16A = None self.position_slider.setValue(0) self.position_offset_slider.setValue(0) self.motor_speed_slider.setValue(0) self.id_selection_box_refresh_button.setEnabled(False) self.disable_widgets() self.port_selection_box.currentTextChanged.connect( self.port_selection_box_changed) self.port_selection_box_refresh_button.clicked.connect( self.port_refresh_button_clicked) self.id_selection_box.currentTextChanged.connect( self.id_selection_box_changed) self.id_selection_box_refresh_button.clicked.connect( self.id_refresh_button_clicked) self.set_id_button.pressed.connect(self.id_updated) self.position_slider.sliderMoved.connect(self.position_slider_updated) self.position_offset_slider.sliderMoved.connect( self.position_offset_slider_updated) self.angle_lower_limit_textentry.textChanged.connect( self.angle_lower_limit_updated) self.angle_upper_limit_textentry.textChanged.connect( self.angle_upper_limit_updated) self.vin_lower_limit_textentry.textChanged.connect( self.vin_lower_limit_updated) self.vin_upper_limit_textentry.textChanged.connect( self.vin_upper_limit_updated) self.temp_limit_textentry.textChanged.connect(self.temp_limit_updated) self.servo_mode_radio_button.toggled.connect( self.servo_mode_radio_button_toggled) self.motor_mode_radio_button.toggled.connect( self.motor_mode_radio_button_toggled) self.motor_speed_slider.valueChanged.connect( self.motor_speed_slider_updated) self.torque_enabled_checkbox.stateChanged.connect( self.torque_enabled_checkbox_toggled) self.led_enabled_checkbox.stateChanged.connect( self.led_enabled_checkbox_toggled) self.led_over_temp_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.led_over_voltage_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.led_rotor_locked_checkbox.stateChanged.connect( self.led_error_triggers_checkbox_toggled) self.scan_for_ports() def disable_widgets(self): self.set_id_line_edit.setEnabled(False) self.position_slider.setEnabled(False) self.position_offset_slider.setEnabled(False) self.angle_lower_limit_textentry.setEnabled(False) self.angle_upper_limit_textentry.setEnabled(False) self.vin_lower_limit_textentry.setEnabled(False) self.vin_upper_limit_textentry.setEnabled(False) self.temp_limit_textentry.setEnabled(False) self.servo_mode_radio_button.setEnabled(False) self.motor_mode_radio_button.setEnabled(False) self.motor_speed_slider.setEnabled(False) self.torque_enabled_checkbox.setEnabled(False) self.led_enabled_checkbox.setEnabled(False) self.led_over_temp_checkbox.setEnabled(False) self.led_over_voltage_checkbox.setEnabled(False) self.led_rotor_locked_checkbox.setEnabled(False) def enable_widgets(self): self.set_id_line_edit.setEnabled(True) self.position_slider.setEnabled(True) self.position_offset_slider.setEnabled(True) self.angle_lower_limit_textentry.setEnabled(True) self.angle_upper_limit_textentry.setEnabled(True) self.vin_lower_limit_textentry.setEnabled(True) self.vin_upper_limit_textentry.setEnabled(True) self.temp_limit_textentry.setEnabled(True) self.servo_mode_radio_button.setEnabled(True) self.motor_mode_radio_button.setEnabled(True) self.motor_speed_slider.setEnabled(True) self.torque_enabled_checkbox.setEnabled(True) self.led_enabled_checkbox.setEnabled(True) self.led_over_temp_checkbox.setEnabled(True) self.led_over_voltage_checkbox.setEnabled(True) self.led_rotor_locked_checkbox.setEnabled(True) def clear_servo(self): self.active_servo = None @catch_disconnection def set_servo_id(self, id_): if not id_.isdigit(): return self.active_servo = LX16A(int(id_)) self.active_servo.enable_torque() self.position_slider.setValue( int(self.active_servo.get_physical_angle())) self.position_slider_readout.setText( f"{int(self.active_servo.get_physical_angle() * 25 / 6) * 6 / 25:0.2f}°" ) self.position_offset_slider.setValue( int(self.active_servo.get_angle_offset())) self.position_offset_slider_readout.setText( f"{int(self.active_servo.get_angle_offset() * 25 / 6) * 6 / 25:0.2f}°" ) self.angle_lower_limit_textentry.setText( str(int(self.active_servo.get_angle_limits()[0]))) self.angle_upper_limit_textentry.setText( str(int(self.active_servo.get_angle_limits()[1]))) self.vin_lower_limit_textentry.setText( str(self.active_servo.get_vin_limits()[0])) self.vin_upper_limit_textentry.setText( str(self.active_servo.get_vin_limits()[1])) self.temp_limit_textentry.setText( str(self.active_servo.get_temp_limit())) self.motor_speed_slider.setValue(self.active_servo.get_motor_speed( ) if self.active_servo.is_motor_mode() else 0) if self.active_servo.is_motor_mode(): self.motor_mode_radio_button.setChecked(True) else: self.servo_mode_radio_button.setChecked(True) self.motor_speed_slider.setEnabled(self.active_servo.is_motor_mode()) self.torque_enabled_checkbox.setChecked( self.active_servo.is_torque_enabled()) self.led_enabled_checkbox.setChecked( self.active_servo.is_led_power_on()) self.led_over_temp_checkbox.setChecked( self.active_servo.get_led_error_triggers()[0]) self.led_over_voltage_checkbox.setChecked( self.active_servo.get_led_error_triggers()[1]) self.led_rotor_locked_checkbox.setChecked( self.active_servo.get_led_error_triggers()[2]) @catch_disconnection def scan_for_servos(self, port): self.setCursor(Qt.CursorShape.WaitCursor) LX16A.initialize(port) self.id_selection_box.clear() for i in range(0, 254): try: servo = LX16A(i) self.id_selection_box.addItem(str(i)) except: pass self.setCursor(Qt.CursorShape.ArrowCursor) @catch_disconnection def scan_for_ports(self): ports = serial.tools.list_ports.comports() for port in ports: self.port_selection_box.addItem(port.device) @catch_disconnection def update_readouts(self): if self.active_servo is None: return try: self.physical_position_readout.setText( f"{self.active_servo.get_physical_angle():0.2f}°") self.temperature_readout.setText( f"{self.active_servo.get_temp()} °C") self.voltage_readout.setText( f"{self.active_servo.get_vin() / 1000} V") except (ServoTimeoutError, ServoChecksumError): pass @catch_disconnection def id_updated(self): new_id = self.set_id_line_edit.text() try: servo = LX16A(int(new_id)) except ServoTimeoutError: # Meaning this ID is not taken self.active_servo.set_id(int(new_id)) self.id_selection_box.item( self.id_selection_box.currentRow()).setText(new_id) return QMessageBox.warning(None, "Error", "ID already taken") @catch_disconnection def position_slider_updated(self, pos): if float(self.voltage_readout.text()[:-2]) < 5: QMessageBox.warning( None, "Error", "The voltage going through the servo is too low. Is your battery powered on?", ) return self.active_servo.move(pos) self.position_slider_readout.setText( f"{int(pos * 25 / 6) * 6 / 25:0.2f}°") @catch_disconnection def position_offset_slider_updated(self, pos): self.active_servo.set_angle_offset(pos) self.position_offset_slider_readout.setText( f"{int(pos * 25 / 6) * 6 / 25:0.2f}°") @catch_disconnection def angle_lower_limit_updated(self, text): if (QIntValidator(0, 240, self).validate(text, 0) != QIntValidator.State.Acceptable): return if int(text) > int(self.angle_upper_limit_textentry.text()): return self.active_servo.set_angle_limits( int(text), int(self.angle_upper_limit_textentry.text())) @catch_disconnection def angle_upper_limit_updated(self, text): if (QIntValidator(0, 240, self).validate(text, 0) != QIntValidator.State.Acceptable): return if int(text) < int(self.angle_lower_limit_textentry.text()): return self.active_servo.set_angle_limits( int(self.angle_lower_limit_textentry.text()), int(text)) @catch_disconnection def vin_lower_limit_updated(self, text): if (QIntValidator(4500, 12000, self).validate(text, 0) != QIntValidator.State.Acceptable): return if int(text) > int(self.vin_upper_limit_textentry.text()): return self.active_servo.set_vin_limits( int(text), int(self.vin_upper_limit_textentry.text())) @catch_disconnection def vin_upper_limit_updated(self, text): if (QIntValidator(4500, 12000, self).validate(text, 0) != QIntValidator.State.Acceptable): return if int(text) < int(self.vin_lower_limit_textentry.text()): return self.active_servo.set_vin_limits( int(self.vin_lower_limit_textentry.text()), int(text)) @catch_disconnection def temp_limit_updated(self, text): if (QIntValidator(50, 100, self).validate(text, 0) != QIntValidator.State.Acceptable): return self.active_servo.set_temp_limit(int(text)) @catch_disconnection def servo_mode_radio_button_toggled(self, checked): if checked: self.active_servo.servo_mode() self.motor_speed_slider.setEnabled(False) self.position_slider.setEnabled(True) self.position_offset_slider.setEnabled(True) else: self.active_servo.motor_mode(int(self.motor_speed_slider.value())) self.motor_speed_slider.setEnabled(True) self.position_slider.setEnabled(False) self.position_offset_slider.setEnabled(False) @catch_disconnection def motor_mode_radio_button_toggled(self, checked): if checked: self.active_servo.motor_mode(int(self.motor_speed_slider.value())) self.motor_speed_slider.setEnabled(True) self.position_slider.setEnabled(False) self.position_offset_slider.setEnabled(False) else: self.active_servo.servo_mode() self.motor_speed_slider.setEnabled(False) self.position_slider.setEnabled(True) self.position_offset_slider.setEnabled(True) @catch_disconnection def motor_speed_slider_updated(self, pos): self.active_servo.motor_mode(pos) @catch_disconnection def torque_enabled_checkbox_toggled(self, checked): if checked: self.active_servo.enable_torque() else: self.active_servo.disable_torque() self.position_slider.setEnabled(checked) self.position_offset_slider.setEnabled(checked) self.servo_mode_radio_button.setEnabled(checked) self.motor_mode_radio_button.setEnabled(checked) self.motor_speed_slider.setEnabled(checked) @catch_disconnection def led_enabled_checkbox_toggled(self, checked): if checked: self.active_servo.led_power_on() else: self.active_servo.led_power_off() @catch_disconnection def led_error_triggers_checkbox_toggled(self): self.active_servo.set_led_error_triggers( self.led_over_voltage_checkbox.isChecked(), self.led_over_temp_checkbox.isChecked(), self.led_rotor_locked_checkbox.isChecked(), ) @catch_disconnection def port_refresh_button_clicked(self, value): self.id_selection_box_refresh_button.setEnabled(False) self.disable_widgets() self.port_selection_box.clear() self.id_selection_box.clear() self.scan_for_ports() @catch_disconnection def id_refresh_button_clicked(self, value): self.disable_widgets() self.id_selection_box.clear() self.scan_for_servos(self.port_selection_box.currentText()) @catch_disconnection def port_selection_box_changed(self, text): if text == "": return self.id_selection_box_refresh_button.setEnabled(True) self.disable_widgets() self.id_selection_box.clear() self.clear_servo() self.scan_for_servos(text) @catch_disconnection def id_selection_box_changed(self, text): if text == "": return self.enable_widgets() self.set_servo_id(text)
def __init__(self, parent = None): super(MainWindow, self).__init__() D = self.screen().availableGeometry() self.move(0,0)#center.x() + .25*D.width() , center.y() - .5*D.height() ) self.resize( int(.95*D.width()), int(6*D.height()) ) #qr = self.frameGeometry() #cp = self.screen().availableGeometry().center() #qr.moveCenter(cp) #self.move(qr.topLeft()) self.setWindowState(self.windowState() & ~QtCore.Qt.WindowState.WindowMinimized | QtCore.Qt.WindowState.WindowActive) self.activateWindow() self.subWin = Window() self.iw = imwin() self.Manual = Manual() self.setCentralWidget(self.iw) #Stacked dock widgets docked1 = QDockWidget("", self) docked2 = QDockWidget("", self) self.addDockWidget(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea, docked1) self.addDockWidget(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea, docked2) docked1.setWidget(self.subWin) docked2.setWidget(self.Manual) docked1.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetFloatable) self.setCorner(QtCore.Qt.Corner.TopLeftCorner, QtCore.Qt.DockWidgetArea.LeftDockWidgetArea); self.setCorner(QtCore.Qt.Corner.TopRightCorner, QtCore.Qt.DockWidgetArea.RightDockWidgetArea) self.setCorner(QtCore.Qt.Corner.BottomLeftCorner, QtCore.Qt.DockWidgetArea.LeftDockWidgetArea); self.setCorner(QtCore.Qt.Corner.BottomRightCorner, QtCore.Qt.DockWidgetArea.RightDockWidgetArea) self.resizeDocks( (docked1,docked2), (400,400), QtCore.Qt.Orientation.Horizontal ) self.exportButton = QPushButton("Export Measurements", self) self.exportButton.clicked.connect(self.export_measurements) self.exportButton.setEnabled(False) self.importImage = QPushButton("New Image", self) self.importImage.clicked.connect(self.file_open) self.lengthButton = QPushButton("Measure Length", self) self.lengthButton.clicked.connect(self.measure_length) self.lengthButton.setEnabled(False) self.lengthButton.setCheckable(True) self.lengthNames = [] self.widthsButton = QPushButton("Measure Widths", self) self.widthsButton.clicked.connect(self.iw.measure_widths) self.widthsButton.setEnabled(False) self.widthsButton.setCheckable(True) self.areaButton = QPushButton("Measure Area", self) self.areaButton.clicked.connect(self.measure_area) self.areaButton.setEnabled(False) self.areaButton.setCheckable(True) self.areaNames = [] self.angleButton = QPushButton("Measure Angle", self) self.angleButton.clicked.connect(self.measure_angle) self.angleButton.setEnabled(False) self.angleButton.setCheckable(True) self.angleNames = [] shortcut_polyClose = QShortcut(QtGui.QKeySequence(QtCore.Qt.Key.Key_Tab), self) shortcut_polyClose.activated.connect(self.iw.polyClose) self.undoButton = QPushButton("Undo", self) self.undoButton.clicked.connect(self.undo) self.undoButton.setEnabled(False) shortcut_undo = QShortcut(QtGui.QKeySequence('Ctrl+Z'), self) shortcut_undo.activated.connect(self.undo) self.bezier = QRadioButton("Bezier fit", self) self.bezier.setEnabled(True) self.bezier.setChecked(True) #self.bezier.toggled.connect(self.onClicked) self.piecewise = QRadioButton("Piecewise", self) self.statusbar = self.statusBar() self.statusbar.showMessage('Select new image to begin') self.tb = QToolBar('Toolbar') #self.addToolBar(QtCore.Qt.RightToolBarArea,self.tb) spacer = QWidget(self) spacer.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.tb.addWidget(spacer) self.addToolBar(self.tb) self.tb.addWidget(self.importImage) self.tb.addWidget(self.exportButton) self.tb.addWidget(self.lengthButton) self.tb.addWidget(self.widthsButton) self.tb.addWidget(self.areaButton) self.tb.addWidget(self.angleButton) self.tb.addWidget(self.undoButton) self.tb.addWidget(self.bezier) self.tb.addWidget(self.piecewise)
class MainWindow(QMainWindow): def __init__(self, parent = None): super(MainWindow, self).__init__() D = self.screen().availableGeometry() self.move(0,0)#center.x() + .25*D.width() , center.y() - .5*D.height() ) self.resize( int(.95*D.width()), int(6*D.height()) ) #qr = self.frameGeometry() #cp = self.screen().availableGeometry().center() #qr.moveCenter(cp) #self.move(qr.topLeft()) self.setWindowState(self.windowState() & ~QtCore.Qt.WindowState.WindowMinimized | QtCore.Qt.WindowState.WindowActive) self.activateWindow() self.subWin = Window() self.iw = imwin() self.Manual = Manual() self.setCentralWidget(self.iw) #Stacked dock widgets docked1 = QDockWidget("", self) docked2 = QDockWidget("", self) self.addDockWidget(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea, docked1) self.addDockWidget(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea, docked2) docked1.setWidget(self.subWin) docked2.setWidget(self.Manual) docked1.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetFloatable) self.setCorner(QtCore.Qt.Corner.TopLeftCorner, QtCore.Qt.DockWidgetArea.LeftDockWidgetArea); self.setCorner(QtCore.Qt.Corner.TopRightCorner, QtCore.Qt.DockWidgetArea.RightDockWidgetArea) self.setCorner(QtCore.Qt.Corner.BottomLeftCorner, QtCore.Qt.DockWidgetArea.LeftDockWidgetArea); self.setCorner(QtCore.Qt.Corner.BottomRightCorner, QtCore.Qt.DockWidgetArea.RightDockWidgetArea) self.resizeDocks( (docked1,docked2), (400,400), QtCore.Qt.Orientation.Horizontal ) self.exportButton = QPushButton("Export Measurements", self) self.exportButton.clicked.connect(self.export_measurements) self.exportButton.setEnabled(False) self.importImage = QPushButton("New Image", self) self.importImage.clicked.connect(self.file_open) self.lengthButton = QPushButton("Measure Length", self) self.lengthButton.clicked.connect(self.measure_length) self.lengthButton.setEnabled(False) self.lengthButton.setCheckable(True) self.lengthNames = [] self.widthsButton = QPushButton("Measure Widths", self) self.widthsButton.clicked.connect(self.iw.measure_widths) self.widthsButton.setEnabled(False) self.widthsButton.setCheckable(True) self.areaButton = QPushButton("Measure Area", self) self.areaButton.clicked.connect(self.measure_area) self.areaButton.setEnabled(False) self.areaButton.setCheckable(True) self.areaNames = [] self.angleButton = QPushButton("Measure Angle", self) self.angleButton.clicked.connect(self.measure_angle) self.angleButton.setEnabled(False) self.angleButton.setCheckable(True) self.angleNames = [] shortcut_polyClose = QShortcut(QtGui.QKeySequence(QtCore.Qt.Key.Key_Tab), self) shortcut_polyClose.activated.connect(self.iw.polyClose) self.undoButton = QPushButton("Undo", self) self.undoButton.clicked.connect(self.undo) self.undoButton.setEnabled(False) shortcut_undo = QShortcut(QtGui.QKeySequence('Ctrl+Z'), self) shortcut_undo.activated.connect(self.undo) self.bezier = QRadioButton("Bezier fit", self) self.bezier.setEnabled(True) self.bezier.setChecked(True) #self.bezier.toggled.connect(self.onClicked) self.piecewise = QRadioButton("Piecewise", self) self.statusbar = self.statusBar() self.statusbar.showMessage('Select new image to begin') self.tb = QToolBar('Toolbar') #self.addToolBar(QtCore.Qt.RightToolBarArea,self.tb) spacer = QWidget(self) spacer.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.tb.addWidget(spacer) self.addToolBar(self.tb) self.tb.addWidget(self.importImage) self.tb.addWidget(self.exportButton) self.tb.addWidget(self.lengthButton) self.tb.addWidget(self.widthsButton) self.tb.addWidget(self.areaButton) self.tb.addWidget(self.angleButton) self.tb.addWidget(self.undoButton) self.tb.addWidget(self.bezier) self.tb.addWidget(self.piecewise) #self.tb.setOrientation(QtCore.Qt.Vertical) def file_open(self): self.iw.scene.clear() self.image_name = QFileDialog.getOpenFileName(self, 'Open File') self.iw.pixmap = QtGui.QPixmap(self.image_name[0]) self.iw.pixmap_fit = self.iw.pixmap.scaled( self.iw.pixmap.width(), self.iw.pixmap.height(), QtCore.Qt.AspectRatioMode.KeepAspectRatio, transformMode=QtCore.Qt.TransformationMode.SmoothTransformation) self.iw.scene.addPixmap(self.iw.pixmap_fit) #add image self.iw.setScene(self.iw.scene) #Adjust window size automatically? self.iw.fitInView(self.iw.scene.sceneRect(), QtCore.Qt.AspectRatioMode.KeepAspectRatio) self.iw.scene.update() self.statusbar.showMessage('Select a measurement to make from the toolbar') self.lengthButton.setEnabled(True) self.areaButton.setEnabled(True) self.angleButton.setEnabled(True) self.exportButton.setEnabled(True) self.undoButton.setEnabled(True) self.bezier.setEnabled(True) self.bezier.setChecked(True) self.widthsButton.setEnabled(False) self.angleNames = [] self.areaNames = [] self.lengthNames = [] #self.iw.measurements = [[]] self.iw.widths = [] self.iw.lengths = [[]] self.iw.L = posData( np.empty(shape=(0, 0)), np.empty(shape=(0, 0))) #lengths self.iw.A = posData( np.empty(shape=(0, 0)), np.empty(shape=(0, 0))) #area self.iw.W = posData( np.empty(shape=(0, 0)), np.empty(shape=(0, 0))) #widths self.iw.T = angleData(np.empty(shape=(0, 0))) #angles self.iw.angleValues = np.empty((0,0)) self.iw.areaValues = np.empty((0,0)) self.iw._lastpos = None self.iw._thispos = None self.iw.measuring_length = False self.iw.measuring_area = False self.iw.measuring_widths = False self.iw.measuring_angle = False self.iw._zoom = 0 self.iw.factor = 1.0 self.iw.d = {} #dictionary for line items self.iw.k = 0 #initialize counter so lines turn yellow self.iw.m = None self.iw.scene.realline = None self.iw.scene.testline = None self.iw.scene.ellipseItem = None self.iw.scene.area_ellipseItem = None self.iw.scene.polyItem = None self.iw.image_name = None def measure_length(self): self.lel = QLineEdit(self) self.lel.move(130, 22) text, ok = QInputDialog.getText(self, 'Input Dialog', 'Length name') if ok: self.lel.setText(str(text)) self.lengthNames.append(self.lel.text()) QApplication.setOverrideCursor(QtCore.Qt.CursorShape.CrossCursor) #change cursor self.widthsButton.setChecked(False) self.widthsButton.setEnabled(False) self.iw.line_count = 0 self.iw.measuring_length = True self.iw.L = posData( np.empty(shape=(0, 0)), np.empty(shape=(0, 0))) #preallocate self.iw._lastpos = None self.iw._thispos = None self.statusbar.showMessage('Click initial point for length measurement') else: self.lengthButton.setChecked(False) def measure_angle(self): self.lea = QLineEdit(self) self.lea.move(130, 22) text, ok = QInputDialog.getText(self, 'Input Dialog', 'Angle name') if ok: self.lea.setText(str(text)) self.angleNames.append(self.lea.text()) QApplication.setOverrideCursor(QtCore.Qt.CrossCursor) #change cursor self.bezier.setEnabled(False) self.iw.measuring_angle = True self.iw._lastpos = None self.iw._thispos = None self.statusbar.showMessage('Click initial point for angle measurement') else: self.angleButton.setChecked(False) def measure_area(self): self.lea = QLineEdit(self) self.lea.move(130, 22) text, ok = QInputDialog.getText(self, 'Input Dialog', 'Area name') if ok: self.lea.setText(str(text)) self.areaNames.append(self.lea.text()) QApplication.setOverrideCursor(QtCore.Qt.CrossCursor) #change cursor self.bezier.setEnabled(False) self.iw.line_count = 0 self.iw.measuring_area = True self.iw._lastpos = None self.iw._thispos = None self.iw.A = posData( np.empty(shape=(0, 0)), np.empty(shape=(0, 0))) #preallocate self.statusbar.showMessage('Click initial point for area measurement') else: self.areaButton.setChecked(False) def undo(self): if self.iw.measuring_length: self.iw._thispos = self.iw._lastpos self.iw.L.downdate() #remove data self.iw.line_count += -1 self.iw.scene.removeItem(self.iw.scene.realline) #remove graphic self.iw.scene.realline = False if self.iw.measuring_area: self.iw._thispos = self.iw._lastpos self.iw.A.downdate() #remove data self.iw.line_count += -1 self.iw.scene.removeItem(self.iw.scene.realline) #remove graphic self.iw.scene.realline = False if self.iw.measuring_widths: self.iw.W.downdate() #remove data self.iw.scene.removeItem(self.iw.scene.ellipseItem) #remove graphic self.iw.scene.ellipseItem = False self.iw.d[str(self.iw.k)].setPen( QtGui.QPen(QtGui.QColor('black'))) #un-highlight next spine self.iw.k += -1 #reduce count if self.iw.measuring_angle: self.iw.T.downdate() #remove data self.iw._thispos = self.iw_lastpos self.iw.scene.removeItem(self.iw.scene.realline) #remove graphic self.iw.scene.realline = False def export_measurements(self): fac = max(self.iw.pixmap.width(), self.iw.pixmap.height()) / max( self.iw.pixmap_fit.width(), self.iw.pixmap_fit.height()) #scale pixel -> m by scaled image name = QFileDialog.getSaveFileName( self, 'Save File', self.image_name[0].split('.', 1)[0])[0] self.pixeldim = float(self.subWin.pixeldim.text()) self.altitude = float(self.subWin.altitude.text()) self.focal = float(self.subWin.focal.text()) #okay in mm https://www.imaging-resource.com/PRODS/sony-a5100/sony-a5100DAT.HTM if name: #Convert pixels to meters #measurements = [ f * fac * self.pixeldim * self.altitude / self.focal for f in self.iw.measurements] #lengths = [ f * fac * self.pixeldim * self.altitude / self.focal for f in self.iw.lengths] #print(self.iw.widths) areas = self.iw.areaValues * ( fac * self.pixeldim * self.altitude / self.focal)**2 values_optical = np.array([ self.subWin.id.text(), self.image_name[0], self.focal, self.altitude, self.pixeldim ]) names_optical = [ 'Image ID', 'Image Path', 'Focal Length', 'Altitude', 'Pixel Dimension' ] names_widths = ['Object'] + ['Length (m)'] + ['Widths (%)'] # + self.iw.widthNames[0] #names_widths.append([self.iw.widthNames[0]]) #Write .csv file print(f"Writing {name} to file") with open(name + '.csv', 'w') as csvfile: writer = csv.writer(csvfile) for (f, g) in zip(names_optical, values_optical): writer.writerow([f, g]) writer.writerow(['Notes', self.subWin.notes.toPlainText()]) writer.writerow(['']) writer.writerow(names_widths) for k,m in enumerate(self.lengthNames): #format and convert pixel length measurement l = "{0:.2f}".format( self.iw.lengths[k] * fac * self.pixeldim * self.altitude / self.focal ) if any(self.iw.widths[k]): #check if width measurement exists for length n = self.iw.widthNames[k] writer.writerow( [''] + [''] + n ) #format and convert pixel width measurement vals = [ "{0:.2f}".format(g * fac * self.pixeldim * self.altitude / self.focal) for g in self.iw.widths[k]] line = [m] + [l] + list(vals) else: #vals = l #f.copy() line = [m] + [l] writer.writerow(line) writer.writerow(['']) writer.writerow(['Object'] + ['Angle']) for k, f in enumerate(self.angleNames): #write angles line = [[f] + ["{0:.3f}".format(self.iw.angleValues[k])]] #need to convert NaNs to empty writer.writerows(line) writer.writerow(['']) writer.writerow(['Object'] + ['Area (m\u00B2)']) for k, f in enumerate(self.areaNames): #write areas line = [[f] + ["{0:.3f}".format(areas[k])]] #need to convert NaNs to empty writer.writerows(line) #Export image self.iw.fitInView(self.iw.scene.sceneRect(), QtCore.Qt.AspectRatioMode.KeepAspectRatio) pix = QtGui.QPixmap(self.iw.viewport().size()) self.iw.viewport().render(pix) pix.save(name + '-measurements.png')
def questionBankPageUI(self): layout = QFormLayout() subLayout = QHBoxLayout() self.questionBankPage.questionList = QListWidget() self.questionBankPage.questionList.currentRowChanged.connect( self.displayQuestionOnQuestionBankPage) self.questionBankPage.questionTextDisplay = QLabel() self.questionBankPage.questionTextDisplay.setFixedSize(500, 100) self.questionBankPage.questionAnswersList = QListWidget() self.questionBankPage.definedCorrectAnswerDisplay = QLabel() self.questionBankPage.definedCorrectAnswerDisplay.setFixedSize(50, 10) self.questionBankPage.questionCodeParserDisplay = QLabel() self.questionBankPage.questionCodeParserDisplay.setFixedSize(100, 50) subLayout.addWidget(self.questionBankPage.questionList) subLayout.addWidget(self.questionBankPage.questionTextDisplay) subLayout.addWidget(self.questionBankPage.questionAnswersList) subLayout.addWidget(self.questionBankPage.definedCorrectAnswerDisplay) subLayout.addWidget(self.questionBankPage.questionCodeParserDisplay) layout.addRow(subLayout) self.questionBankPage.newQuestionTitle = QLineEdit() self.questionBankPage.newQuestionContent = QPlainTextEdit() layout.addRow(self.questionBankPage.newQuestionTitle, self.questionBankPage.newQuestionContent) self.questionBankPage.newQuestionAnswerInput = QLineEdit() self.questionBankPage.newQuestionAnswerList = QListWidget() layout.addRow(self.questionBankPage.newQuestionAnswerInput, self.questionBankPage.newQuestionAnswerList) colorLayout = QFormLayout() colorButtonGroup = QButtonGroup(self.questionBankPage) self.questionBankPage.yellowRadio = QRadioButton() self.questionBankPage.blueRadio = QRadioButton() self.questionBankPage.redRadio = QRadioButton() self.questionBankPage.yellowRadio.toggled.connect( self.colorRadioToggle) self.questionBankPage.blueRadio.toggled.connect(self.colorRadioToggle) self.questionBankPage.redRadio.toggled.connect(self.colorRadioToggle) colorButtonGroup.addButton(self.questionBankPage.yellowRadio) colorButtonGroup.addButton(self.questionBankPage.blueRadio) colorButtonGroup.addButton(self.questionBankPage.redRadio) colorLayout.addRow("Yellow", self.questionBankPage.yellowRadio) colorLayout.addRow("Blue", self.questionBankPage.blueRadio) colorLayout.addRow("Red", self.questionBankPage.redRadio) combLayout = QHBoxLayout() combLayout.addLayout(colorLayout) layout.addRow(combLayout) self.questionBankPage.definedNewCorrectAnswerDisplay = QLabel() layout.addRow(self.questionBankPage.definedNewCorrectAnswerDisplay) self.questionBankPage.defineCorrectAnswerButton = QPushButton( "&Define Correct Answer") self.questionBankPage.defineCorrectAnswerButton.clicked.connect( self.defineCorrectAnswer) self.questionBankPage.submitNewAnswerButton = QPushButton( "Submit &Answer") self.questionBankPage.submitNewAnswerButton.clicked.connect( self.submitNewAnswer) layout.addRow(self.questionBankPage.defineCorrectAnswerButton, self.questionBankPage.submitNewAnswerButton) self.questionBankPage.submitNewQuestionButton = QPushButton( "Submit New &Question") self.questionBankPage.submitNewQuestionButton.clicked.connect( self.submitNewQuestion) layout.addRow(self.questionBankPage.submitNewQuestionButton) self.questionBankPage.backButton = QPushButton("&Back") self.questionBankPage.backButton.clicked.connect( self.goTo_FacilStartPage) self.questionBankPage.refreshButton = QPushButton("&Refresh") self.questionBankPage.refreshButton.clicked.connect( self.goTo_QuestionBankPage) layout.addRow(self.questionBankPage.backButton, self.questionBankPage.refreshButton) self.questionBankPage.setLayout(layout)