The following contains a simple PyQT interfaced that publishes the values in the QWidgets via Ros topics
The code was tested on
- Python 3.10 with a anaconda environment.
- Windows WSL
PyQt versions
- PyQt5 5.15.9
- PyQt5-Qt5 5.15.2
The following contains a simple PyQT interfaced that publishes the values in the QWidgets via Ros topics
The code was tested on
PyQt versions
| from __future__ import annotations | |
| import time | |
| from typing import List, Tuple | |
| from PyQt5.QtCore import Qt | |
| from PyQt5.QtCore import QSize | |
| from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget, QPushButton | |
| from PyQt5.QtWidgets import QComboBox, QSlider, QGridLayout, QTextEdit | |
| import sys | |
| from dataclasses import dataclass | |
| import rospy | |
| from sensor_msgs.msg import Joy | |
| from diagnostic_msgs.msg import KeyValue | |
| @dataclass | |
| class CustomSlider: | |
| controller: SlidersBlock | |
| label: str | |
| range: Tuple[int, int] | |
| init_val: float | |
| max_val: float | |
| def __post_init__(self): | |
| self.slider_label = QLabel(self.label+f"{self.init_val:05.2f}") | |
| self.slider = QSlider(Qt.Horizontal) | |
| self.slider.setRange(self.range[0], self.range[1]) | |
| self.slider.setSingleStep(1) | |
| self.slider.setValue(int(self.init_val/self.max_val*self.range[1])) | |
| self.slider.valueChanged.connect(self.slider_cb) | |
| def slider_cb(self, i): | |
| val = self.max_val*(i/self.range[1]) | |
| self.slider_label.setText(self.label+f"{val:05.2f}") | |
| self.controller.publish_dist_params() | |
| def disable_slider(self): | |
| self.slider.setEnabled(False) | |
| def enable_slider(self): | |
| self.slider.setEnabled(True) | |
| def get_current_value(self): | |
| i = self.slider.value() | |
| cur_val = self.max_val*(i/self.range[1]) | |
| return cur_val | |
| class SlidersBlock: | |
| def __init__(self): | |
| self.grid_layout = QGridLayout() | |
| self.sliders_list: List[CustomSlider] = [] | |
| self.sliders_list.append(CustomSlider(self, "a=", (0, 100), 7.0, 15.0)) | |
| self.sliders_list.append(CustomSlider(self, "b=", (0, 100), 10.0, 20.0)) | |
| self.sliders_list.append(CustomSlider(self, "c=", (0, 100),3, 10.0)) | |
| for idx, custom_slider in enumerate(self.sliders_list): | |
| self.grid_layout.addWidget(custom_slider.slider_label, idx, 0) | |
| self.grid_layout.addWidget(custom_slider.slider, idx, 1) | |
| def add_publisher(self, publisher: ParamPublisher): | |
| self.publisher = publisher | |
| def enable_all_sliders(self): | |
| for slider in self.sliders_list: | |
| slider.enable_slider() | |
| def disable_all_sliders(self): | |
| for slider in self.sliders_list: | |
| slider.disable_slider() | |
| def publish_dist_params(self): | |
| a = self.sliders_list[0].get_current_value() | |
| b = self.sliders_list[1].get_current_value() | |
| c = self.sliders_list[2].get_current_value() | |
| self.publisher.pub_dist_params(a, b, c) | |
| class MainWindow(QMainWindow): | |
| def __init__(self): | |
| super().__init__() | |
| self.setWindowTitle("Parameter publisher") | |
| # QWigets config | |
| self.button = QPushButton("Publish parameters") | |
| self.button.setCheckable(True) | |
| self.button.clicked.connect(self.pub_button_cb) | |
| self.combo_label = QLabel("Operation mode") | |
| self.fmt_label(self.combo_label) | |
| self.combo_label.setFixedHeight(25) | |
| self.combo_box = QComboBox() | |
| self.combo_box.addItems(["mode 1", "mode 2", "mode 3", "mode 4"]) | |
| self.combo_box.setEnabled(False) | |
| # self.combo_box.currentIndexChanged.connect( self.index_changed ) | |
| self.combo_box.currentTextChanged.connect( self.text_changed ) | |
| self.label = QLabel("Operation mode") | |
| self.input = QLineEdit() | |
| self.input.textChanged.connect(self.label.setText) | |
| # Create a QGridLayout | |
| self.dist_label = QLabel("Distortion params") | |
| self.fmt_label(self.dist_label) | |
| self.dist_label.setFixedHeight(25) | |
| self.slider_block = SlidersBlock() | |
| self.slider_block.disable_all_sliders() | |
| self.text_edit_label = QLabel("Console") | |
| self.fmt_label(self.text_edit_label) | |
| self.text_edit = QTextEdit() | |
| self.text_edit.setReadOnly(True) | |
| # Layout config | |
| layout = QVBoxLayout() | |
| layout.addWidget(self.button) | |
| layout.addWidget(self.combo_label) | |
| layout.addWidget(self.combo_box) | |
| layout.addWidget(self.dist_label) | |
| layout.addLayout(self.slider_block.grid_layout) | |
| layout.addWidget(self.text_edit_label) | |
| layout.addWidget(self.text_edit) | |
| container = QWidget() | |
| container.setLayout(layout) | |
| # Window config. | |
| self.setCentralWidget(container) | |
| self.setFixedSize(QSize(400, 300)) | |
| def fmt_label(self, widget): | |
| font = widget.font() | |
| font.setBold(True) | |
| widget.setFont(font) | |
| def pub_button_cb(self): | |
| # Init param publishers | |
| self.param_pub = ParamPublisher() | |
| time.sleep(0.2) | |
| self.slider_block.add_publisher(self.param_pub) | |
| self.button.setText("publishers activated") | |
| self.button.setEnabled(False) | |
| self.button.setStyleSheet("QPushButton:checked { background-color: green; }") | |
| self.combo_box.setEnabled(True) | |
| self.slider_block.enable_all_sliders() | |
| self.text_edit.append("Publishers activated") | |
| self.text_edit.append("Publishing to topic: /volumetric/camera_params") | |
| # def index_changed(self, i): # i is an int | |
| # print(i) | |
| def text_changed(self, selected_mode): # s is a str | |
| self.param_pub.pub_op_mode(selected_mode) | |
| print(selected_mode) | |
| class ParamPublisher: | |
| def __init__(self) -> None: | |
| base_topic = "/volumetric/camera_params/" | |
| #Operation mode publisher | |
| self.mode_pub = rospy.Publisher(base_topic+'op_mode', KeyValue, queue_size=10) | |
| self.dist_pub = rospy.Publisher(base_topic+'dist_params', Joy, queue_size=10) | |
| rospy.init_node('talker', anonymous=True) | |
| rate = rospy.Rate(10) # 10hz | |
| def pub_op_mode(self, mode): | |
| self.mode_pub.publish(KeyValue(key="op_mode", value=mode)) | |
| def pub_dist_params(self, a, b, c): | |
| self.dist_pub.publish(Joy(header=None, axes=[a, b, c], buttons=[])) | |
| def main(): | |
| app = QApplication(sys.argv) | |
| window = MainWindow() | |
| window.show() | |
| app.exec() | |
| if __name__ == "__main__": | |
| main() |